오늘은 따로 진도는 안 나갔고 어제 배운 모델 2 방식 실습을 했다.
MVC 패턴을 적용하여 회원 정보 추가, 조회, 수정, 삭제 등의 간단한 CRUD 기능을 실습했다.
전체 구현 흐름
전체 구현 흐름은 다음과 같다.
- 브라우저에서
localhost:8080/mvcEx/member/…주소로 요청 - 서블릿 MemberController가 요청을 받아 그 요청에 해당하는 모델을 선택하여 작업을 요청 -> 커맨드 패턴: 브라우저가 URL 패턴을 이용해 컨트롤러에게 수행 작업을 요청하는 방법
- 컨트롤러는
getPathInfo()메서드를 사용하여 URL 패턴에서 요청명을 받아와 각 요청에 맞는 작업을 수행 - 각 요청에 따른 nextPage로 포워딩
컨트롤러의 작업을 좀 더 구체적으로 살펴보면, 우선 MemberController의 doHandle() 메서드 안에서 request.getPathInfo() 메서드를 실행해 String 변수 action에 담는다.
그리고 action 값에 따른 분기를 한다.
1. 최초 요청이거나(`action == null`), action 값이 `/listMembers.do`인 경우
1) MemberVO 리스트를 만들고 전체 회원들을 담는다.
2) /listMembers.jsp로 포워딩한다.
3) 회원 정보 출력창이 브라우저에 출력된다.
2. action 값이 `/addMember.do`인 경우
1) 요청 파라미터로부터 속성 정보를 받아 새로운 MemberVO 객체를 만든다.
2) `memberDAO.addMember()` 메서드를 호출해 회원을 추가해준다.
3) `/member/listMembers.do`로 포워딩한다.
4) 1번이 실행된다.
3. action 값이 /memberForm.do인 경우
1) 요청 파라미터로부터 id 정보를 받아 해당 id의 회원을 찾는다.
2) /modMemberForm.jsp로 포워딩한다.
3) 회원 정보 수정창이 브라우저에 출력된다.
4. action 값이 `/modMember.do`인 경우
1) 요청 파라미터로부터 속성 정보를 받아 새로운 MemberVO 객체를 만든다.
2) memberDAO.modMember() 메서드를 호출해 회원 정보를 수정해준다.
3) /member/listMembers.do로 포워딩한다.
4) 1번이 실행된다.
5. action 값이 /delMember.do인 경우
1) 요청 파라미터로부터 id 정보를 받아 `memberDAO.delMember(id)` 메서드를 호출해 회원을 삭제해준다.
2) /member/listMembers.do로 포워딩한다.
3) 1번이 실행된다.
6. 그 외의 action 값인 경우
1) 1번이 실행된다.
소스 코드
소스 코드는 다음과 같다.
MemberController.java
package mvcEx;
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("/member/*") // member라는 경로가 포함된 request는 다 이 MemberController가 받음
public class MemberController extends HttpServlet {
private static final long serialVersionUID = 1L;
MemberDAO memberDAO; // MemberDAO 객체 초기화
@Override
public void init(ServletConfig config) throws ServletException {
memberDAO = new MemberDAO();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
protected 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")) { // 최초 요청이거나 action 값이 /listMembers.do면 회원 목록을 출력
List<MemberVO> membersList = memberDAO.listMembers();
request.setAttribute("membersList", membersList);
nextPage = "/listMembers.jsp"; // listMembers.jsp로 포워딩
} else if (action.equals("/addMember.do")) { // action값이 /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 = "/member/listMembers.do"; // 회원 등록 후 다시 회원 목록을 출력
} else if (action.equals("/memberForm.do")) { // action 값이 /memberForm.do면 회원 가입창을 화면에 출력
nextPage = "/memberForm.jsp"; // memberForm.jsp로 포워딩
} else if (action.equals("/modMemberForm.do")) { // 수정 버튼 눌렀을 때 실행됨
String id = request.getParameter("id");
MemberVO memInfo = memberDAO.findMember(id);
request.setAttribute("memInfo", memInfo);
nextPage = "/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");
System.out.println(id + pwd + name + email);
MemberVO memberVO = new MemberVO(id, pwd, name, email);
memberDAO.modMember(memberVO);
request.setAttribute("msg", "modified");
nextPage = "/member/listMembers.do";
} else if (action.equals("/delMember.do")) {
String id = request.getParameter("id");
memberDAO.delMember(id);
request.setAttribute("msg", "deleted");
nextPage = "/member/listMembers.do";
} else { // 그 외 다른 action 값은 회원 목록을 출력
List<MemberVO> membersList = memberDAO.listMembers();
request.setAttribute("membersList", membersList);
nextPage = "/listMembers.jsp";
}
RequestDispatcher dispatch = request.getRequestDispatcher(nextPage); // nextPage에 지정한 요청명대로 다시 서블릿에 요청
dispatch.forward(request, response);
}
}
MemberDAO.java
package mvcEx;
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 conn;
private PreparedStatement pstmt;
private DataSource dataFactory;
public MemberDAO() {
// 톰캣이 만들어 놓은 커넥션 풀에 접근하기 위한 방법
try {
Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:/comp/env");
dataFactory = (DataSource) envContext.lookup("jdbc/oracle");
} catch (Exception e) {
e.printStackTrace();
}
}
public List<MemberVO> listMembers(){
List<MemberVO> membersList = new ArrayList<MemberVO>();
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 vo = new MemberVO(id, pwd, name, email, joinDate);
membersList.add(vo);
}
rs.close();
pstmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return membersList; // 조회한 레코드의 개수만큼 ArrayList를 반환
}
public void addMember(MemberVO memberVO) {
try {
conn = dataFactory.getConnection();
String id = memberVO.getId();
String pwd = memberVO.getPwd();
String name = memberVO.getName();
String email = memberVO.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();
pstmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void delMember(String id) {
try {
conn = dataFactory.getConnection();
String query = "delete from t_member where id = ?";
System.out.println(query);
pstmt = conn.prepareStatement(query);
pstmt.setString(1, id);
pstmt.executeUpdate();
pstmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public MemberVO findMember(String _id) {
MemberVO memInfo = null;
try {
conn = dataFactory.getConnection();
String query = "select * from t_member where id=?";
pstmt = conn.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");
memInfo = new MemberVO(id, pwd, name, email, joinDate);
pstmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return memInfo;
}
public void modMember(MemberVO memberVO) {
String id = memberVO.getId();
String pwd = memberVO.getPwd();
String name = memberVO.getName();
String email = memberVO.getEmail();
try {
conn = dataFactory.getConnection();
String query = "update t_member set pwd=?, name=?, email=? where id=?";
System.out.println(query);
pstmt = conn.prepareStatement(query);
pstmt.setString(1, pwd);
pstmt.setString(2, name);
pstmt.setString(3, email);
pstmt.setString(4, id);
pstmt.executeUpdate();
pstmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
MemberVO.java
package mvcEx;
import java.sql.Date;
// Member Value Object의 줄임말
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();
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();
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;
}
}
listMembers.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
isELIgnored="false"
%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<%
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>
<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>
</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>
<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.id }</td>
<td>${mem.pwd }</td>
<td>${mem.name}</td>
<td>${mem.email }</td>
<td>${mem.joinDate}</td>
<td><a href="${contextPath}/member/modMemberForm.do?id=${mem.id }">수정</a></td>
<td><a href="${contextPath}/member/delMember.do?id=${mem.id }">삭제</a></td>
</tr>
</c:forEach>
</c:when>
</c:choose>
</table>
<a href="${contextPath}/member/memberForm.do"><p class="cls2">회원 가입하기</p></a>
</body>
</html>
memberForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
isELIgnored="false" %>
<%@ taglib prefix="fmt" 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>
<body>
<form method="post" action="${contextPath}/member/addMember.do">
<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>
modMemberForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
isELIgnored="false" %>
<%@ taglib prefix="fmt" 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}" />
<%
request.setCharacterEncoding("UTF-8");
%>
<head>
<meta charset="UTF-8">
<title>회원 정보 수정창</title>
<style>
.cls1 {
font-size:40px;
text-align:center;
}
</style>
</head>
<body>
<h1 class="cls1">회원 정보 수정창</h1>
<form method="post" action="${contextPath}/member/modMember.do?id=${memInfo.id}">
<table align="center" >
<tr>
<td width="200"><p align="right" >아이디</td>
<td width="400"><input type="text" name="id" value="${memInfo.id}" disabled ></td>
</tr>
<tr>
<td width="200"><p align="right" >비밀번호</td>
<td width="400"><input type="password" name="pwd" value="${memInfo.pwd}" >
</td>
</tr>
<tr>
<td width="200"><p align="right" >이름</td>
<td width="400"><input type="text" name="name" value="${memInfo.name}" ></td>
</tr>
<tr>
<td width="200"><p align="right" >이메일</td>
<td width="400"><input type="text" name="email" value="${memInfo.email}" ></td>
</tr>
<tr>
<td width="200"><p align="right" >가입일</td>
<td width="400"><input type="text" name="joinDate" value="${memInfo.joinDate }" disabled ></td>
</tr>
<tr align="center" >
<td colspan="2" width="400"><input type="submit" value="수정하기" >
<input type="reset" value="다시입력" > </td>
</tr>
</table>
</form>
</html>
실행 결과
localhost:8080/mvcEx/member/listMembers.do 요청했을 때 회원 정보 출력창이 뜬다.

여기서 회원 가입하기 텍스트를 클릭하면

이렇게 회원 가입창이 뜬다.

회원 정보를 대충 입력하고 가입하기 버튼을 클릭하면

이렇게 회원 정보 출력창에 가입한 회원이 추가되어 출력된다.
이번엔 수정을 해보겠다. 수정 텍스트를 클릭하면

이렇게 회원 정보 수정창이 뜬다.
수정을 하고 수정하기 버튼을 누르면

회원 정보를 수정했다는 alert 창이 먼저 뜨고 회원 정보 출력창이 뜬다.
회원 정보가 수정된 것을 확인할 수 있다.
마지막으로 삭제 텍스트를 클릭하면

삭제했다는 alert 창이 먼저 뜨고 회원 정보 출력창이 뜬다.
방금 만든 회원이 삭제된 것을 확인할 수 있다.
❕느낀점
오늘을 끝으로 서블릿과 JSP 기초를 마무리하게 되었다. 처음엔 서블릿으로 시작했다가 점차 기술이 발전하면서 JSP까지 오게 되었고, 마지막으로는 MVC 패턴을 사용한 개발까지 배울 수 있어 뭔가 자바 웹 애플리케이션 프로그래밍의 진화를 보는 것 같았다.
앞으로는 진화의 끝판왕(?) 스프링과 스프링 부트를 배우게 된다. 지금까지 배운 서블릿과 JSP 내용을 잘 익히고 스프링 개념도 잘 습득해서 스프링으로 개발을 할 수 있는 멋진 개발자가 되도록 노력해야겠다.
'Java' 카테고리의 다른 글
| [TIL-260312] Servlet & JSP 입문: JSP 내장 객체, 액션 태그, 모델2 (0) | 2026.03.13 |
|---|---|
| [TIL-260311] Servlet & JSP 입문: 커넥션 풀, JSP 정의, JSP 스크립트 (1) | 2026.03.12 |
| [TIL-260310] Servlet & JSP 입문: 서블릿의 응답 처리, DB 연동 (0) | 2026.03.10 |
| [TIL-260309] Servlet & JSP 입문: JSP 실습, Servlet 기초 (0) | 2026.03.10 |
| [TIL-260306] Servlet & JSP 입문: 자바와 웹, 웹 애플리케이션, HTTP (0) | 2026.03.08 |
