딸기말차

[Java web] 3. Servlet 실습 본문

Bootcamp/Java web

[Java web] 3. Servlet 실습

딸기말차 2023. 7. 14. 01:01

엔코아 플레이데이터(Encore Playdata) Backend 2기 백엔드 개발 부트캠프 (playdata.io)

 

백엔드 개발 부트캠프

백엔드 기초부터 배포까지! 매력있는 백엔드 개발자 포트폴리오를 완성하여 취업하세요.

playdata.io


1. Servlet 실습_1) 게시판

어제의 실습은 jsp만 사용해 해결하였지만, 금일 실습은 jsp 간의 데이터 전달이 아니라 servlet을 사용한 전달을 실습하였다. 해당 실습에 주어진 DB table은 다음과 같다.

board table

주어진 DB를 활용해, 구현해야하는 servlet은 다음과 같다.

 

1. BoardListServlet

DB에서 데이터를 가져와 boardList.jsp로 넘겨 게시물을 화면에 뿌려줄 수 있게 해주는 servlet이다.

 

2. BoardWriteServlet

BoardWrite.jsp에서 form 태그를 통해 post 방식으로 BoardWriteServlet으로 데이터를 전달하고, 해당 데이터를 insert query로 DB에 저장한다. 

 

3. BoardDetailServlet

게시글 제목을 누르면, primary key인 num 값을 get 방식으로 전달받고, 전달받은 num 값을 이용해 해당 num 값을 가진 게시물을 DB에서 가져와 boardDetail.jsp로 넘겨 화면에 뿌려준다.

 

4. BoardModifyServlet

BoardModify.jsp에서 새롭게 입력한 데이터를 form 태그를 통해 post 방식으로 boardModifyServlet으로 전달하고, 해당 데이터를 update query로 DB에 저장한다.

 

5. BoardDetailServlet

삭제 버튼을 누르면, primary key인 num 값을 get 방식으로 전달받고, 전달받은 num 값을 이용해 해당 num 값을 가진 게시물을 DB에서 삭제한다.


2.  구조 설계

각 servlet과 jsp 파일에서, 어떤 방식을 사용해 어디로 가는지에 대한 프로젝트 진행 구조를 정리하였다.

 

출발 주소 / 전송방식 dispatcher get post redirect
BoardListServlet BoardList.jsp
(select table)
     
BoardList.jsp   BoardDetailServlet
(게시물 제목 클릭)
BoardListServlet
(검색 버튼)
BoardListServlet
(목록 버튼)
BoardWrite.jsp
(글쓰기 버튼)
BoardWriteServlet       BoardListServlet
BoardWrite.jsp     BoardWriteServlet
(게시물 저장버튼)
BoardListServlet
(목록 버튼)
BoardDetailServlet BoardDetail.jsp
(select table)
     
BoardDetail.jsp   BoardModifyServlet
(수정 버튼)
BoardDeleteServlet
(삭제 버튼)
  BoardListServlet
(목록 버튼)
BoardModifyServlet BoardModify.jsp
(doGet method)
    BoardListServlet
(doPost method)
BoardModify.jsp     BoardModifyServlet
(게시물 수정버튼)
BoardListServlet
(목록 버튼)
BoardDeleteServlet       BoardListServlet

3.  BoardListServlet / BoardList.jsp

DB에 저장 된 게시물들의 목록을 불러오는 페이지이다. 우선 BoardListServlet의 구조를 정리해보면,

 

1. 게시물들을 저장할 BoardDAO 타입의 리스트를 생성한다.

2. 검색을 위해 고른 카테고리와 검색어를 request 객체를 통해 받아서 저장한다.

3. 만약 고른 카테고리와 검색어가 없다면, 모든 게시물을 select해 dispatcher 객체를 통해 jsp로 넘겨준다.

4. 만약 고른 카테고리와 검색어가 있다면, 해당 검색에 맞는 게시물을 select해 dispatcher 객체를 통해 jsp로 넘겨준다.

