MVC 적용하기
가장 먼저 만들어야 할 것은 controller이다. mvc모델에 경우 view에 들어가기 위해서는 반드시 매핑된 주소를 통해서 들어가야한다. 우리가 만들 mvc의 view같은 경우는 WEB-INF라는 폴더안에 들어가게 되는데 이 폴더는 특수한 폴더로 외부에선 절대로 직접 접근하여 열 수 없게 만들어졌기 때문이다. 그러므로 우리는 view를 보기위해서 view에 매핑된 controller를 먼저 만들어보자.
@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);
}
}
위의 코드를 보게 되면 매핑된 url이 존재하고 경로를 string으로 지정하여 그것을 dispatcher로 만들고 forward를 통해 이동하게 만들어져있다. dispatcher.forward()는 다른 서블릿이다. JSP로 이동할 수 있는 기능이다. 서버 내부에서 다시 호출이 발생한다.
※ WEB-INF : 이 경로안에 JSP가 있으면 외부에서 직접 JSP를 호출할 수 없다. 우리가 기대하는 것은 항상 컨트롤러를 통해서 JSP가 호출되는 것이다.
Redirect VS Forward
리다이렉트는 실제 클라이어트(웹 브라우저)에 응답이 나갔다가, 클라이언트가 redirect경로로 다시 요청한다. 따라서 클라이언트가 인지할 수 있고, URL 경로도 실제로 변경된다. 반면 포워드는 서버 내부에서 일어나는 호출이기 때문에 클아이언트가 전혀 인지하지 못한다.
포워딩 된 위치로 이동하여 전에 Servlet과 JSP에서도 사용했던 new-form으로 이동한다.
<%@ 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>
위의 저장되는 방식은 Servlet, JSP, MVC 모두 다르지만 이렇게 하나의 폼을 사용할 수 있는 이유가 form 안에 action이 상대경로이기 때문이다. 모두 new-form으로 들어온 매핑주소는 다르지만 모두 맨 마지막이 save로 끝나기 때문에 가능하다.
이제 이렇게 값을 가져온 mvc방식의 java파일을 보자
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username,age);
memberRepository.save(member);
// 위의 코드까지는 이전과 똑같다.
//Model에 데이터를 보관
request.setAttribute("member",member);
String viewPath = "/WEB-INF/views/save-result.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
}
위의 코드를 보게 되면 save까지는 같은 방식이다. 하지만 아래를 보게 되면 저장된 객체를 request.setAttribue에 담는 모습을 볼 수 있다. 이게 차이점이다. 이렇게 request 요청에 저장된 값(model)을 "member"라는 변수에 담고 그대로 포워딩을 하여 값을 가져가보자.
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<html>
<head>
<title>title</title>
</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>
우리는 MVC방식의 java파일에서 저장된 값을 member라는 변수에 담아서 request로 가져왔다.
위의 코드를 보게 되면 꺼내는 방식이 앞전과는 다른데 이렇게 가능한 이유는 우리가 값을 저장하기 위해 Member라는 VO객체를 통해 담았기 때문에 그대로 id, username, age 이런식으로 간결하게 꺼내올 수 있는것이다. 가능하면 이렇게 아니 무조건 이름은 통일하는게 맞다. 이제 이렇게 하나씩 memberRepository에 저장 된 정보들을 List로 모두 보여주는 모습을 보자.
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Member> members = memberRepository.fineAll();
request.setAttribute("members",members);
String viewPath = "/WEB-INF/views/members.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
}
이번에도 저장된 값들을 fineAll() (findAll)을 통해 members에 저장을 했는데 이번에는 하나의 객체가 아닌 여러 members이기 때문에 List로 가져왔는데 역시 모두 Member객체 타입이기 때문에 List<Member>인 모습을 볼 수 있다. 마찬가지로 request.setAttribute에 "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>
<tr>
<th>id</th>
<th>username</th>
<th>age</th>
</tr>
<tr>
<c:forEach var="item" items="${members}">
<tr>
<td>${item.id}</td>
<td>${item.username}</td>
<td>${item.age}</td>
</tr>
</c:forEach>
</tr>
</table>
</body>
</html>
우리는 이번에 List 즉 다수의 회원정보를 가져왔는데 members라는 하나의 변수에 저장을 해서 가져왔다.
그렇다면 숫자를 넣어서 꺼내면 될까? 위의 코드를 보게 되면 값을 꺼내오는 모습은 하나의 회원정보를 꺼내는 모습과 동일 하지만 이번에는 꺼내는 횟수가 많을뿐이다. java에서 for문과 동일한 방식이다. <c:foreach>라는 jstl문을 사용했다.
이방식을 사용하기 위해서는 맨위 상단에
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
이런 taglib이라는 부분이 잇는데 보시다시피 기능을 해당 url에서 가져온 모습이다. 앞에 prefix는 해당 url의 기능들을 불러서 사용할 변수라고 생각하면 된다. 해당 url에는 아주 많은 기능들이 있는데 <c:foreach>도 그중 하나이다.
<c:foreach> 안에 var와 items가 있는데 var는 foreach문 안에서 사용할 변수의 이름이고 items는 안에서 돌릴 값들(members)의 값을 넣어준다. 우리는 members라는 변수에 List로 저장을 해서 왓으니 items에는 ${members} 값을 넣어주고 var에는 간결하게 item이라는 이름을 붙여주었다. ( 어떤이름이든 상관없다 단순한 변수이기 때문에 ) 이제 이렇게 저장된 값들을 안에서 하나씩 꺼낼때마다 반복하게 되고 더이상 꺼낼값이 없다면 for문을 나가게 된다. 물론 foreach문 안에서도 많은 기능들이 있지만 우리는 jstl을 공부하는게 아니니 궁굼하다면 나중에 찾아보도록하자.

우리는 위의 그림에서 서비스,리포지토리를 사용하지 않고 controller에서 view로 이동하고 view에서 저장된 값을 다시 controller에서 가공한 뒤 model에 담아서 view에 뿌려준 모습을 햇다. service와 repository는 나중에 DB와 연결을 했을때 사용하는 기능이니 천천히 배워보자.