MVC2

현서·2025년 6월 12일
1

자바

목록 보기
30/32

MVC2

웹 애플리케이션에서 요청 처리와 화면 출력을 명확히 분리한 구조로, 서블릿이 컨트롤러 역할을 하여 클라이언트의 요청을 받아 비즈니스 로직을 처리한 뒤, 데이터를 JSP에 전달하고 JSP는 오직 결과 화면만 출력하는 방식

  • 로직과 화면이 분리되어 코드의 재사용성과 유지보수성이 향상되며, 실제 프로젝트와 프레임워크(Spring)에서도 널리 채택되는 구조

클라이언트 > 컨트롤러 서블릿 > DAO/DTO > 결과 저장 > JSP 포워딩

항목MVC1MVC2
컨트롤러없음(jsp가 처리)있음(서블릿이 처리)
JSP가 로직 + 출력JSP는 오직 뷰
코드 재사용낮음높음
유지보수성낮음높음
사용 기술JSP 중심Servlet 중심 + JSP

JNDI(Java Naming and Directory Interface)
: 이름으로 객체를 찾기 위한 표준.
DB연결, 자원(리소스), 환경 설정 등을 이름으로 등록해두고, 자바 코드에서 그 이름으로 가져다 쓰는 방식

  1. 보안성: 코드에 직접 쓰지 않고, 외부(톰켓)에 저장할 수 있음
  2. 유지보수: 코드 수정 없이 설정만 바꾸면 DB나 환경을 변경
  3. 공통 자원 재사용, 커넥션 풀: 여러 서블릿이나 클래스에서 공통된 자원을 설정만으로 공유, 톰캣이 커넥션 풀을 관리해주므로 성능도 좋아짐

C:\tomcat9\conf 이 경로 안에 context.xml 내용을 이렇게 바꾸었다.

<Context>
    <!-- JNDI 이름 정의 -->
    <Resource name="jdbc/mydb"
              auth="Container"
              type="javax.sql.DataSource"
              maxTotal="20"
              maxIdle="10"
              maxWaitMillis="-1"
              username="root"
              password="1234"
              driverClassName="com.mysql.cj.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/java?serverTimezone=Asia/Seoul"/>
</Context>

DBUtil.java

