[ToyProject] Servlet, JSP, h2 를 이용하여 게시판 프로그램 만들기

Yeppi's 개발 일기·2022년 5월 26일
1

프로젝트 모음

목록 보기
2/2

1. 게시판 프로그램

Servlet, JSP, JDBCh2 를 이용하여 간단한 게시판 프로그램을 구현해보자
해당 프로젝트는 클론 코딩으로 진행되었다



2. 프로젝트 설명

웹 페이지의 기본적인 기능이 대부분 모여있는 것이 게시판이라고 할 수 있다. 기본적인 웹 브라우저와 서버의 동작을 해당 프로젝트를 통해 이해하고, 가장 많이 사용하는 웹 페이지의 기본 기능을 구현하면서 각 코드별 어떻게 상호작용하는 지 이해하는 것이 해당 프로젝트의 목표이다.

로그인 여부

사용자가 로그인을 하지 않았다면 게시판을 열람만 할 수 있도록 하고
사용자가 회원가입 및 로그인을 했다면 게시판에 게시물을 올리고, 삭제하고, 수정할 수 있게 한다.
또한 사용자가 회원가입을 할 때 일반 회원과 관리자 회원을 구분하도록 하여, 관리자만 게시물을 삭제할 수 있도록 설정한다. 또한 사용자가 원할 때 언제든지 로그아웃을 할 수 있도록 로그아웃 버튼도 생성한다.


웹 페이지의 상단과 하단은 앞서 배운 headerfooter 로 작성한다.

로그인하기 전이라면 언제든지 메인 화면으로 돌아올 수 있는 home 버튼, 회원 가입 버튼, 로그인 버튼으로 구성한다. 만약 로그인을 했다면 언제든지 메인 화면으로 돌아올 수 있는 home 버튼, 글 목록 및 글 등록 버튼, 로그아웃 버튼으로 구성한다.

웹사이트의 기본 정보를 나열한다. 대게 흔히 쓰는 사이트들을 들어가서 제일 밑으로 내리면 기업명, 기업 대표 번호, 업체명 주소 등 여러 정보들이 나오는 데 이런 정보를 뿌려주면 된다. 간단한 프로젝트 이므로 가상의 문의 전화번호 및 주소를 적어둔다.


게시판 & 게시물

게시판 목록 형태를 표로 구성한다. 행의 가장 상단인 각 속성들의 제목은 번호, 제목, 작성자, 등록일, 조회수로 나타낸다. 만약 게시판에 게시물을 아무도 등록하지 않았다면 해당 속성들만 나열되어있을 것이다.
게시물 등록 순서대로 번호가 Count 되어 게시물의 개수를 파악할 수 있다. 그리고 제목과 작성자는 한글을 입력해도 깨지지 않도록 encoding 처리를 해준다. 등록일은 시스템 서버의 년/월/일 이 자동으로 기입되도록 하며, 조회수는 기본적으로 null 이 아닌 0 을 세팅해준다.

게시물 검색

게시물의 제목 및 내용 중에서 원하는 키워드가 있을 때 사용자가 검색하여 편리하게 찾을 수 있도록 한다. 검색은 제목이나 내용 중 하나를 선택한 후에 해당 조건에 맞는 내용을 검색할 수 있다. 예를 들어, 제목으로 선택한 후 ep 라고 검색했다면 제목이 yeppi, yep0101, eppizzzep 가 들어가는 모든 단어를 검색할 것이다.

게시물 글내용

게시판 화면에서 원하는 게시물을 클릭하면 해당 게시물의 제목, 작성자, 내용, 등록일, 조회수의 내용을 상세하게 보여준다. 언제든지 글 수정을 할 수 있도록 글 수정 버튼을 하단에 배치한다. 그러나 글 삭제 버튼은 관리자 권한으로 로그인하였을 때만 생성되도록 한다.



3. 구현하기

해당 토이프로젝트 소스코드가 push 되어 있는 yeppi의 github 입니다.
해당 프로젝트는 Servlet, JSP 를 중점으로 진행하였습니다.
JDBC 연결과 회원 가입 및 로그인의 JAVA 코드는 [ToyProject] JDBC-Java-h2 회원 관리 프로그램을 참고해주세요.

🍑디렉토리 구조🍑

1) DB

CREATE TABLE USERS(
	ID VARCHAR2(8) PRIMARY KEY,
	PASSWORD VARCHAR2(8),
	NAME VARCHAR2(20),
	ROLE VARCHAR2(5)
);

INSERT INTO USERS VALUES('test', 'test', 'yeppi', 'Admin');