@WebServlet("/boardList")
public class BoardListServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private ArrayList<BoardDAO> boards = new ArrayList<BoardDAO>();
	private MySQLConnector mySQLConnector = new MySQLConnector();
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		String name = request.getParameter("search");
		String keyword = request.getParameter("keyword");
		
		if (name == null || keyword == null) {
			boards = mySQLConnector.selectAllList();
			request.setAttribute("boards", boards);
			RequestDispatcher requestDispatcher = request.getRequestDispatcher("BoardList.jsp");
			requestDispatcher.forward(request, response);
		}
		else {
			boards = mySQLConnector.searchKeyword(name, keyword);
			request.setAttribute("boards", boards);
			RequestDispatcher requestDispatcher = request.getRequestDispatcher("BoardList.jsp");
			requestDispatcher.forward(request, response);
		}	
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

 

다음으로 BoardList.jsp의 구조를 정리해보자면,

 

1. Dispatcher 객체를 통해 넘겨받은 게시물 리스트를 getAttribute를 통해 저장한다.

2. searchForm이라는 name을 가진 form 태그를 통해 카테고리, 검색어를 입력받는다.

3. 만약 게시물 리스트의 size가 0이라면 등록 된 게시물이 없다는 문구를, size가 0이 아니라면 for문을 통해 게시물 리스트를 화면에 뿌려준다.

4. 게시물의 제목을 누르면, boardDetail servlet에 get 방식으로 게시물의 번호를 넘겨준다.

5. 목록 버튼을 누르면, 해당 페이지로 다시 redirect 한다.

6. 글쓰기 버튼을 누르면, BoardWrite.jsp 로 redirect 한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.lhs.dao.*" %>
<%ArrayList<BoardDAO> boards = (ArrayList<BoardDAO>)request.getAttribute("boards");%>
	
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
<title>게시판 목록</title>

<style type="text/css">
* {
	font-size: 9pt;
}

p {
	width: 600px;
	text-align: right;
}

table thead tr th {
	background-color: gray;
}
</style>
<script type="text/javascript">
	function boardWrite() {
		document.location = "BoardWrite.jsp";
	}
</script>
</head>
<body>
	<form name="searchForm" action="" method="get">
		<p>
			<select name="search">
				<option value="ALL">전체검색</option>
				<option value="SUBJECT">제목</option>
				<option value="WRITER">작성자</option>
				<option value="CONTENTS">내용</option>
			</select> 
			<input type="text" name="keyword" value="" /> 
			<input type="submit" value="검색" />
		</p>
	</form>

	<table border="1" summary="게시판 목록">
		<caption>게시판 목록</caption>
		<colgroup>
			<col width="50" />
			<col width="300" />
			<col width="80" />
			<col width="100" />
			<col width="70" />
		</colgroup>
		<thead>
			<tr>
				<th>번호</th>
				<th>제목</th>
				<th>작성자</th>
				<th>등록 일시</th>
				<th>조회수</th>
			</tr>
		</thead>
		<tbody>
			<%if (boards.size() == 0) { %>
			<tr>
				<td align="center" colspan="5">등록된 게시물이 없습니다.</td>
			</tr>
			<%} else {%>
				<%for (BoardDAO board : boards) {%>
					<tr>
						<td align="center"><%=board.getNum()%></td>
						<td><a href="boardDetail?num=<%=board.getNum()%>"><%=board.getSubject()%></a></td>
						<td align="center"><%=board.getWriter()%></td>
						<td align="center"><%=board.getReg_date()%></td>
						<td align="center"><%=board.getHit()%></td>
					</tr>
				<%}%>
			<%}%>
		</tbody>
		<tfoot>
			<tr>
				<td align="center" colspan="5">1</td>
			</tr>
		</tfoot>
	</table>

	<p>
		<input type="button" value="목록" onclick="boardList()" />
		<input type="button" value="글쓰기" onclick="boardWrite()" />
	</p>
</body>
</html>

4.  BoardWriteServlet / BoardWrite.jsp

form 태그를 통해 게시물을 작성 후 DB에 저장하는 페이지이다. 우선 BoardWriteServlet의 구조를 정리해보면,

 

