++ 모델2 방식 (Model2) ++
- 웹 애플리케이션의 각 기능(클라이언트의 요청 처리, 응답 처리, 비즈니스 로직 처리)을 분리
- 객체 지향 프로그래밍에서 각각의 기능을 모듈화해서 개발
- 각 기능이 서로 분리되어 있어 개발 및 유지보수에 용이
- 각 기능(모듈)의 높은 재사용성
- 디자이너와 개발자의 작업을 분업화 --> 쉽게 개발 가능
Model1
Model2
++ MVC ++
- Model-View-Controller(모델-뷰-컨트롤러)
- 일반적인 프로그램 개발에 사용되는 디자인 패턴을 웹 애플리케이션에 도입한 것
- 웹 애플리케이션을 화면 부분, 요청 처리 부분, 로직 처리 부분으로 나누어 개발하는 방법
- 각 기능이 분리 --> 개발 및 유지보수가 편리, 높은 재사용성
- 디자이너와 개발자의 작업 분업화 가능
- Controller : 서블릿 -> 사용자의 요청 및 흐름 제어 담당
- View : JSP -> 사용자에게 보여줄 화면 담당
- Model : DAO, Service -> 비즈니스 로직 처리
Controller | Model | View |
- 서블릿이 컨트롤러의 역할 - 클라이언트의 요청을 분석 - 요청의 필요한 모델 호출 - Model에서 처리한 결과 출력 위해 JSP를 선택 |
- 비즈니스 로직 수행 (예 : 데이터베이스 연동) - 일반적으로 DAO와 VO 클래스로 이루어짐 |
- JSP가 화면 기능 담당 - Model에서 처리한 결과 화면에 표시 |
** 호출은 무조건 Controller가 받음!!
회원 정보 조회 기능 구현
① 브라우저에서 /mem.do(서블릿)로 요청 ② 서블릿 MemberController가 요청을 받아 MemberDAO의 listMembers() 메서드를 호출 ③ MemberDAO의 listMembers() 메서드에서 SQL문으로 회원 정보를 조회한 후 회원 정보를MemberVO에 설정하여 반환 ④ 다시 MemberController에서는 조회한 회원 정보를 회원 목록창(listMembers.jsp)으로 포워딩 ⑤ 회원 목록창(listMembers.jsp)에서 포워딩한 회원 정보를 목록으로 출력 |
(출처 : 자바 웹을 다루는 기술 (이병승, 길벗))
** request : 클라이언트와 서블릿 간의 저장 객체.
Server폴더에서
context.xml 파일에
<Resource>태그 추가. (</Context> 위에 추가하면 된다.)
(밑에 <Manager .../>태그는 주석처리)
context.xml의 jdbc방식 (url, user, password 등)을 MemberDAO에서 호출해서 사용
데이터베이스는 지난번에 생성했던 membertable 디비의 t_member테이블을 사용할 것이다.
package member.test.mvc;
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, Date joinDate) {
this.id = id;
this.pwd = pwd;
this.name = name;
this.email = email;
this.joinDate = joinDate;
}
...
}
MemberVO.java
MemberVO 클래스 생성
(Getters and Setters 생성)
package member.test.mvc;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class MemberDAO {
private Connection con;
private PreparedStatement pstmt;
private DataSource dataFactory;
public MemberDAO() {
try {
javax.naming.Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:/comp/env");
dataFactory = (DataSource) envContext.lookup("jdbc/membertable");
} catch (Exception e) {
e.printStackTrace();
}
}
public List listMembers() {
List list = new ArrayList();
try {
con = dataFactory.getConnection();
String query = "select * from t_member order by joinDate desc";
System.out.println(query);
pstmt = con.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);
list.add(memberVo);
}
rs.close();
pstmt.close();
con.close();
} catch(Exception e) {
e.printStackTrace();
}
return list;
}
public void addMember(MemberVO m) {
try {
con = 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 = con.prepareStatement(query);
pstmt.setString(1, id);
pstmt.setString(2, pwd);
pstmt.setString(3, name);
pstmt.setString(4, email);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
MemberDAO.java
MemberDAO 클래스 생성.
서버(톰캣)의 context.xml에 미리 데이터베이스 연동 코드를 넣어 놓았기 때문에
url등을 다시 코드로 작성하지 않아도 된다. (connDB()함수도)
package member.test.mvc;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@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();
}
public void destroy() { }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, 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> memberList = memberDAO.listMembers();
request.setAttribute("membersList", memberList);
RequestDispatcher dispatch = request.getRequestDispatcher("/memberMVC/listMembers.jsp");
dispatch.forward(request, response);
}
}
/mem.do (서블릿)
MemberController.java(서블릿 파일)생성
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" import="java.util.*, member.test.mvc.*" isELIgnored="false" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<% request.setCharacterEncoding("utf-8"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>회원정보 출력창</title>
<style type="text/css">
.cls1 { font-size: 40px; text-align: center; }
.cls2 { text-align: center;}
</style>
</head>
<body>
<table align="center" width="100%" border="1">
<tr align="center" bgcolor="lightgreen">
<td width="7%">ID</td>
<td width="7%">PASSWORD</td>
<td width="7%">NAME</td>
<td width="7%">EMAIL</td>
<td width="7%">JOINDATE</td>
</tr>
<c:choose>
<c:when test="${membersList == null}">
<tr align="center">
<td colspan="5" width="7%">
<b>등록된 회원이 없습니다.</b></td>
</tr>
</c:when>
<c:when test="${membersList != null}">
<c:forEach var="mem" items="${membersList}">
<tr align="center">
<td width="7%">${mem.id}</td>
<td width="7%">${mem.pwd}</td>
<td width="7%">${mem.name}</td>
<td width="7%">${mem.email}</td>
<td width="7%">${mem.joinDate}</td>
</tr></c:forEach></c:when></c:choose>
</table>
<a href="#"><p class="cls2">회원가입하기</p></a>
</body>
</html>
listMembers.jsp 생성
데이터베이스와 연동한
회원정보출력창
① 브라우저에서 /mem.do(서블릿)로 요청 ② 서블릿 MemberController가 요청을 받아 MemberDAO의 listMembers() 메서드를 호출 ③ MemberDAO의 listMembers() 메서드에서 SQL문으로 회원 정보를 조회한 후 회원 정보를MemberVO에 설정하여 반환 ④ 다시 MemberController에서는 조회한 회원 정보를 회원 목록창(listMembers.jsp)으로 포워딩 ⑤ 회원 목록창(listMembers.jsp)에서 포워딩한 회원 정보를 목록으로 출력 |
회원 정보 추가 기능 구현
Command Pattern (커맨드 패턴) |
- 브라우저가 URL 패턴을 이용해 컨트롤러에게 수행 작업을 요청 - Controller는 HttpServletRequest의 getPathInfo() 메소드를 통해 URL 패턴에서 요청명을 받아 작업을 수행 (URL패턴 요청 형식 : http://localhost:3306/projsp02/member/listMembers.do) -> /member : 회원 기능, /listMembers.do : 조회기능 |
① 회원 가입창에서 회원 정보를 입력하고 URL 패턴을 /member/addMember.do로 서버에 요청 ② MemberController에서 HttpServletRequest의 getPathInfo() 메서드를 이용해 요청명인 /addMember.do를 받아옴 ③ 요청명에 대해 MemberDAO의 addMember() 메서드를 호출 ④ addMember() 메서드에서 SQL문으로 테이블에 회원 정보를 추가 |
database와
MemberDAO.java,
MemberVO.java
는 위 예제와 동일
package member.test.mvcCommand;
...
@WebServlet("/memAdd/*")
public class MemberController extends HttpServlet {
private static final long serialVersionUID = 1L;
MemberDAO memberDAO; // 필드
public void init(ServletConfig config) throws ServletException {
memberDAO = new MemberDAO();
System.out.println("init 호출");
}
public void destroy() { System.out.println("destroy 호출"); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
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();
System.out.println("action : " + action);
if(action == null || action.equals("/listMembers.do")) {
List<MemberVO> memberList = memberDAO.listMembers();
request.setAttribute("memberList", memberList);
nextPage = "/memberMVCCommand/listMembers.jsp";
} else if (action.equals("/addMember.do")) {
String id = request.getParameter("id");
String pwd = request.getParameter("pwd");
String name = request.getParameter("name");
String email = request.getParameter("email");
MemberVO memberVO = new MemberVO(id, pwd, name, email);
memberDAO.addMember(memberVO);
nextPage = "/memAdd/listMembers.do";
} else if (action.equals("/memberForm.do")) {
nextPage = "/memberMVCCommand/memberForm.jsp";
} else {
List<MemberVO> memberList = memberDAO.listMembers();
request.setAttribute("memberList", memberList);
nextPage = "/memberMVCCommand/listMembers.jsp";
}
RequestDispatcher dispatch = request.getRequestDispatcher(nextPage);
dispatch.forward(request, response);
}
}
MemberController.java
@WebServlet("/memAdd/*") 서블릿 수정
특히 doHandle(...)함수
action에 따라 실행되는 창이 달라지도록 한 것이다.
...
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
...
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
...
<a href="${contextPath}/memAdd/memberForm.do"><p class="cls2">회원가입하기</p></a>
</body>
</html>
listMembers.jsp
상단에 <c:set var="contextPath" value="${pageContext.request.contextPath}" /> 구문 추가,
회원가입하기 텍스트링크(하이퍼링크href)에 href="${contextPath}/memAdd/memberForm.do" 추가
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isELIgnored="false" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>회원가입창</title>
<style type="text/css">
.cls1 { font-size: 40px; text-align: center; }
.cls2 { text-align: center; }
</style>
</head>
<body>
<form action="${contextPath}/memAdd/addMember.do" method="post" >
<h1 style="text-align: center">회원가입창</h1>
<table align="center">
<tr>
<td width="200"><p align="right">아이디</p></td>
<td width="400"><input type="text" name="id"></td>
</tr>
<tr>
<td width="200"><p align="right">비밀번호</p></td>
<td width="400"><input type="password" name="pwd"></td>
</tr>
<tr>
<td width="200"><p align="right">이름</p> </td>
<td width="400"><input type="text" name="name"></td>
</tr>
<tr>
<td width="200"><p align="right">이메일</p></td>
<td width="400"><input type="text" name="email"></td>
</tr>
<tr>
<td width="200"></td>
<td width="80"><input type="submit" value="가입하기">
<input type="reset" value="다시입력"></td>
</tr>
</table>
</form>
</body>
</html>
memberForm.jsp 추가 (회원가입창)
--결과--
listMembers.jsp파일을 서버로 실행시키면,
이렇게 초기화면이 나온다.
회원가입하기를 누루고, 정보를 입력
가입하기
회원가입창에서 입력한 정보가
데이터베이스에 추가된 것을 확인할 수 있다.
데이터베이스 테이블의 데이터에서도 확인 가능하다.
console창
회원 정보 수정과 삭제 기능 구현
수정 | 삭제 |
① 회원 정보 수정창에서 회원 정보를 수정 -> /member/modMember.do로 컨트롤러에 요청 ② 컨트롤러는 전송된 회원 수정 정보를 가져온 후 테이블에서 수정 ③ 수정을 마친 후 컨트롤러는 다시 회원 list를 표시 |
① 회원 목록창에서 삭제 요청 -> /member/delMember.do와 회원 ID를 컨트롤러로 전달 ② 컨트롤러는 HttpServletRequest의 getPathInfo() 메서드를 이용해 요청명 얻음 ③ 회원 ID를 SQL문으로 전달해 삭제 |
데이터베이스와
MemberVO.java는 동일하다.
memberForm.jsp에서는 action의 경로만 수정해주면 된다.
if(action == null || action.equals("/listMembers.do")) {
List<MemberVO> memberList = memberDAO.listMembers();
request.setAttribute("memberList", memberList);
nextPage = "/memberMVCDnM/listMembers.jsp";
}
...
else if (action.equals("/modMemberForm.do")) {
String id = request.getParameter("id");
MemberVO memInfo = memberDAO.findMember(id);
request.setAttribute("memInfo", memInfo);
nextPage = "/memberMVCDnM/modMemberForm.jsp";
} else if (action.equals("/modMember.do")) {
String id = request.getParameter("id");
String pwd = request.getParameter("pwd");
String name = request.getParameter("name");
String email = request.getParameter("email");
MemberVO memberVO = new MemberVO(id, pwd, name, email);
memberDAO.modMember(memberVO);
request.setAttribute("msg", "modified");
nextPage = "/memDnM/listMembers.do";
} else if (action.equals("/delMember.do")) {
String id = request.getParameter("id");
memberDAO.delMember(id);
request.setAttribute("msg", "deleted");
nextPage = "/memDnM/listMembers.do";
}
else {
List<MemberVO> memberList = memberDAO.listMembers();
request.setAttribute("memberList", memberList);
nextPage = "/memberMVCDnM/listMembers.jsp";
}
MemberController.java 서블릿파일의
서블릿 이름을 /memDnM으로 변경해주었으며,
doHandle()함수의 if-else문에 수정과 삭제를 추가해주었다.
public MemberVO findMember(String _id) {
MemberVO memberInfo = null;
try {
con = dataFactory.getConnection();
String query = "select * from t_member where id=?";
pstmt = con.prepareStatement(query);
pstmt.setString(1, _id);
System.out.println(query);
ResultSet rs = pstmt.executeQuery();
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");
memberInfo = new MemberVO(id, pwd, name, email, joinDate);
pstmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
return memberInfo;
}
public void modMember(MemberVO m) {
String id = m.getId();
String pwd = m.getPwd();
String name = m.getName();
String email = m.getEmail();
try {
con = dataFactory.getConnection();
String query = "update t_member set pwd=?,name=?,email=? where id=?";
System.out.println(query);
pstmt = con.prepareStatement(query);
pstmt.setString(1, pwd);
pstmt.setString(2, name);
pstmt.setString(3, email);
pstmt.setString(4, id);
pstmt.executeUpdate();
pstmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void delMember(String id) {
try {
con = dataFactory.getConnection();
String query = "delete from t_member where id=?";
System.out.println(query);
pstmt = con.prepareStatement(query);
pstmt.setString(1, id);
pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
}
MemberDAO.java 파일에서는
findMember(), modMember(), delMember() 함수를 추가
...
<head>
<c:choose>
<c:when test='${msg == "addMember"}'>
<script>
window.onload = function() {
alert("회원을 등록했습니다. ");
}
</script>
</c:when>
<c:when test='${msg == "modified"}'>
<script>
window.onload = function() {
alert("회원 정보를 수정했습니다. ");
}
</script>
</c:when>
<c:when test='${msg == "deleted"}'>
<script>
window.onload = function() {
alert("회원 정보를 삭제했습니다. ");
}
</script>
</c:when>
</c:choose>
...
<td width="7%">수정</td>
<td width="7%">삭제</td>
...
<td width="7%"><a href="${contextPath}/memDnM/modMemberForm.do?id=${mem.id}">수정</a></td>
<td width="7%"><a href="${contextPath}/memDnM/delMember.do?id=${mem.id}">삭제</a></td>
...
<a href="${contextPath}/memDnM/memberForm.do"><p class="cls2">회원가입하기</p></a>
...
listMembers.jsp파일에서는,
각 테이블에 수정, 삭제 열을 추가하고,
회원정보 등록/수정/삭제 여부에 따라 alert창으로 알려주는 구문을 추가.
경로 설정도 잊지 말아야한다.
위의 예제들에서 추가 파일이 필요하다.
바로 회원정보를 수정하는 창이다.
...
<h1 class="cls1">회원 정보 수정</h1>
<form action="${contextPath}/memDnM/modMember.do?id=${memInfo.id}" method="post" >
<table align="center">
<tr>
<td width="200"><p align="right">아이디</p></td>
<td width="350"><input type="text" name="id" value="${memInfo.id}" disabled></td>
</tr>
...
<td width="80"><input type="submit" value="수정하기">
<input type="reset" value="다시입력"></td>
...
modMemberForm.jsp
회원가입창과 동일하지만, 아이디는 disabled로 설정하여 수정하지 못하도록 설정.
그리고 input태그에 value="${memInfo.id}와 같이, 기존 회원의 정보를 input박스에 출력되도록 했다.
--결과--
처음 데이터베이스 테이블 데이터
처음 회원 가입창
정보를 입력하고 가입하기
입력한 회원정보가 리스트에 출력되었다. (첫번째 줄)
NAME 김오늘의 수정을 누르면
수정할 수 있는 "회원 정보 수정"창이 뜬다.
아이디는 변경 불가이다.
이름과 이메일을 변경해보겠다.
이렇게 alert창이 떠서 수정되었음을 알려주고,
회원 정보 리스트에서 수정된 정보를 보여준다.
↓
데이터베이스에서도 변경된 것을 확인할 수 있다.
다시 회원정보 출력창으로 돌아와,
NAME 김내일의 삭제 버튼을 누르면
alert창으로 삭제되었음을 알려주고,
회원정보가 삭제된다.
회원정보 출력창과 데이터베이스 데이터에서 삭제된 김내일의 정보
** JSP에서 .do는 가상경로이다. (.abc와 같이 다른 확장자로 해도 전혀 상관없다.)
다른 서블릿과 URL 충돌을 막기 위해 이런식으로 확장자를 사용하게 되었다고 한다.
'JSP 웹프로그래밍' 카테고리의 다른 글
JSP #12 : Model2 방식 - 게시판(230111) (0) | 2023.01.16 |
---|---|
JSP #10 : 커스텀 태그(230109)2_1 (0) | 2023.01.09 |
JSP #9 : database와 연동 (230106) (0) | 2023.01.06 |
JSP : EL 자료형, 연산자, 실습(230105)Expression Language (0) | 2023.01.05 |
JSP #8 : 커스텀 태그 & EL & JSTL (230105)2 (0) | 2023.01.05 |
댓글