CREATE TABLE BOARD(
	SEQ NUMBER(5) PRIMARY KEY,
	TITLE VARCHAR2(200),
	WRITER VARCHAR2(20),
	CONTENT VARCHAR2(2000),
	REGDATE DATE DEFAULT CURRENT_DATE,
	CNT NUMBER(5) DEFAULT 0
);


  • footer.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<br>
<hr>
<br>
<center>
	문의 전화 : 031-1234-1234<br> 주소 : 경기도 짱구대로 1234
</center>
</body>
</html>
  • header.jsp
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>게시판 프로그램</title>
</head>
<body>
	<hr>
	<a href="index.jsp">Home</a>&nbsp;&nbsp;&nbsp;
	<%
	UserVO user = (UserVO) session.getAttribute("user");
	%>
      
	<%	if(user == null) { %>
      
	<a href="insertUser.jsp">회원가입</a>&nbsp;&nbsp;&nbsp;
	<a href="login.jsp">로그인</a>&nbsp;&nbsp;&nbsp;
      
	<%	} else { %>
      
	<a href="getBoardList.do">글목록</a>&nbsp;&nbsp;&nbsp;
	<a href="insertBoard.jsp">글등록</a>&nbsp;&nbsp;&nbsp;
	<a href="logout.do">로그아웃</a>&nbsp;&nbsp;&nbsp;
      
	<%	} %>

	<hr>
	<br>


3) 회원 가입 및 로그인

  • insertUser.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ include file="../layout/header.jsp" %>

<center>
<form action="insertUser.do" method="post">
<table border="1" cellpadding="0" cellspacing="0">
	<tr>
		<td bgcolor="orange">아이디</td>
		<td><input type="text" name="id" size="10" /></td>
	</tr>
	<tr>
		<td bgcolor="orange">비밀번호</td>
		<td><input type="password" name="password" size="12" /></td>
	</tr>
	<tr>
		<td bgcolor="orange">이름</td>
		<td><input type="text" name="name" size="30" /></td>
	</tr>
	<tr>
		<td bgcolor="orange">권한</td>
		<td>
			<input type="radio" name="role" value="USER" checked="checked" />일반회원
	        <input type="radio" name="role" value="ADMIN" />관리자
		</td>
	</tr>
	<tr>
		<td colspan="2" align="center">
			<input type="submit" value="회원가입" />
		</td>
	</tr>
</table>
</form>
</center>

<%@ include file="../layout/footer.jsp" %>
  • login.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ include file="../layout/header.jsp" %>

<center>
<form action="login.do" method="post">
<table border="1" cellpadding="0" cellspacing="0">
	
	<tr>
		<td bgcolor="orange">아이디</td>
		<td><input type="text" name="id" size="20" /></td>
	</tr>
	
	<tr>
		<td bgcolor="orange">비밀번호</td>
		<td><input type="password" name="password" size="20" /></td>
	</tr>

	<tr>
		<td colspan="2" align="center">
			<input type="submit" value="로그인" />
		</td>
	</tr>
</table>
</form>
</center>

<%@ include file="../layout/footer.jsp" %>


4) 게시물 및 게시판

  • insertBoard.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ include file="../layout/header.jsp" %>

<center>
<form action="insertBoard.do" method="post">
<table border="1" cellpadding="0" cellspacing="0">
	<tr>
		<td bgcolor="orange" width="70">제목</td><td align="left">
		<input type="text" name="title"/></td>
	</tr>
	<tr>
		<td bgcolor="orange">작성자</td><td align="left">
		<input type="text" name="writer" size="10"/></td>
	</tr>
	<tr>
		<td bgcolor="orange">내용</td><td align="left">
		<textarea name="content" cols="40" rows="10"></textarea></td>
	</tr>
	<tr>
		<td colspan="2" align="center">
		<input type="submit" value="글등록"/></td>
	</tr>
</table>
</form>
</center>

<%@ include file="../layout/footer.jsp" %>
  • getBoardList.jsp
<%@page contentType="text/html; charset=UTF-8" %>
<%@include file="../layout/header.jsp" %>

<center>

<!-- 검색 화면 시작 -->
<form action="getBoardList.do" method="post">
<table border="1" cellpadding="0" cellspacing="0" width="700">
	<tr>
		<td align="right">
			<select name="searchCondition">
				<option value="TITLE" <c:if test="${condition == 'TITLE' }">selected</c:if>>제목
				<option value="CONTENT" <c:if test="${condition == 'CONTENT' }">selected</c:if>>내용
			</select>
			<input type="text" name="searchKeyword" value="${keyword }" />
			<input type="submit" value="검색" />
		</td>
	</tr>
</table>
</form>
<!-- 검색 화면 종료 -->

<table border="1" cellpadding="0" cellspacing="0" width="700">
<tr>
	<th bgcolor="orange" width="100">번호</th>
	<th bgcolor="orange" width="200">제목</th>
	<th bgcolor="orange" width="150">작성자</th>
	<th bgcolor="orange" width="150">등록일</th>
	<th bgcolor="orange" width="100">조회수</th>
