모델 1 방식
JSP를 하지는 않았지만, JSP를 이용한 방식이 모델 1 방식이다. DB연동 같은 작업과 그 결과를 나타내주는 작업을 동일한 JSP에서 수행한다. 즉, 모든 클라리언트의 요청과 비지니스 로직을 JSP가 담당하는 구조이다.
기능 구현이 쉽고 편리하다는 장점이 있지만, 복잡해지면 유지보수에 문제가 발생한다.
이 모델 1 방식의 단점을 보완한 것이 모델 2 방식이다. 흔히 알고있는 MVC패턴에 대해 시작할 것이다.
모델 2 방식
웹 애플리케이션의 각 기능(클라이언트 요청, 응답, 비지니스 로직 처리)을 분리해서 구현한다. 각각의 기능을 모듈화 한다라고 이해하면 된다.
즉, 기능이 분리되어 있어 개발 및 유지보수가 쉽고 재사용성이 높다.
MVC 디자인 패턴
Model-View-Controller의 개념으로 화면 부분, 요청 처리, 로직 처리 3가지를 나누어 개발하는 방식이다.
위 그림에서 화면기능(view), 요청처리(Contriller), 로직처리(Model) 의 구조로 이해하면 된다.
Controller: 서블릿이 이 역할을 담당, 클라이언트의 요청을 분석하고 요청에 대해 필요한 모델을 호출, 모델에서 처리한 결과를 보여주기 위해 JSP를 선택
Model: DB연동과 같은 비지니스 로직을 수행, DAO와 VO클래스로 이루어져 있음
View: JSP가 화면기능을 담당하며 Model에서 처리한 결과를 화면에 표시
*이 카테고리에서 JSP를 크게 다루지 않을 것이다. Servlet에서 부족한 내용(쿠키, 세션, API등)은 추후에 추가할 것이다.*
MVC를 이용한 회원 관리
MVC 방싣으로 브라우저의 요청은 Servlet이 담당하고 비지니스 처리는 Model, 화면은 JSP가 맡는 방식으로 다시 구현한다. 이전의 코드를 활용하여 개발원리를 알아보자. 구조는 아래와 같다.
이제 이클립스 작업을 해보자. JSP에 대한 설명은 생략한다.
회원 정보 조회하기
이전에 진행했던 방식으로 조회하는 기능을 보여준다. 프로젝트의 구조는 아래와 같다.
lib폴더에 jar이 많은데 우리가 사용하지 않았던 jar은 JSP와 관련된 라이브러리이다. commons- 는 jsp 파일 업로드에 관련한 것이고 해당 이름을 치면 웹 사이트에서 쉽게 다운받을 수 있다. 추가하고 3개의 클래스와 1개의 JSP파일을 위의 경로에 맞게 추가해주자. JSP 코드는 아래와 같다.
listMembers.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
isELIgnored="false"
%>
<%
request.setCharacterEncoding("UTF-8");
%>
<html>
<head>
<meta charset="UTF-8">
<title>회원 정보 출력창</title>
<style>
.cls1 {
font-size:40px;
text-align:center;
}
.cls2 {
font-size:20px;
text-align:center;
}
</style>
</head>
<body>
<p class="cls1">회원정보</p>
<table align="center" border="1" >
<tr align="center" bgcolor="lightgreen">
<td width="7%" ><b>아이디</b></td>
<td width="7%" ><b>비밀번호</b></td>
<td width="7%" ><b>이름</b></td>
<td width="7%"><b>이메일</b></td>
<td width="7%" ><b>가입일</b></td>
</tr>
<c:choose>
<c:when test="${membersList==null}" >
<tr>
<td colspan=5>
<b>등록된 회원이 없습니다.</b>
</td>
</tr>
</c:when>
<c:when test="${membersList != null }" >
<c:forEach var="mem" items="${membersList}" >
<tr align="center">
<td>${mem.joinDate}</td>
</tr>
</c:forEach>
</c:when>
</c:choose>
</table>
<a href="#"><p class="cls2">회원 가입하기</p></a>
</body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
MemberController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
package sec01xex01;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
/**
* Servlet implementation class MemberController
*/
@WebServlet("/mem.do")
public class MemberController extends HttpServlet {
private static final long serialVersionUID = 1L;
MemberDAO memberDAO;
public void init(ServletConfig config) throws ServletException {
memberDAO = new MemberDAO(); //객체 초기화
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doHandle(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doHandle(request, response);
}
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
List<MemberVO> membersList = memberDAO.listMembers(); //요청에 대해 외원 정보를 조회\
System.out.println(membersList);
request.setAttribute("membersList", membersList); //조회한 정보를 request에 바인딩
RequestDispatcher dispatch = request.getRequestDispatcher("/test01/listMembers.jsp");
dispatch.forward(request, response);
//컨트롤러에서 표시하고자 하는 JSP로 포워딩
//포워딩, 바인딩은 Servlet에서 추후에 설명
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
이 코드는 이전의 실습해서 계속 사용했던 코드와 비슷하다. 컨트롤러는 MemberDAO객체르 초기화하고 MemberDAO의 listMember() 메서드를 호출하여 회원 정보를 ArrayList로 반환한다. 이 후 RequestDispatch 클래스로 JSP로 포워딩한다.
MemberDAO.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
package sec01xex01;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class MemberDAO {
private DataSource dataFactory;
private Connection conn;
private PreparedStatement pstmt;
public MemberDAO() {
try {
Context ctx = new InitialContext();
} catch (Exception e) {
e.printStackTrace();
}
}
public List<MemberVO> listMembers() {
List<MemberVO> membersList = new ArrayList();
try {
conn = dataFactory.getConnection();
String query = "select * from t_member order by joinDate desc";
System.out.println(query);
pstmt = conn.prepareStatement(query);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String id = rs.getString("id");
String pwd = rs.getString("pwd");
String name = rs.getString("name");
String email = rs.getString("email");
Date joinDate = rs.getDate("joinDate");
MemberVO memberVO = new MemberVO(id, pwd, name, email, joinDate);
membersList.add(memberVO);
}
} catch (SQLException e) {
e.printStackTrace();
}
return membersList;
}
public void addMember(MemberVO m) {
try {
conn = dataFactory.getConnection();
String id = m.getId();
String pwd = m.getPwd();
String name = m.getName();
String email = m.getEmail();
String query = "INSERT INTO t_member(id, pwd, name, email)" + " VALUES(?, ? ,? ,?)";
System.out.println(query);
pstmt = conn.prepareStatement(query);
pstmt.setString(1, id);
pstmt.setString(2, pwd);
pstmt.setString(3, name);
pstmt.setString(4, email);
pstmt.executeUpdate(); //SQL문 실행
} catch (SQLException e) {
e.printStackTrace();
}
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
MemberDAO 클래스도 이전에 했던것과 비슷하다. DB연동을 위해 DB의 쿼리문을 작성하여 실행하는 역할을 한다고 이해하고 있다. listMembers() 메서드 호출시 SQL문을 이용해 회원 정보를 조회한 후 그 결과를 ArrayList로 반환한다.
MemberVO.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
package sec01xex01;
import java.sql.Date;
public class MemberVO {
private String id;
private String pwd;
private String name;
private String email;
private Date joinDate;
public MemberVO() {
System.out.println("MemberVO.........");
}
public MemberVO(String id, String pwd, String name, String email) {
super();
System.out.println("????????");
this.id = id;
this.pwd = pwd;
this.name = name;
this.email = email;
}
public MemberVO(String id, String pwd, String name, String email, Date joinDate) {
super();
System.out.println("????????");
this.id = id;
this.pwd = pwd;
this.name = name;
this.email = email;
this.joinDate = joinDate;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
코드를 복사하여 실행하는것도 도움이 되겠지만, 컨트롤러 클래스와 DAO클래스는 한번 작성해보면서 이해하면 어떻게 프로그램이 동작하는지 체감할 수 있을것이다. 필자 역시 여러 오류가 생기면서 println()출력을 사용하여 어디서 문제가 발생했는지 찾을 수 있었다. 코드를 짜보면서 오류가 발생한다면 흐름을 추적하고 코드의 역할을 확실히 이해할 수 있을것이다.
이제 서버를 키고 localhost:8090/MVC/mem.do 로 접속하면 이전에 우리가 사용했던 DB의 목록을 확인할 수 있다.
회원 정보 추가
조회한 결과를 보면서 '회원 가입하기' 버튼은 아직 동작하지 않음을 알 수 있다. 이제 회원 정보를 추가해보자.
순서는 컨트롤러가 브라우저로부터 어떤 요청(여기서는 회원 가입)인지 확인해야 한 다음, 그 요청에 해당하는 모델을 선택해 작업을 요청하는 순서이다. 이러한 방법을 커맨드 패턴이라고도 한다.
한마디로 URL 패턴을 이용해 컨트롤러에게 수행 작업을 요청하는 방법이다. 여기서는 아래와 같은 URL을 사용할 것이다. 여러분이 인터넷을 하면서 많이 보았을 것이다.
localhost:8090/MVC/member/listmembers.do
/member: 첫 번째 단계의 요청은 회원 기능 /listmembers.do: 회원 기능중 조회기능
여기서 위 코드를 수정하여 만들어보자. JSP에 대한 설명은 넘어간다. MemberController.java만 수정하고 jsp 파일을 하나 추가한다. 수정된 java 클래스는 아래와 같다. dohandle() 메서드를 수정하고 @WebServlet("/member/*") 로 수정한다.
String action 값을 기준으로 어떤 요청을 할지 결정한다. memberForm.do 페이지가 열리고 이 페이지에서 addmember를 action값으로 보내면 회원 정보가 추가된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String nextPage = null;
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String action = request.getPathInfo(); // URL에서 요청명을 가져온다.
System.out.println("action : " + action);
System.out.println("최초 요청? 회원 조회??,,,,," + action);
List<MemberVO> membersList = memberDAO.listMembers(); //요청에 대해 외원 정보를 조회\
System.out.println(membersList);
request.setAttribute("membersList", membersList); //조회한 정보를 request에 바인딩
nextPage = "/test01/listMembers.jsp";
}
System.out.println("회원 정보를 추가하자,,,,," + action);
String id = request.getParameter("id");
String pd = request.getParameter("pwd");
String name = request.getParameter("name");
String email = request.getParameter("email");
MemberVO memberVO = new MemberVO(id,pd,name,email);
memberDAO.addMember(memberVO); //DAO의 addmember로 DB에 저장
}
System.out.println("회원 가입창으로 이동하자,,,,," + action);
}
else {
System.out.println("다른 입력이 들어옴..." + action);
List<MemberVO> membersList = memberDAO.listMembers();
request.setAttribute("membersList", membersList);
nextPage = "/test01/listMembers.jsp";
}//그 외 다른 action 값은 회원 목록을 출력
System.out.println("조건문 다 통과....." + action);
RequestDispatcher dispatch = request.getRequestDispatcher(nextPage); //nextPage에 따른 요청명으로 서블릿에 요청
dispatch.forward(request, response);
//컨트롤러에서 표시하고자 하는 JSP로 포워딩
//포워딩, 바인딩은 Servlet에서 추후에 설명
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
action에 따라 조건문으로 어떤 요청을 처리하는지 나타낸다.
memberForm.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
isELIgnored="false" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 가입창</title>
<body>
<h1 style="text-align:center">회원 가입창</h1>
<table align="center">
<tr>
<td width="200"><p align="right">아이디</td>
<td width="400"><input type="text" name="id"></td>
</tr>
<tr>
<td width="200"><p align="right">비밀번호</td>
<td width="400"><input type="password" name="pwd"></td>
</tr>
<tr>
<td width="200"><p align="right">이름</td>
<td width="400"><p><input type="text" name="name"></td>
</tr>
<tr>
<td width="200"><p align="right">이메일</td>
<td width="400"><p><input type="text" name="email"></td>
</tr>
<tr>
<td width="200"><p> </p></td>
<td width="400">
<input type="submit" value="가입하기">
<input type="reset" value="다시입력">
</td>
</tr>
</table>
</form>
</body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
그리고 listMembers.jsp 의 마지막 <a> 태그와 상단에 <c>태그를 추가한다.
1
2
3
4
5
6
7
|
...<중략>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<%
request.setCharacterEncoding("UTF-8");
%>
...<중략>
|
결과는 아래와 같다.
먼저 localhost:8090/MVC/member/listMember.do 로 요청하면 조회 화면이 뜨고, 회원 가입하기를 눌러보자.
form에 내용을 입력하고 가입하기를 누르면 새로 추가된 회원이 아래와 같이 나타난다.
다음 포스트에 이제 회원 정보 수정 및 삭제기능을 구현해보자.
Refernce
자바 웹을 다루는 기술<길벗>
'Servlet JSP MVC Spring' 카테고리의 다른 글
[MVC] 정보 수정 및 삭제 (0) | 2020.03.05 |
---|---|
[Servlet] 포워드(dispatch), 바인딩 (0) | 2020.03.03 |
[Servlet]커넥션풀을 이용한 회원 정보 CRUD(생성,조회,수정,삭제) (1) | 2020.02.23 |
[Servlet] 서블릿과 데이터베이스 연동 조회: PrepareStatement (0) | 2020.02.21 |
[Servlet] 웹 브라우저에서 서블릿 전송 및 예제들 (0) | 2020.02.12 |