1. 작성한 게시물의 데이터를 저장할 BoardDAO 타입의 객체를 생성한다.

2. post 방식으로 데이터를 넘겼기 때문에, 인코딩 정보를 UTF-8로 설정한다.

3. form 태그로 넘어온 데이터를 request.getParameter로 불러와, BoardDAO 객체에 저장한다.

4. 해당 BoardDAO 객체를 insert query를 실행하는 메서드로 넘겨, insert를 실행한다.

5. insert를 마쳤다면, boardList servlet으로 redirect 한다.

@WebServlet("/boardWrite")
public class BoardWriteServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private MySQLConnector mySQLConnector = new MySQLConnector();
	private BoardDAO board = new BoardDAO();

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		board.setSubject(request.getParameter("subject"));
		board.setWriter(request.getParameter("writer"));
		board.setContents(request.getParameter("contents"));
		board.setIp(request.getRemoteAddr());
		mySQLConnector.insertNewContents(board);
		response.sendRedirect("/board_mysql/boardList");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

 

다음으로 BoardWrite.jsp의 구조를 정리해보자면,

 

1. form 태그의 action에 boardWrite라는 servlet 주소를 넣어, 입력한 값들이 submit 될 때 servlet으로 작성한 데이터를 넘길 수 있게 한다.

2. form 태그 내에서 입력을 진행한다. 이때 required 옵션으로 입력 값이 없으면 반드시 쓰게 하고, autofocus 옵션으로 해당 페이지에 넘어왔을 때 커서 위치를 지정해준다.

3. List 버튼을 누르면, boardList servlet으로 redirect 한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 등록 폼</title>
<script type="text/javascript">
	function boardList() {
		document.location = "boardList";
	}
</script>

</head>
<body>
	<h2>게시판 등록 폼</h2>
	<form action="boardWrite" method="POST">
	  제목: <input type="text" name="subject" required="required" autofocus  /><br />
	  글쓴이: <input type="text" name="writer" required="required" /><br />
	  내용: <textarea rows = "5" cols="50" name="contents" required="required"></textarea><br/>
	  <input type="submit" value="저장">
	</form>
	<input type="button" value="List" onclick="boardList()">
</body>
</html>

5.  BoardDetailServlet / BoardDetail.jsp

BoardList 페이지에서 게시물의 제목을 누를 시 넘어오는 게시물 상세페이지이다. 우선 BoardDetailServlet의 구조를 정리해보면,

 

1. 선택한 게시물의 데이터를 저장할 BoardDAO 객체를 생성한다.

2. BoardList.jsp에서 get방식으로 넘겨받은 게시물의 번호를 request.getParameter로 가져와 저장한다.

3. BoardList.jsp에서 게시물의 제목을 눌러 접근했기 때문에, 조회수가 올라야한다.

때문에 게시물의 번호를 update query를 실행하는 메서드의 인자로 넘겨 게시물의 조회수를 update한다.

4. 게시물의 번호를 해당 게시물을 select 하기 위한 메서드의 인자로 넘겨 게시물 데이터를 가져온다.

5. 게시물 데이터를 dispatcher 객체에 담아 BoardDetail.jsp로 넘겨준다.

@WebServlet("/boardDetail")
public class BoardDetailServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private MySQLConnector mySQLConnector = new MySQLConnector();
	private BoardDAO board = new BoardDAO();
	   
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int num = Integer.parseInt(request.getParameter("num"));
		mySQLConnector.updateHitCount(num);
		board = mySQLConnector.selectDetailPage(num);
		request.setAttribute("board", board);
		
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("BoardDetail.jsp");
		requestDispatcher.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

 

다음으로 BoardDetail.jsp의 구조를 정리해보자면,

 

1. Dispatcher 객체를 통해 넘겨받은 게시물을 getAttribute를 통해 저장한다.

2. table 태그 내에 가져온 데이터를 뿌려준다.

3. 수정 버튼을 누르면, 해당 게시글의 번호를 get 방식으로 boardModify servlet에 넘겨준다.