</tr>

<c:forEach var="board" items="${boardList }">
<tr>
	<td>${board.seq }</td>
	<td align="left"><a href="getBoard.do?seq=${board.seq }">${board.title }</a></td>
	<td>${board.writer }</td>
	<td>${board.regDate }</td>
	<td>${board.cnt }</td>
</tr>
</c:forEach>

</table>
</center>

<%@include file="../layout/footer.jsp" %>
  • getBoard.jsp
<%@page contentType="text/html; charset=UTF-8" %>
<%@ include file="../layout/header.jsp" %>

<center>
<form action="updateBoard.do" method="post">
<input name="seq" type="hidden" value="${board.seq }"/>
<table border="1" cellpadding="0" cellspacing="0">
	<tr>
		<td bgcolor="orange" width="70">제목</td>
		<td align="left"><input name="title" type="text" value="${board.title }"/></td>
	</tr>
	<tr>
		<td bgcolor="orange">작성자</td>
		<td align="left">${board.writer }</td>
	</tr>
	<tr>
		<td bgcolor="orange">내용</td>
		<td align="left">
			<textarea name="content" cols="40" rows="10">${board.content }</textarea>
		</td>
	</tr>
	<tr>
		<td bgcolor="orange">등록일</td>
		<td align="left">${board.regDate }</td>
	</tr>
	<tr>
		<td bgcolor="orange">조회수</td>
		<td align="left">${board.cnt }</td>
	</tr>
	<tr>
		<td colspan="2" align="center">
			<input type="submit" value="글 수정"/>
		</td>
	</tr>
</table>
</form>
<br>

<c:if test="${user.role == 'ADMIN' }">
<a href="deleteBoard.do?seq=${board.seq }">글삭제</a>
</c:if>

</center>

<%@ include file="../layout/footer.jsp" %>
 


5) DispatcherServlet 기능 로직