package com.koreait.mvc2.util;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class DBUtil {
    private static DataSource ds;

    static {
        try {
            Context ctx = new InitialContext();
            Context env = (Context) ctx.lookup("java:comp/env");
            ds = (DataSource) env.lookup("jdbc/mydb"); // context.xml의 name
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        return ds.getConnection();  // 커넥션 풀에서 하나를 꺼냄
    }
}

MemberController.java

package com.koreait.mvc2.controller;

import com.koreait.mvc2.service.MemberService;
import com.koreait.mvc2.service.MemberServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("*.member")
public class MemberController extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private MemberService service = new MemberServiceImpl();

    public MemberController() {}

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doAction(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doAction(req, resp);
    }

    protected void doAction(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String uri = req.getRequestURI();
        String context = req.getContextPath();
        String command = uri.substring(context.length());

        switch (command) {
            case "/join.member":
                req.getRequestDispatcher("/WEB-INF/views/join.jsp").forward(req, resp);
                break;
            case "/joinForm.member":
                service.join(req, resp);
                break;
            case "/login.member":
                req.getRequestDispatcher("/WEB-INF/views/login.jsp").forward(req, resp);
                break;
            case "/loginForm.member":
                service.login(req, resp);
                break;
            case "/logout.member":
                service.logout(req, resp);
                break;
            case "/mypage.member":
                req.getRequestDispatcher("/WEB-INF/views/mypage.jsp").forward(req, resp);
                break;
            case "/modifyForm.member":
                if(req.getMethod().equals("GET")){
                    req.getRequestDispatcher("/WEB-INF/views/edit.jsp").forward(req, resp);
                }else if(req.getMethod().equalsIgnoreCase("POST")){
                    service.modify(req, resp);
                }
                break;
            case "/delete.member":
                service.delete(req, resp);
                break;
            default:
                resp.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
}

MemberService.java

package com.koreait.mvc2.service;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public interface MemberService {
    void join(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
    void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
    void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
    void modify(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
    void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
}

MemberServiceImpl.java

package com.koreait.mvc2.service;

import com.koreait.mvc2.dao.MemberDAO;
import com.koreait.mvc2.dto.MemberDTO;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Member;

public class MemberServiceImpl implements MemberService {

    private MemberDAO dao = new MemberDAO();

    @Override
    public void join(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        MemberDTO dto = new MemberDTO();
        dto.setUserid(req.getParameter("userid"));
        dto.setUserpw(req.getParameter("userpw"));
        dto.setName(req.getParameter("name"));
        dto.setHp(req.getParameter("hp"));
        dto.setEmail(req.getParameter("email"));
        dto.setGender(req.getParameter("gender"));
        dto.setSsn1(req.getParameter("ssn1"));
        dto.setSsn2(req.getParameter("ssn2"));
        dto.setZipcode(req.getParameter("zipcode"));
        dto.setAddress1(req.getParameter("address1"));
        dto.setAddress2(req.getParameter("address2"));
        dto.setAddress3(req.getParameter("address3"));
        boolean success = dao.insertMember(dto);
        req.setAttribute("success", success);
        req.getRequestDispatcher("/WEB-INF/views/result.jsp").forward(req, resp);
    }

    @Override
    public void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userid = req.getParameter("userid");
        String userpw = req.getParameter("userpw");

        MemberDTO dto = dao.login(userid, userpw);
        if(dto!=null){
            req.getSession().setAttribute("user", dto);
            req.setAttribute("loginUser", dto);
        }
        req.getRequestDispatcher("/WEB-INF/views/result.jsp").forward(req, resp);
    }

    @Override
    public void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getSession().invalidate();
        resp.sendRedirect("login.member");
    }

    @Override
    public void modify(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        MemberDTO sessionDto = (MemberDTO) req.getSession().getAttribute("user");
        MemberDTO dto = new MemberDTO();
        dto.setUserid(sessionDto.getUserid());
        dto.setName(req.getParameter("name"));
        dto.setHp(req.getParameter("hp"));
        dto.setEmail(req.getParameter("email"));
        dto.setGender(req.getParameter("gender"));
        dto.setZipcode(req.getParameter("zipcode"));
        dto.setAddress1(req.getParameter("address1"));
        dto.setAddress2(req.getParameter("address2"));
        dto.setAddress3(req.getParameter("address3"));
        boolean isModify = dao.updateMember(dto);
        if(isModify){
            req.getSession().setAttribute("user", dto);
        }
        req.setAttribute("isModify", isModify);
        req.getRequestDispatcher("/WEB-INF/views/mypage.jsp").forward(req, resp);
    }

    @Override
    public void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        MemberDTO sessionDto = (MemberDTO) req.getSession().getAttribute("user");
        if(sessionDto != null){
            dao.deleteMember(sessionDto.getUserid());
            req.getSession().invalidate();
        }
        resp.sendRedirect("login.member");
    }
}

🔹 req.getSession().setAttribute("user", dto)
세션 영역에 저장 → 여러 페이지(요청)에서 쓸 수 있음.

로그인 유지가 필요할 때 사용.

ex: 게시판 글쓰기, 댓글 작성, 마이페이지 등 로그인 사용자 확인할 때 씀.

🔹 req.setAttribute("loginUser", dto)
요청(request) 영역에 저장 → 현재 페이지 요청이 끝나면 사라짐.

페이지에 바로 값을 전달하고 싶을 때 사용.

ex: 로그인 성공 후 main.jsp로 loginUser 값을 넘기고 싶을 때.

MemberDAO.java

package com.koreait.mvc2.dao;

import com.koreait.mvc2.dto.MemberDTO;
import com.koreait.mvc2.util.DBUtil;
import com.mysql.cj.x.protobuf.MysqlxPrepare;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class MemberDAO {
    public boolean insertMember(MemberDTO member) {
        String sql = """
                insert into member (userid, userpw, name, hp, email,
                gender, ssn1, ssn2, zipcode, address1, address2, address3)
                values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)     
            """;
        try(Connection conn = DBUtil.getConnection();
            PreparedStatement pstmt = conn.prepareStatement(sql)){
            pstmt.setString(1, member.getUserid());
            pstmt.setString(2, member.getUserpw());
            pstmt.setString(3, member.getName());
            pstmt.setString(4, member.getHp());
            pstmt.setString(5, member.getEmail());
            pstmt.setString(6, member.getGender());
            pstmt.setString(7, member.getSsn1());
            pstmt.setString(8, member.getSsn2());
            pstmt.setString(9, member.getZipcode());
            pstmt.setString(10, member.getAddress1());
            pstmt.setString(11, member.getAddress2());
            pstmt.setString(12, member.getAddress3());
            return pstmt.executeUpdate() == 1;
        }catch(Exception e){
            e.printStackTrace();
            return false;
        }
    }

    public MemberDTO login(String userid, String userpw){
        String sql = "SELECT * FROM member WHERE userid = ? AND userpw = ?";

        try(Connection conn = DBUtil.getConnection();
            PreparedStatement pstmt = conn.prepareStatement(sql)){
            pstmt.setString(1, userid);
            pstmt.setString(2, userpw);
            ResultSet rs = pstmt.executeQuery();
            if(rs.next()){
                MemberDTO member = new MemberDTO();
                member.setIdx(rs.getInt("idx"));
                member.setUserid(rs.getString("userid"));
                member.setName(rs.getString("name"));
                member.setHp(rs.getString("hp"));
                member.setEmail(rs.getString("email"));
                member.setGender(rs.getString("gender"));
                member.setZipcode(rs.getString("zipcode"));
                member.setAddress1(rs.getString("address1"));
                member.setAddress2(rs.getString("address2"));
                member.setAddress3(rs.getString("address3"));
                member.setPoint(rs.getInt("point"));
                return member;
            }
        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
        return null;
    }

    public boolean updateMember(MemberDTO dto) {
        String sql = """
       update member set name=?, hp=?, email=?, gender=?,
        zipcode=?, address1=?, address2=?, address3=?
        where userid=?
            """;
        try(Connection conn = DBUtil.getConnection();
            PreparedStatement pstmt = conn.prepareStatement(sql)){
            pstmt.setString(1, dto.getName());
            pstmt.setString(2, dto.getHp());
            pstmt.setString(3, dto.getEmail());
            pstmt.setString(4, dto.getGender());
            pstmt.setString(5, dto.getZipcode());
            pstmt.setString(6, dto.getAddress1());
            pstmt.setString(7, dto.getAddress2());
            pstmt.setString(8, dto.getAddress3());
            pstmt.setString(9, dto.getUserid());
            return pstmt.executeUpdate() == 1;
        }catch(Exception e){
            e.printStackTrace();
            return false;
        }
    }

    public boolean deleteMember(String userid) {
        String sql = "delete from member where userid=?";
        try(Connection conn = DBUtil.getConnection();
        PreparedStatement pstmt = conn.prepareStatement(sql)){
            pstmt.setString(1, userid);
            return pstmt.executeUpdate() == 1;
        }catch(Exception e){
            e.printStackTrace();
            return false;
        }
    }
}

MemberDTO.java

package com.koreait.mvc2.dto;

public class MemberDTO {
    private int idx;
    private String userid;
    private String userpw;
    private String name;
    private String hp;
    private String email;
    private String gender;
    private String ssn1;
    private String ssn2;
    private String zipcode;
    private String address1;
    private String address2;
    private String address3;
    private String regdate;
    private int point;

    public MemberDTO() {
    }

    public MemberDTO(int idx, String userid, String userpw, String name, String hp, String email, String gender, String ssn1, String ssn2, String zipcode, String address1, String address2, String address3, String regdate, int point) {
        this.idx = idx;
        this.userid = userid;
        this.userpw = userpw;
        this.name = name;
        this.hp = hp;
        this.email = email;
        this.gender = gender;
        this.ssn1 = ssn1;
        this.ssn2 = ssn2;
        this.zipcode = zipcode;
        this.address1 = address1;
        this.address2 = address2;
        this.address3 = address3;
        this.regdate = regdate;
        this.point = point;
    }

    public int getIdx() {
        return idx;
    }

    public void setIdx(int idx) {
        this.idx = idx;
    }

    public String getUserid() {
        return userid;
    }

    public void setUserid(String userid) {
        this.userid = userid;
    }

    public String getUserpw() {
        return userpw;
    }

    public void setUserpw(String userpw) {
        this.userpw = userpw;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getHp() {
        return hp;
    }

    public void setHp(String hp) {
        this.hp = hp;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getSsn1() {
        return ssn1;
    }

    public void setSsn1(String ssn1) {
        this.ssn1 = ssn1;
    }

    public String getSsn2() {
        return ssn2;
    }

    public void setSsn2(String ssn2) {
        this.ssn2 = ssn2;
    }

    public String getZipcode() {
        return zipcode;
    }

    public void setZipcode(String zipcode) {
        this.zipcode = zipcode;
    }

    public String getAddress1() {
        return address1;
    }

    public void setAddress1(String address1) {
        this.address1 = address1;
    }

    public String getAddress2() {
        return address2;
    }

    public void setAddress2(String address2) {
        this.address2 = address2;
    }

    public String getAddress3() {
        return address3;
    }

    public void setAddress3(String address3) {
        this.address3 = address3;
    }

    public String getRegdate() {
        return regdate;
    }

    public void setRegdate(String regdate) {
        this.regdate = regdate;
    }

    public int getPoint() {
        return point;
    }

    public void setPoint(int point) {
        this.point = point;
    }
}

join.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>회원가입</title>
</head>
<body>
<h2>회원가입</h2>
<form method="post" action="joinForm.member">
    <p>아이디: <input type="text" name="userid"></p>
    <p>비밀번호: <input type="password" name="userpw"></p>
    <p>이름: <input type="text" name="name"></p>
    <p>휴대폰: <input type="text" name="hp"></p>
    <p>이메일: <input type="email" name="email"></p>
    <p>성별: <select name="gender">
        <option value="남자">남자</option>
        <option value="여자">여자</option>
    </select></p>
    <p>주민등록번호: <input type="text" name="ssn1"> - <input type="password" name="ssn2"></p>
    <p>우편번호: <input type="text" name="zipcode"></p>
    <p>주소: <input type="text" name="address1"></p>
    <p>상세주소: <input type="text" name="address2"></p>
    <p>참고항목: <input type="text" name="address3"></p>
    <p><button type="submit">완료</button></p>
</form>
</body>
</html>

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>로그인</title>
</head>
<body>
<h2>로그인</h2>
<form method="post" action="loginForm.member">
    <input type="hidden" name="action" value="login">
    <p>아이디: <input type="text" name="userid"></p>
    <p>비밀번호: <input type="password" name="userpw"></p>
    <p><button type="submit">로그인</button></p>
</form>
</body>
</html>

mypage.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    com.koreait.mvc2.dto.MemberDTO user = (com.koreait.mvc2.dto.MemberDTO) session.getAttribute("user");
    session.getAttribute("user");
%>
<html>
<head>
    <title>마이페이지</title>
</head>
<body>
<h2>${user.name}님 마이페이지</h2>
<p>아이디: ${user.userid}</p>
<p>이메일: ${user.email}</p>
<form method="get" action="modifyForm.member">
    <button type="submit">회원정보 수정</button>
</form>
<form method="post" action="delete.member" onsubmit="return confirm('정말 탈퇴하시겠습니까?')">
    <button type="submit">회원 탈퇴</button>
</form>
<a href="logout.member">로그아웃</a>
</body>
</html>

edit.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    com.koreait.mvc2.dto.MemberDTO user = (com.koreait.mvc2.dto.MemberDTO) session.getAttribute("user");
%>
<html>
<head>
    <title>회원정보 수정</title>
</head>
<body>
<h2>회원정보 수정</h2>
<form method="post" action="modifyForm.member">
    <p>아이디: ${user.userid}</p>
    <p>이름: <input type="text" name="name" value="${user.name}"></p>
    <p>휴대폰: <input type="text" name="hp" value="${user.hp}"></p>
    <p>이메일: <input type="email" name="email" value="${user.email}"></p>
    <p>성별: <select name="gender">
        <option ${user.gender == "남자" ? "selected" : ""} value="남자">남자</option>
        <option ${user.gender == "여자" ? "selected" : ""} value="여자">여자</option>
    </select></p>
    <p>우편번호: <input type="text" name="zipcode" value="${user.zipcode}"></p>
    <p>주소: <input type="text" name="address1" value="${user.address1}"></p>
    <p>상세주소: <input type="text" name="address2" value="${user.address2}"></p>
    <p>참고항목: <input type="text" name="address3" value="${user.address3}"></p>
    <p><button type="submit">완료</button></p>
</form>
</body>
</html>

result.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>Result</title>
</head>
<body>
<c:choose>
    <c:when test="${not empty success}">
        <c:choose>
            <c:when test="${success}">
                <h2>회원가입이 성공적으로 처리되었습니다!</h2>
                <p><a href="mypage.member">마이페이지</a></p>
            </c:when>
            <c:otherwise>
                <h2>회원가입 중 문제가 발생했습니다.</h2>
            </c:otherwise>
        </c:choose>
    </c:when>
    <c:when test="${not empty loginUser}">
        <h2>${loginUser.userid}(${loginUser.name})님, 로그인 성공!</h2>
        <p><a href="mypage.member">마이페이지</a> | <a href="logout.member">로그아웃</a></p>
    </c:when>
    <c:otherwise>
        <h2>로그인 실패</h2>
        <p>아이디 또는 비밀번호를 확인하세요 🤢🤢🤢</p>
    </c:otherwise>
</c:choose>
</body>
</html>

Filter
웹 애플리케이션에서 요청이나 응답을 가로채서 전처리 또는 후처리할 수 있는 기능을 제공하는 서블릿 컴포넌트

  • 로그인 여부 확인, 관리자 권한 확인
  • 누가 URL에 접근했는지 로그 출력
  • 응답 내용을 gzip으로 압축
  • URL 접근 제한, 파라미터 필터링

init() : 필터가 초기화될 때 1번만 호출됨(설정 읽기 등 가능)
doFIlter() : 핵심 메서드. 요청이 필터를 통과할 때마다 실행됨
destroy() : 필터가 제거될 때 실햄됨(자원 정리 등)

적용방식

    1. 어노테이션 방식
    1. web.xml 등록

web.xml에 이렇게 내용을 추가했다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
         version="6.0">
    <!--로그인 필터 등록-->
    <filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>com.koreait.mvc2.filter.LoginFilter</filter-class>
    </filter>
    <!--로그인 필터 적용-->
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/mypage.member</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/modifyForm.member</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/delete.member</url-pattern>
    </filter-mapping>
</web-app>

LoginFilter

package com.koreait.mvc2.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter
public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        HttpSession session = req.getSession();
        boolean loggedIn = session != null && session.getAttribute("user") != null;

        if(loggedIn){
            chain.doFilter(request, response); // 다음 필터나 서블릿으로 진행
        }else{
            resp.sendRedirect(req.getContextPath()+"/login.member");
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

로그인 되어 있지 않으면, 바로 로그인 페이지로 넘어가게끔 필터로 걸러주었다. 이로써 로그인도 안 된 상태에서 마이페이지, 회원수정, 회원탈퇴 페이지에 들어갈 수 없게 된다.


MVC2 폴더 구조

profile
The light shines in the darkness.

0개의 댓글