본문 바로가기
Spring Tutorial

[스프링MVC 20] MVC 패턴으로 회원 관리 웹 애플리케이션

by 미소5 2023. 7. 27.

직접 MVC 패턴을 적용해서 프로젝트를 리팩터링 해보자.

컨트롤러로 서블릿을 사용하고, 뷰로 JSP를 사용하고, Model은 HttpServletRequest 객체를 사용한다.

  • request는 내부에 데이터 저장소를 가지고 있는데, request.setAttribute() , request.getAttribute() 를 사용하면 데이터를 보관하고, 조회할 수 있다.

 


  • 회원 등록
/**회원등록 폼 -컨트롤러*/

@WebServlet(name = "mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form")
public class MvcMemberFormServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String viewPath = "/WEB-INF/views/new-form.jsp";
        RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
        dispatcher.forward(req, resp);
   }

}
  • /WEB-INF
    • 이 경로안에 JSP가 있으면 외부에서 직접 JSP를 호출할 수 없다. (우리가 기대하는 것은 항상 컨트롤러를 통해서 JSP를 호출하는 것)
      • localhost:8080/jsp/members.jsp 로 호출 불가능
  • dispatcher.forward()
    • 다른 서블릿이나 jsp로 이동할 수 있는 기능. 서버 내부에서 이 경로로(viewPath) 다시 호출이 발생한다.
  • redirect vs forward
    • 리다이렉트는 실제 클라이언트(웹 브라우저)에 응답이 나갔다가, 클라이언트가 redirect 경로로 다시 요청한다. 따라서 클라이언트가 인지할 수 있고, URL 경로도 실제로 변경된다. 반면에 포워드(forward)서버 내부에서 일어나는 호출이기 때문에 클라이언트가 전혀 인지하지 못한다.

 


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 회원 등록 폼 - 뷰 -->

<html>
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>

<!-- 상대경로 사용. [현재 URL이 속한 계층 경로 + /save] -->
<form action="save" method="post">
 username: <input type="text" name="username" />
 age: <input type="text" name="age" />
 <button type="submit">전송</button>
</form>

</body>
</html>
  • form의 action을 보면 절대 경로( / 로 시작)가 아니라 상대경로( / 로 시작X)인 것을 확인할 수 있다. 이렇게 상대경로를 사용하면 폼 전송시 현재 URL이 속한 계층 경로 + save가 호출된다.
    • 현재 계층 경로: /servlet-mvc/members/
    • 결과: /servlet-mvc/members/save

 

※ 이후 코드에서 해당 jsp를 계속 사용하기 때문에, 상대경로를 사용한 부분을 그대로 유지해야함

 


  • 회원 저장
/**회원 저장 - 컨트롤러*/

@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        int age = Integer.parseInt(req.getParameter("age"));

        Member member = new Member(username, age);
        memberRepository.save(member);

        req.setAttribute("member", member);   //Model에 데이터를 보관

        String viewPath = "/WEB-INF/views/save-result.jsp";
        RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
        dispatcher.forward(req, resp);
    }

}
  • HttpServletRequest를 Model로 사용한다. request가 제공하는 setAttribute()를 사용하면 request 객체에 데이터를 보관해서 뷰에 전달할 수 있다. 는 request.getAttribute()를 사용해서 데이터를 꺼내면 된다.

 


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 회원 저장 - 뷰 -->

<html>
<head>
 <meta charset="UTF-8">
</head>
<body>
성공

<ul>
 <li>id=${member.id}</li>
 <li>username=${member.username}</li>
 <li>age=${member.age}</li>
</ul>

<a href="/index.html">메인</a>
</body>
</html>
  • <%= req.getAttribute("member")%> 로 모델에 저장한 member 객체를 꺼낼 수 있지만, 너무 복잡해진다. 