4. 목록 버튼을 누르면, boardList servlet으로 redirect 된다.

5. 삭제 버튼을 누르면, 해당 게시글의 번호를 get방식으로 boardDelete servlet에 넘겨준다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.lhs.dao.*" %>

<%BoardDAO board = (BoardDAO)request.getAttribute("board");%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 상세조회</title>
<script type="text/javascript">
	function boardModify(num) {
		document.location = "boardModify?num=" + num;
	}
	
	function boardList() {
		document.location = "boardList";
	}
	
	function boardDelete(num) {
		document.location = "boardDelete?num=" + num;
	}

</script>

</head>
<body>
	<h2>게시판 상세조회</h2>
	<table border="1">
		<th>제목</th>
		<tr>
			<td><%=board.getSubject()%></td>
		</tr>
		
		<th>작성자 / 조회수</th>
		<tr>
			<td><%=board.getWriter()%> / <%=board.getHit()%></td>
		</tr>
		
		<th>등록일시</th>
		<tr>
			<td><%=board.getReg_date()%></td>
		</tr>
		
		<th>내용</th>
		<tr>
			<td><%=board.getContents()%></td>
		</tr>
    </table>
    <input type="button" value="modify" onclick="boardModify(<%=board.getNum()%>)">
    <input type="button" value="list" onclick="boardList()">
    <input type="button" value="delete" onclick="boardDelete(<%=board.getNum()%>)">
</body>
</html>

6. BoardModifyServlet / BoardModify.jsp

BoardDetail.jsp에서 get 방식으로 받은 게시물 번호를 통해 수정할 내용을 화면에 보여주고, 수정을 진행할 수 있는 페이지이다. 우선 BoardModifyServlet의 구조를 보면,

 

1. get 방식으로 넘겨받은 게시물 번호를 사용해 해당 게시물을 select하여, BoardDAO 객체에 담는다.

2. BoardDAO 객체를 dispatcher를 통해 BoardDetail.jsp로 넘겨준다.

3. 넘겨준 BoardDAO 객체로 수정할 내용을 확인하고, form 태그를 통해 post 방식으로 수정할 데이터들이 넘어오면, request.getParameter로 받아 저장한다.

4. 저장한 수정할 데이터들을 update query의 인자로 넘겨, update를 진행한다.

5. update가 완료되면 boardList servlet으로 redirect 한다.

@WebServlet("/boardModify")
public class BoardModifyServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	MySQLConnector mySQLConnector = new MySQLConnector();
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		BoardDAO board = mySQLConnector.selectModifyData(Integer.parseInt(request.getParameter("num"))); 
		request.setAttribute("board", board);
		
		RequestDispatcher rd = request.getRequestDispatcher("BoardModify.jsp");
		rd.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		int num = Integer.parseInt(request.getParameter("num"));
		String subject = request.getParameter("subject");
		String writer = request.getParameter("writer");
		String contents = request.getParameter("contents");
		mySQLConnector.updateModifyData(num, subject, writer, contents);
		response.sendRedirect("/board_mysql/boardList");
	}
}

 

위 코드를 보면 doGet 메서드와 doPost 메서드를 둘다 사용하고 있다. 이 순서를 헷갈리지 말아야하는데,

1. BoardDetail.jsp에서 수정 버튼을 눌렀을 경우 get 방식으로 BoardModify servlet에 접근한다. 때문에 처음에 이 servlet은 doGet 메서드를 실행한다.

2. 이 후 doGet 메서드 내에서 BoardModify.jsp로 넘어가고, form 태그 내에서 수정할 데이터들을 작성한다.

3. form 태그의 method를 post로 지정했기 때문에, 수정할 데이터를 작성 후 저장 버튼을 누르면 다시 BoardModify servlet으로 접근해, doPost 메서드를 실행한다.

 

다음으로 BoardModify.jsp의 구조를 정리해보자면,

 

1. BoardModify servlet에서 넘어온 BoardDAO 객체를 request.getAttribute로 호출해 저장한다.

