초보의 Servlet 개발 조회
별 재미없는 이야기만 주저리주저리 했으니 신나는 개발을 해보자.
1. 목표
index.jsp(이하 메인)에서 버튼을 클릭하여 목록으로 진입하고 목록에서 특정 Row를 선택하면 상세 화면으로 이동하자.
- 메인을 수정하고 회원 목록으로 이동하기
- 회원목록은 open시 DB에 적재된 모든 회원을 조회
- 회원목록에서 특정 Row를 클릭하면 상세로 이동
- 회원상세는 open시 특정된 Row의 상세 데이터만 조회하고 출력
2. 메인 수정
소스코드 :
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>olDevServlet Hello World!</title>
</head>
<body>
<p> 여기가 Main!!</p>
<form id="indexFrm" name="indexFrm">
<a href="javascript:void(0);" onclick="fnPageChange('/mberList.do', 'post')">회원목록</a>
</form>
</body>
<script type="text/javascript">
function fnPageChange(url, type) {
var frm = document.getElementById("indexFrm");
frm.method = type;
frm.action = url;
frm.submit();
}
</script>
</html>
특별한 내용은 딱히 없고 method post 버튼명을 회원 목록으로 변경하고 get을 제거함.
3. Servlet mapping (web.xml) 수정
소스코드 :
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID"
version="2.5">
<display-name>olDevServlet</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>mberList</servlet-name>
<servlet-class>com.MberListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mberList</servlet-name>
<url-pattern>/mberList.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>mberDetail</servlet-name>
<servlet-class>com.MberDetailServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mberDetail</servlet-name>
<url-pattern>/mberDetail.do</url-pattern>
</servlet-mapping>
</web-app>
목록과 상세를 조회할 것 이기 때문에 기존의 sample은 삭제하고 목록, 상세 Servlet을 mapping 해줌.
4. 회원목록 (MberListServlet.java, mberListView.jsp)
소스코드(MberListServlet.java) :
package com;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MberListServlet extends HttpServlet {
private static final long serialVersionUID = 3161530544990290786L;
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// get 방식으로 안보낼 생각임
}
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
Connection dbConn = null;
List<Map<String, Object>> resultList = null;
try {
Class.forName("org.mariadb.jdbc.Driver");
dbConn = DriverManager.getConnection(
"jdbc:mariadb://127.0.0.1:3306/oldev"
, "olDev"
, "olDev@1234"
);
Statement stmt = dbConn.createStatement();
String sqlStr = "";
sqlStr += "SELECT MBER_SN ";
sqlStr += " , MBER_ID ";
sqlStr += " , MBER_PWD ";
sqlStr += " , MBER_NM ";
sqlStr += " , IFNULL(MBER_MOBLPHON, '') AS MBER_MOBLPHON ";
sqlStr += " , IFNULL(RM, '') AS RM ";
sqlStr += " , REGIST_SN ";
sqlStr += " , REGT_DTTM ";
sqlStr += " , UPDT_SN ";
sqlStr += " , UPDT_DTTM ";
sqlStr += " FROM OD_MBER ";
ResultSet resultSet = stmt.executeQuery(sqlStr);
if (resultSet != null) {
resultList = new ArrayList<Map<String, Object>>();
while(resultSet.next()) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("mberSn", resultSet.getString("MBER_SN"));
map.put("mberId", resultSet.getString("MBER_ID"));
map.put("mberPwd", resultSet.getString("MBER_PWD"));
map.put("mberNm", resultSet.getString("MBER_NM"));
map.put("moblPhon", resultSet.getString("MBER_MOBLPHON"));
map.put("rm", resultSet.getString("RM"));
map.put("regiSn", resultSet.getString("REGIST_SN"));
map.put("regiDt", resultSet.getString("REGT_DTTM"));
map.put("updtSn", resultSet.getString("UPDT_SN"));
map.put("updtDt", resultSet.getString("UPDT_DTTM"));
resultList.add(map);
}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
req.setAttribute("result", resultList);
RequestDispatcher rd = req.getRequestDispatcher("/mberListView.jsp");
rd.forward(req, resp);
}
}
뭔가 오지게 길어 보이지만 소스코드를 잘 보면 JSP 개발에서 사용했던 조회 SQL을 그대로 가져왔다.
Connection, statement 등 SQL을 사용하려면 안 쓸 수가 없지 않겠는가? 그래서 복붙 복붙...ㅎㅎ
- driver jar 추가
JSP 개발에서 사용했던 mariadb-java-client-2.7.0.jar를 WEB-INF/lib 밑으로 옮겨놓고 만약 옮기지 않고 소스코드를 실행시키면 ClassNotFoundException이 발생하는데 Class.forName("...") 이 눔이 클래스를 못 찾아서 그렇다. 당장에 옮겨주자.
- RequestDispatcher
전 글에서 response.sendRedirect("...") method는 응답 페이지로 데이터를 전달할 수 없었다. 그래서 응답 페이지로 데이터를 전달하기 위한 방법으로 HttpServlet은 RequestDispatcher method를 제공하는데 응답될 화면에 request와 response를 forward 시켜줌으로써 요청에 대한 응답의 data 값을 유지할 수 있도록 해준다.
SendRedirect
앞서 설명하대로 Redirect는 request, respose를 유지하지 않고 응답받은 browser가 새 화면으로 보내주는 역할을 했었는데 아래 Dispatcher를 보자.
RequestDispatcher
SendRedirect처럼 예상은 '어 그럼 Dispatcher는 바로 호출하나 보네?'라고 생각할 수 있겠지만 실제론 이미지와 같이 요청을 먼저 받은 Servlet이 Dispatcher에 설정된 Servlet에 보낼 데이터를 세팅하고 Forward를 하게 되며 Forward 된 Servlet이 Response를 보냄으로써 Borwser는 응답을 받게 된다.
chrome을 열고 F12를 눌러둔 상태에서 조회를 실행하고 이미지와 같이 순서대로 눌러서 응답을 확인해보자.
이미지와 같이 Borwser는 응답으로 mberListView.jsp의 결과 html을 받았다.
이를 순서대로 다시 정리해보면
-> 메인에서 mberList.do 호출
-> Servlet Mapping 된 MberListServlet.java에서 요청을 받음
-> SQL을 수행하고 결과를 도출 Request.setAttribute를 설정
-> RequestDispatcher... Forward로 mberListView.jsp 호출
-> mberListView.jsp는 Request.getAttribute로 받은 데이터 처리
-> Browser에 mberListView.jsp Response를 보냄
-> Browser에 내용이 Rendering 되고 종료
뭐 이런 순서이고 결국 Servlet을 호출하면 제2의 Servlet으로 보낼거 보내고 나 대신 응답 해주세요 하는 건데 사실 이런 거 외울 필요가 있을까 싶다. Dispatcher Forward 아니면 데이터 못 보내는데 간단하게 아무것도 없이 페이지 호출은 SendRedirect, 페이지에 데이터 전달이 필요하면 Dispatcher Forward 로만 생각해도 될 것 같다. 참고로 데이터 안 보내는 화면이 몇 개나 되겠나? 거의 Forward 한다고 보면 될 것 같다. (문법이나 잘 지키면 되는게 아닐까?....)
Servlet에서 하는건 그렇다 치고 다음 화면도 봐보자.
소스코드(MberListView.jsp) :
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Map" %>
<%
List<Map<String, Object>> resultList = (List<Map<String, Object>>)request.getAttribute("result");
%>
<body>
<form id="mberListFrm" name="mberListFrm" method="post">
<table style="border:1px solid blue; width: 90%;">
<tr>
<td style="border-bottom:1px solid blue;">회원 일련번호</td>
<td style="border-bottom:1px solid blue;">회원 아이디</td>
<td style="border-bottom:1px solid blue;">회원 비밀번호</td>
<td style="border-bottom:1px solid blue;">회원 이름</td>
<td style="border-bottom:1px solid blue;">회원 휴대폰</td>
<td style="border-bottom:1px solid blue;">비고</td>
<td style="border-bottom:1px solid blue;">등록자</td>
<td style="border-bottom:1px solid blue;">등록일시</td>
<td style="border-bottom:1px solid blue;">수정자</td>
<td style="border-bottom:1px solid blue;">수정일시</td>
</tr>
<%
if (resultList != null && resultList.size() > 0) {
for (int i = 0 ; i < resultList.size() ; i++) {
Map<String, Object> result = resultList.get(i);
%>
<tr style="background: lightblue;">
<td><%=result.get("mberSn")%></td>
<td><%=result.get("mberId")%></td>
<td><%=result.get("mberPwd")%></td>
<td><a href="javascript:void(0);" onclick="fnDetailPage('<%=result.get("mberSn")%>')"><%=result.get("mberNm")%></a></td>
<td><%=result.get("moblPhon")%></td>
<td><%=result.get("rm")%></td>
<td><%=result.get("regiSn")%></td>
<td><%=result.get("regiDt")%></td>
<td><%=result.get("updtSn")%></td>
<td><%=result.get("updtDt")%></td>
</tr>
<%
}
} else {
%>
<tr style="background: lightgray;">
<td colspan="10">검색된 데이터가 없습니다.</td>
</tr>
<%
}
%>
<tr>
<td colspan="10">
<div align="right">
<a href="javascript:void(0);" style="text-decoration:none; border:1px solid; background-color: lightgreen;" onclick="fnMainPage('/');">메인으로</a>
</div>
</td>
</tr>
</table>
</form>
</body>
<script type="text/javascript">
function fnMainPage(url) {
location.href = url;
}
function fnDetailPage(mberSn) {
var mberSnInput = document.createElement("input");
mberSnInput.setAttribute("type", "hidden");
mberSnInput.setAttribute("name", "mberSn");
mberSnInput.setAttribute("value", mberSn);
var frm = document.getElementById("mberListFrm");
frm.appendChild(mberSnInput);
frm.action = "/mberDetail.do";
frm.submit();
}
</script>
JSP 개발에서 사용한 소스에서 DB 관련된 내용을 제거하여 재사용했고 Dispatcher Forward로 데이터를 전달받기 때문에 request.getAttribute로 데이터를 가져와 data type cating 하고 loop로 데이터를 출력하였다. Redirect는 안됐었지만 Forward는 보는 것처럼 데이터를 받아 원하는 대로 출력할 수 있다.
5. 회원 상세 (MberDetailServlet.java, mberDetailView.jsp)
특별하게 손댄건 없고... 소스나 한 번 보고 넘어가자...
소스코드(MberDetailServlet.java) :
package com;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MberDetailServlet extends HttpServlet {
private static final long serialVersionUID = 3161530544990290786L;
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// get 방식으로 안보낼 생각임
}
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
Connection dbConn = null;
Map<String, Object> resultMap = null;
try {
String paramMberSn = req.getParameter("mberSn");
Class.forName("org.mariadb.jdbc.Driver");
dbConn = DriverManager.getConnection(
"jdbc:mariadb://127.0.0.1:3306/oldev"
, "olDev"
, "olDev@1234"
);
Statement stmt = dbConn.createStatement();
String sqlStr = "";
sqlStr += "SELECT MBER_SN ";
sqlStr += " , MBER_ID ";
sqlStr += " , MBER_PWD ";
sqlStr += " , MBER_NM ";
sqlStr += " , IFNULL(MBER_MOBLPHON, '') AS MBER_MOBLPHON ";
sqlStr += " , IFNULL(RM, '') AS RM ";
sqlStr += " , REGIST_SN ";
sqlStr += " , REGT_DTTM ";
sqlStr += " , UPDT_SN ";
sqlStr += " , UPDT_DTTM ";
sqlStr += " FROM OD_MBER ";
sqlStr += " WHERE MBER_SN = '"+paramMberSn+"' ";
ResultSet resultSet = stmt.executeQuery(sqlStr);
if (resultSet != null) {
resultMap = new HashMap<String, Object>();
while(resultSet.next()) {
resultMap.put("mberSn", resultSet.getString("MBER_SN"));
resultMap.put("mberId", resultSet.getString("MBER_ID"));
resultMap.put("mberPwd", resultSet.getString("MBER_PWD"));
resultMap.put("mberNm", resultSet.getString("MBER_NM"));
resultMap.put("moblPhon", resultSet.getString("MBER_MOBLPHON"));
resultMap.put("rm", resultSet.getString("RM"));
resultMap.put("regiSn", resultSet.getString("REGIST_SN"));
resultMap.put("regiDt", resultSet.getString("REGT_DTTM"));
resultMap.put("updtSn", resultSet.getString("UPDT_SN"));
resultMap.put("updtDt", resultSet.getString("UPDT_DTTM"));
}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
req.setAttribute("result", resultMap);
RequestDispatcher rd = req.getRequestDispatcher("/mberDetailView.jsp");
rd.forward(req, resp);
}
}
Parameter로 MBER_SN을 전달받아 조회하는 SQL 외엔 전체적으로 MberListServlet과 동일하게 Dispatcher Forward를 사용해 처리 하였다.
소스코드(mberDetailView.jsp) :
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.Map" %>
<%
Map<String, Object> resultMap = (Map<String, Object>)request.getAttribute("result");
%>
<body>
<form id="mberDetailFrm" method="post">
<table style="border:1px solid blue;">
<tr>
<td style="border:1px solid blue;">회원 일련번호</td>
<td style="border:1px solid blue;">회원 아이디</td>
<td style="border:1px solid blue;">회원 비밀번호</td>
<td style="border:1px solid blue;">회원 이름</td>
<td style="border:1px solid blue;">비고</td>
</tr>
<tr>
<td style="border:1px solid blue;"><input type="hidden" id="mberSn" name="mberSn" value="<%=resultMap.get("mberSn")%>"><%=resultMap.get("mberSn")%></td>
<td style="border:1px solid blue;"><%=resultMap.get("mberId")%></td>
<td style="border:1px solid red;"><input type="text" id="mberPwd" name="mberPwd" value="<%=resultMap.get("mberPwd")%>"></td>
<td style="border:1px solid red;"><input type="text" id="mberNm" name="mberNm" value="<%=resultMap.get("mberNm")%>"></td>
<td style="border:1px solid red;"><input type="text" id="rm" name="rm" value="<%=resultMap.get("rm")%>"></td>
</tr>
<tr>
<td colspan="5">
<div align="right">
<a href="javascript:void(0);" style="text-decoration:none; border:1px solid; background-color: lightgreen;" onclick="fnListPage('/mberList.do');">목록</a>
</div>
</td>
</tr>
</table>
</form>
</body>
<script type="text/javascript">
function fnListPage(pageUrl) {
var frm = document.getElementById("mberDetailFrm");
frm.action = pageUrl;
frm.submit();
}
</script>
목록과 마찬가지로 Forward 받은 데이터를 출력한다.
6. 실행
기왕 만든 거 실행시켜 화면을 띄우고 뿌듯함을 느껴보자.
첨부된 소스파일을 실행시켜보면 이미지와 같이 잘 나온다. ㅎㅎ
뭐 쨌든 목표는 채웠고.. 다음은 스크립트릿과 Dom(document)을 jqeury, jstl, el로 바꿔보자 스크립트릿... 사용은 지양하라고 나와있는데 왜일까? 그건 늘 그렇듯 천천히 알아보자...;; ㅎㅎ