<li>id=<%= ((Member)req.getAttribute("member")).getId() %></li>
<li>username=<%= ((Member)req.getAttribute("member")).getUsername() %></li>
<li>age=<%= ((Member)req.getAttribute("member")).getAge() %></li>
  • JSP가 제공하는 ${} 문법으로, req의 attribute에 담긴 데이터를 편리하게 조회할 수 있다.

 


  • 회원 목록 조회
/**회원 목록 조회 - 컨트롤러*/

@WebServlet(name = "mvcMemberListServlet", urlPatterns = "/servlet-mvc/members")
public class MvcMemberListServlet extends HttpServlet {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        List<Member> members = memberRepository.findAll();

        req.setAttribute("members", members);

        String viewPath = "/WEB-INF/views/members.jsp";
        RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
        dispatcher.forward(req, resp);
    }
}
  • request 객체를 사용해서 List<Member> members모델에 보관

 


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 회원 목록 조회 - 뷰 -->

<html>
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
<a href="/index.html">메인</a>
<table>

 <thead>
 <th>id</th>
 <th>username</th>
 <th>age</th>
 </thead>

 <tbody>
 <c:forEach var="item" items="${members}">
    <tr>
        <td>${item.id}</td>
        <td>${item.username}</td>
        <td>${item.age}</td>
    </tr>
 </c:forEach>
 </tbody>

</table>
</body>
</html>
  • 모델에 담아둔 members를 JSP가 제공하는 taglib기능을 사용해서 반복하면서 출력했다. (members 리스트에서 member를 순서대로 꺼내서 item 변수에 담고, 출력하는 과정을 반복)
  • <c:forEach> 기능을 사용하려면 다음과 같이 선언해야 한다.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

 

  •  해당 기능을 사용하지 않고, 다음과 같이 출력해도 되지만, 매우 지저분
<%
 for (Member member : members) {
 out.write(" <tr>");
 out.write(" <td>" + member.getId() + "</td>");
 out.write(" <td>" + member.getUsername() + "</td>");
 out.write(" <td>" + member.getAge() + "</td>");
 out.write(" </tr>");
 }
%>

JSP와 같은 뷰 템플릿은 이렇게 화면을 렌더링 하는데 특화된 다양한 기능을 제공한다.

 


실행

[스프링MVC 19] MVC 패턴 (tistory.com)

 

[스프링MVC 19] MVC 패턴

1. 하나의 서블릿이나 JSP만으로 비즈니스 로직과 뷰 렌더링까지 모두 처리하게 되면, 너무 많은 역할을 하게되고, 결과적으로 유지보수가 어려워진다. (비즈니스 로직을 호출하는 부분에 변경이

joly156.tistory.com

 



[스프링 MVC 8] 서블릿: HttpServletRequest (tistory.com)

 

[스프링 MVC 8] 서블릿: HttpServletRequest

HttpServletRequest 역할 HTTP 요청 메시지를 개발자가 직접 파싱해서 사용해도 되지만, 매우 불편할 것이다. 서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 HTTP 요청

joly156.tistory.com

[스프링MVC 17] 서블릿으로 회원 관리 웹 애플리케이션 (tistory.com)

 

[스프링MVC 17] 서블릿으로 회원 관리 웹 애플리케이션

서블릿으로 회원 관리 웹 애플리케이션을 만들어보자. MemberFormServlet 단순하게 회원 정보를 입력할 수 있는 HTML Form을 만들어 응답 /**회원 등록 폼*/ @WebServlet(name="memberFormServlet", urlPatterns = "/servlet

joly156.tistory.com

[스프링MVC 18] JSP로 회원 관리 웹 애플리케이션 (tistory.com)

 

[스프링MVC 18] JSP로 회원 관리 웹 애플리케이션

JSP로 회원 관리 웹 애플리케이션을 만들어보자. JSP를 사용하려면 build.gradle에 라이브러리를 추가해야 한다. implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' implementation 'javax.servlet:jstl' 회원 등록

joly156.tistory.com

728x90
반응형