<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
</body>
</html>
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
MemberRepository memberRepository = MemberRepository.getInstance();
List<Member> members = memberRepository.findAll();
%>
<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>
<%
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>");
}
%>
</tbody>
</table>
</body>
</html>
서블릿으로 개발할 땐 java로 html 코드를 짜야해서 IDE의 도움도 못 받고 굉장히 불편함.
jsp가 이를 해결해줬지만 jsp가 비즈니스~뷰의 영역까지 포함하기 때문에 너무 많은 역할을 하고 있다.
그리고 java코드, 데이터조회로직, 뷰로직 까지 하면 조금만 복잡한 코드가 되면 굉장히 가독성이 떨어질 것이다.
이는 유지보수가 굉장히 힘들어진다.
진짜 문제는 둘 사이(비즈니스로직과 뷰)의 변경 라이프 사이클이 다르다는 점이다.
예를들어 "UI를 일부 수정하는 일" 과 "비즈니스 로직을 수정하는 일" 은 각각 다르게 발생할 가능성이 매우 높고 대부분 서로에게 영향을 주지 않는다.
이렇게 변경의 라이프 사이클이 다른 부분을 하나의 코드로 관리하는 것은 유지보수하기 좋지 않다.
이를 해결하고자 MVC 패턴이 등장한 것이다.
그래서 비즈니스 로직을 servlet에서 처리하고 jsp는 뷰 역할만 하는 것이다.
컨트롤러: 사용자가 호출하는 대상이며 해당 컨트롤러가 사용자 요청이 제대로 된 것인지 HTTP 스펙이 맞는지 등등 을 검사한다.
서비스: 비즈니스 로직이 실행되는 곳 DB접근을 하고 로직을 거쳐 결과를 전달한다.
컨트롤러: 서비스에서 받은 결과값을 모델로 정의하여 값을 넣어서 뷰에 전달함 (reqeust.setAttribute)
뷰: 컨트롤러가 넣어둔 데이터를 컨트롤러가 정의한 모델로 가져와서 뿌려줌. (reqeust.getAttribute)
컨트롤러 아래 코드는 그냥 소규모 예제이기 때문에 따로 서비스 로직 없이 바로 뷰로 보내주는 컨트롤러이다.
@WebServlet(name = "mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form")
public class MvcMemberFormServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String viewPath = "/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>jsp/servlet으로 mvc 폼 구현</title>
</head>
<body>
<form action="save" method="post">
username: <input type="text" name="username"/>
age: <input type="number" step="1" name="age"/>
<button type="submit">전송</button>
</form>
</body>
</html>
/xxx
이런식으로 교체되는거다. 그래서 해당 url이 호출되는 것이다. <%@ page import="hello.servlet.domain.member.Member" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>save-result/jsp/servlet</title>
</head>
<body>
성공
<ul>
<li>id=${member.id}></li>
<li>username=${member.username}</li>
<li>age=<%= ((Member)request.getAttribute("member")).getAge(); %></li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>
그래서 컨트롤러에서 넘어온 값을 이렇게 표현 가능하다 프로퍼티 접근법으로 그냥 필드값을 넣어주면 알아서 .getxxx() 메서드로 바꿔준다는 것이다.
그래고 원래는 getAttribute를 해서 갖고온 값을 캐스팅하여 .getxxx() 해야하는데 표현식을 통해 편리하게 작성할 수 있다.
<%@ 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>
굉장히 반복되는 구조가 많다.
prefix와 subfix가 항상 붙고 (/WEB-INF/views/, .jsp) 혹시 구조가 바뀐다면 일일이 모든 파일을 다 변경해야한다.
그리고 dispatcher를 가져와 forward하는 코드도 중복이다.
response는 거의 쓰이지도 않을 뿐더러 request도 가끔은 안 쓰인다.
테스트 코드 작성이 굉장히 어렵다.
공통 처리가 어렵다.
cmd + e
: 이전 파일 위치 목록
ctrl + shift + T
: 테스트 파일 즉석 작성