2. 저장한 데이터를 사용해 수정할 내용을 화면에 뿌려준다.

3. form 태그를 통해 수정할 내용을 입력받는다.

4. form 태그의 action이 BoardModify servlet의 주소기 때문에, 저장 버튼을 누를 시 수정할 내용이 post 방식으로 BoardModify servlet으로 전달된다.

5. 목록 버튼을 누르면, boardList servlet으로 redirect 된다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.lhs.dao.*"%>
<% BoardDAO boarddao = (BoardDAO)request.getAttribute("board"); %>

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
	function boardList(){
		document.location = "boardList";
	}
</script>
<meta charset="UTF-8">
<title>게시판 수정 폼</title>
</head>

<body>
	<h2>게시판 수정 폼</h2>
	<form action="boardModify"  method="post" style="width: 70%; height: 40%;">
		제목<input type="text" name="subject" value=<%= boarddao.getSubject() %>><br />
		글쓴이<input type="text" name="writer" value=<%= boarddao.getWriter() %>><br />
		<textarea name="contents" style="width: 100%; height: 150px;"><%= boarddao.getContents() %></textarea> <br />
		<input type="hidden" name="num" value=<%=boarddao.getNum()%>>
		<input type="submit" value="저장">
	</form>
	<input type="button" value="목록" onclick="boardList()">
</body>
</html>

7. BoardDeleteServlet

BoardDetail.jsp에서 get 방식으로 넘겨받은 게시물 번호를 사용해 삭제를 진행하는 페이지이다. 해당 기능은 삭제를 하고 BoardList servlet으로 redirect 되기 때문에, jsp는 사용하지 않고 servlet으로만 구현하였다. 해당 servlet의 구조를 보자면,

 

1. 넘어온 게시물 번호를 request.getParameter로 저장한다.

2. 저장한 번호를 delete query를 실행하는 메서드의 인자로 넘겨, delete를 진행한다.

3. 삭제를 진행한 후, 삭제를 완료했다는 alert 창을 띄우고 BoardList servlet으로 redirect 한다.

@WebServlet("/boardDelete")
public class BoardDeleteServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private MySQLConnector mySQLConnector = new MySQLConnector();
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int num = Integer.parseInt(request.getParameter("num")); 
		mySQLConnector.deleteBoard(num);
		
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter outs = response.getWriter();
		outs.println("<script>alert('삭제되었습니다.'); location.href='boardList';</script>");
		outs.flush();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	}
}

8.  15일차 후기

이전 팀 실습을 부여받았을 땐 설계 과정을 거치지 않고 팀원끼리 각자 코딩만을 진행하였다. 하지만 그렇게 실습을 진행하니, 구현한 프로젝트 내 servlet, jsp들 안에서 데이터의 흐름이 각자 달라 사실상 통합을 진행할 수 없는 코드가 만들어졌었다. 

때문에 이번 실습은 최대한 설계에 집중해 진행하였다. 프로젝트 구조, 파일 명, servlet 주소 등을 최대한 통일시켜 프로젝트를 통합 시 최대한 에러가 나지 않게 하기 위해 노력해 보았다.

 

물론 통합을 진행하고 에러가 나지 않은 것은 아니었지만, 금방 수정할 수 있었고, 그만큼 초기 설계가 굉장히 중요하다는 것을 알게되었다. 또한 설계가 잘 되어있을수록 코딩시간도 단축되는 것을 느낄 수 있었다.

때문에 다음 프로젝트는 최대한 자세히 초기 설계를 구성해, 어느 사람이 와도 설계서를 보면 개발을 진행할 수 있는 환경을 만들어봤으면 좋겠다고 생각했다.

'Bootcamp > Java web' 카테고리의 다른 글

[Java web] 6. Mini Project_2  (0) 2023.07.22
[Java web] 5. EL, JSTL, Java Beans  (1) 2023.07.18
[Java web] 4. Session, JSP tag  (0) 2023.07.15
[Java web] 2. JSP 실습  (0) 2023.07.13
[Java web] 1. Servlet, JSP  (0) 2023.07.12