@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	
	public DispatcherServlet() {}
	
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 사용자 요청 path 정보를 추출
		String uri = request.getRequestURI();
		String path = uri.substring(uri.lastIndexOf("/"));
		System.out.println("요청 path : " + path);
		
		// 추출한 path 정보에 따라서 요청을 분기처리
		if(path.equals("/login.do")) {
			System.out.println("로그인 기능 처리");
			
			// 사용자 입력정보 추출
			String id = request.getParameter("id");
			String password = request.getParameter("password");
			
			// DB 연동 처리
			UserVO vo = new UserVO();
			vo.setId(id);
			
			UserDAO dao = new UserDAO();
			UserVO user = dao.getUser(vo);
			
			
			// 화면 이동
			HttpSession session = request.getSession();
			if(user != null) {
				if(user.getPassword().equals(password)) {
					// 상태 정보를 세션에 저장 
					session.setAttribute("user", user);
					
					// 글 목록 화면으로 이동
					response.sendRedirect("/getBoardList.do");
				} else {
					response.sendRedirect("/login.jsp");
				}
			} else {
				response.sendRedirect("/insertUser.do");
			}
			
		} else if(path.equals("/logout.do")) {
			System.out.println("로그아웃 기능 처리");
			
			HttpSession session = request.getSession();
			session.invalidate();

			response.sendRedirect("/");
			
		} else if(path.equals("/insertUser.do")) {
			System.out.println("회원 등록 기능 처리");
			
			// 사용자 입력정보 추출
			String id = request.getParameter("id");
			String password = request.getParameter("password");
			String name = request.getParameter("name");
			String role = request.getParameter("role");
				
			// DB 연동 처리
			UserVO vo = new UserVO();
			vo.setId(id);
			vo.setPassword(password);
			vo.setName(name);
			vo.setRole(role);
			
			UserDAO dao = new UserDAO();
			dao.insertUser(vo);
			
			// 화면 이동
			RequestDispatcher dispatcher = request.getRequestDispatcher("/getBoardList.do");
			dispatcher.forward(request, response);
			
			
		} else if(path.equals("/insertBoard.do")) {
			System.out.println("글 등록 기능 처리");
			
			// 사용자 입력정보 추출
			String title = request.getParameter("title");
			String writer = request.getParameter("writer");
			String content = request.getParameter("content");
			
			// DB 연동 처리
			BoardVO vo = new BoardVO();
			vo.setTitle(title);
			vo.setWriter(writer);
			vo.setContent(content);
			
			BoardDAO boardDAO = new BoardDAO();
			boardDAO.insertBoard(vo);
			
			// 페이지 네비게이션
			RequestDispatcher dispatcher = request.getRequestDispatcher("/getBoardList.do");
			dispatcher.forward(request, response);
			
		} else if(path.equals("/updateBoard.do")) {
			System.out.println("글 수정 기능 처리");
			
			// 사용자 입력정보 추출
			String title = request.getParameter("title");
			String seq = request.getParameter("seq");
			String content = request.getParameter("content");
			
			// DB 연동 처리
			BoardVO vo = new BoardVO();
			vo.setTitle(title);
			vo.setSeq(Integer.parseInt(seq));
			vo.setContent(content);
			
			BoardDAO boardDAO = new BoardDAO();
			boardDAO.updateBoard(vo);
			
			// 페이지 네비게이션
			RequestDispatcher dispatcher = request.getRequestDispatcher("/getBoardList.do");
			dispatcher.forward(request, response);
			
		} else if(path.equals("/deleteBoard.do")) {
			System.out.println("글 삭제 기능 처리");
			
			// 사용자 입력정보 추출
			String seq = request.getParameter("seq");
			
			// DB 연동 처리
			BoardVO vo = new BoardVO();
			vo.setSeq(Integer.parseInt(seq));
			
			BoardDAO boardDAO = new BoardDAO();
			boardDAO.deleteBoard(vo);
			
			// 페이지 네비게이션
			RequestDispatcher dispatcher = request.getRequestDispatcher("/getBoardList.do");
			dispatcher.forward(request, response);
			
		} else if(path.equals("/getBoard.do")) {
			System.out.println("글 상세 조회 기능 처리");
			
			// 사용자 입력정보 추출
			String seq = request.getParameter("seq");
			
			// DB 연동 처리
			BoardVO vo = new BoardVO();
			vo.setSeq(Integer.parseInt(seq));
			
			BoardDAO boardDAO = new BoardDAO();
			BoardVO board = boardDAO.getBoard(vo);
			
			// 화면 이동
			// 검색 결과를 request 객체에 등록하고 글 목록 화면(getBoardList.jsp)으로 이동(forwarding)
			request.setAttribute("board", board);
			RequestDispatcher dispatcher = request.getRequestDispatcher("getBoard.jsp");
			dispatcher.forward(request, response);
			
		} else if(path.equals("/getBoardList.do")) {
			System.out.println("글 목록 검색 기능 처리");
			
			// 사용자 입력정보 추출
			String searchCondition = request.getParameter("searchCondition");
			String searchKeyword = request.getParameter("searchKeyword");

			// Null Check
			if(searchCondition == null) searchCondition = "TITLE";
			if(searchKeyword == null) searchKeyword = "";
			
			request.setAttribute("condition", searchCondition);
			request.setAttribute("keyword", searchKeyword);

			// DB 연동 처리
			BoardVO vo = new BoardVO();
			vo.setSearchCondition(searchCondition);
			vo.setSearchKeyword(searchKeyword);
			
			BoardDAO dao = new BoardDAO();
			List<BoardVO> boardList = dao.getBoardList(vo);
			
			// 화면 이동
			// 검색 결과를 request 객체에 등록하고 글 목록 화면(getBoardList.jsp)으로 이동(forwarding)
			request.setAttribute("boardList", boardList);
			RequestDispatcher dispatcher = request.getRequestDispatcher("getBoardList.jsp");
			dispatcher.forward(request, response);
			
		} else {
			System.out.println("요청 URL이 잘못되었습니다.");
		}
	}

}


🍑게시판 사이트 동작 형태🍑

처음에는 일반 회원 권한으로 로그인하여 글만 수정하고, 두번째는 관리자 권한으로 로그인하여 글 삭제합니다.
그리고 제목과 내용 키워드 중 제목에서 sp 에 해당하는 게시물을 찾아내는 영상입니다.
그 외 다른 기능들은 github 코드를 참고해주세요



🧐회고🧐

클론 코딩이라서 지난번 프로젝트보다는 비교적 수월했다. 웹과 서버의 동작 방식이 여러개가 있고 각 강단점을 잘 파악할 수 있는 계기가 되었다. ServletJSP 뿐만아니라 ELJSTL 을 사용하여 더 가벼운 코드를 작성하는 것이 무엇인지 잘 알 수 있었다. 특히 Dispatch 클래스를 활용할 때 여러 동작을 한번에 관리할 수 있어서 매우 편하다고 생각했다. xml, html 파일에 의존적이지 않고 각 기능마다 필요한 페이지를 동적인 형태로 만든다는 것이 무슨 의미인지 잘 와닿지 않았었는 데 JSP를 많이 이용하면서 많은 개념을 이해할 수 있었다.

profile
imaginative and free developer. 백엔드 / UX / DATA / 기획에 관심있지만 고양이는 없는 예비 개발자👋

0개의 댓글