- 위와 같은 형태로 MVC 형태의 코드를 작성해 볼 것이다.
- 현재 서버를 기동하고 아무런 정보가 담겨있지 않은 상태이다.
- ~~~/new-form의 URI를 통해 접근했을 때
- 아래의 코드는 여러 Controller를 관리하는 앞단에 존재하는 FrontController에 해당한다.
@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v3/*")
// URI 요청이 v3 하위 경로로 오면 아래 메서드가 무조건 실행된다.
public class FrontControllerServletV3 extends HttpServlet {
private Map<String, ControllerV3> controllerMap = new HashMap<>();
// String과 ControllerV3를 참조형으로 하는 controllerMap이라는 HashMap을 생성한다.
public FrontControllerServletV3() {
controllerMap.put("/front-controller/v3/members/new-form", new MemberFormControllerV3());
controllerMap.put("/front-controller/v3/members/save", new MemberSaveControllerV3());
controllerMap.put("/front-controller/v3/members", new MemberListControllerV3());
}
// 해당 메서드를 통해 Map에 URI, new를 통해 객체가 생성된다.
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("FrontControllerServletV3.service");
String requestURI = request.getRequestURI();
// 브라우저에 입력된 URI를 받을 수 있다. 회원 가입을 누르게 되면 new-form의 URI가 requestURI에 저장된다.
ControllerV3 controller = controllerMap.get(requestURI);
// Map에 저장된 해당 URI에 대한 value 값을 controller 변수에 넣는다. // 여기서 ControllerV3의 참조형이지만 실제로는 MemberFormControllerV3의 객체를 사용한다.
if (controller == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
// 해당 URI에 대한 value가 없으면 404(SC_NOT_FOUND)를 호출하고 아무것도 반환하지 않는다.
//paramMap
Map<String, String> paramMap = createParamMap(request);
// 매배변수를 request로 하고, request 저장소에 있는 key, value 값을 Map<String, String> 형태로 반환한다.
// 즉, 회원가입 form을 통해 저장된 파라미터의 key, value값을 반환하는 것이다.
ModelView mv = controller.process(paramMap);
// createParamMap을 통해 저장된 파라미터 key, value들을 ModelView를 참조형으로 하는 참조변수 mv에 저장한다.
// 현재 MemberFormControllerV3의 객체를 사용하고 있다.
// 현재 위의 코드는 ModelView mv = new ModelView("new-form"); 와 동일하다.
//new-form
String viewName = mv.getViewName();//논리 이름 new-form 이것밖에 못 가져온다.
// /WEB-INF ~~~ 로 만들어진다.
// 매개변수를 포함한 생성자를 통해 해당 viewName이 new-form으로 전달된다.
MyView view = viewResolver(viewName);
//viewResolver라는 메서드를 통해 "/WEB-INF/views/new-form.jsp"의 값이 viewPath로 저장된다.
view.render(mv.getModel(), request, response);
}
private static MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" + viewName + ".jsp");
}
private static Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
return paramMap;
}
}
@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v3/*")
- 위 설정으로 인해 /v3/하위 경로가 호출되면 아래 메서드가 전부 실행된다.
- 우선 new-form에서는 별도의 데이터가 저장되어 넘어가지 않기 때문에 request 저장소에 parameter 값으로 꺼낼 값은 현재 없는 상황이다.
<%@ 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>
- 위와 같이 username과 age를 입력하게 전송 버튼을 누르게 되면 상대 경로를 통해 /front-controller/v3/members/save로 입력된 정보들이 post를 통해 데이터가 전달된다.
- 데이터를 전달하게 되면 위와 같이 ~~~/save의 URI로 form에 의한 데이터가 전달된다.
@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v3/*")
// URI 요청이 v3 하위 경로로 오면 아래 메서드가 무조건 실행된다.
public class FrontControllerServletV3 extends HttpServlet {
private Map<String, ControllerV3> controllerMap = new HashMap<>();
// String과 ControllerV3를 참조형으로 하는 controllerMap이라는 HashMap을 생성한다.
public FrontControllerServletV3() {
controllerMap.put("/front-controller/v3/members/new-form", new MemberFormControllerV3());
controllerMap.put("/front-controller/v3/members/save", new MemberSaveControllerV3());
controllerMap.put("/front-controller/v3/members", new MemberListControllerV3());
}
// 해당 메서드를 통해 Map에 URI, new를 통해 객체가 생성된다.
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("FrontControllerServletV3.service");
String requestURI = request.getRequestURI();
// 브라우저에 입력된 URI를 받을 수 있다. 회원 가입을 누르게 되면 new-form의 URI가 requestURI에 저장된다.
ControllerV3 controller = controllerMap.get(requestURI);
// Map에 저장된 해당 URI에 대한 value 값을 controller 변수에 넣는다. // 여기서 ControllerV3의 참조형이지만 실제로는 MemberFormControllerV3의 객체를 사용한다.
if (controller == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
// 해당 URI에 대한 value가 없으면 404(SC_NOT_FOUND)를 호출하고 아무것도 반환하지 않는다.
//paramMap
Map<String, String> paramMap = createParamMap(request);
// 매배변수를 request로 하고, request 저장소에 있는 key, value 값을 Map<String, String> 형태로 반환한다.
// 즉, 회원가입 form을 통해 저장된 파라미터의 key, value값을 반환하는 것이다.
ModelView mv = controller.process(paramMap);
// createParamMap을 통해 저장된 파라미터 key, value들을 ModelView를 참조형으로 하는 참조변수 mv에 저장한다.
// 현재 MemberFormControllerV3의 객체를 사용하고 있다.
// 현재 위의 코드는 ModelView mv = new ModelView("new-form"); 와 동일하다.
//new-form
String viewName = mv.getViewName();//논리 이름 new-form 이것밖에 못 가져온다.
// /WEB-INF ~~~ 로 만들어진다.
// 매개변수를 포함한 생성자를 통해 해당 viewName이 new-form으로 전달된다.
MyView view = viewResolver(viewName);
//viewResolver라는 메서드를 통해 "/WEB-INF/views/new-form.jsp"의 값이 viewPath로 저장된다.
view.render(mv.getModel(), request, response);
}
private static MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" + viewName + ".jsp");
}
private static Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
return paramMap;
}
}
- 위의 코드를 자세히 분석해보겠다.
@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v3/*")
// URI 요청이 v3 하위 경로로 오면 아래 메서드가 무조건 실행된다.
public class FrontControllerServletV3 extends HttpServlet {
private Map<String, ControllerV3> controllerMap = new HashMap<>();
// String과 ControllerV3를 참조형으로 하는 controllerMap이라는 HashMap을 생성한다.
public FrontControllerServletV3() {
controllerMap.put("/front-controller/v3/members/new-form", new MemberFormControllerV3());
controllerMap.put("/front-controller/v3/members/save", new MemberSaveControllerV3());
controllerMap.put("/front-controller/v3/members", new MemberListControllerV3());
}
- 위 코드를 통해 1. ~~~/new-form 2. ~~~/save / 3.~~~/members의 String 값을 key로, new ~~~를 통한 객체를 value로 controllerMap에 HashMap을 통해 저장된다.
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("FrontControllerServletV3.service");
String requestURI = request.getRequestURI();
// 브라우저에 입력된 URI를 받을 수 있다. 회원 가입을 누르게 되면 new-form의 URI가 requestURI에 저장된다.
- HttpServletRequest를 URI로 전달된 정보들이 담긴다.
https://insoobaik.tistory.com/366
- HttpServletRequest에 저장되는 정보들은 위와 같다.
- 현재 ~~~/save의 URI가 requestURI 변수에 담긴다.
ControllerV3 controller = controllerMap.get(requestURI);
// Map에 저장된 해당 URI에 대한 value 값을 controller 변수에 넣는다. // 여기서 ControllerV3의 참조형이지만 실제로는 MemberFormControllerV3의 객체를 사용한다.
if (controller == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
// 해당 URI에 대한 value가 없으면 404(SC_NOT_FOUND)를 호출하고 아무것도 반환하지 않는다.
- controller 변수에 ~~~/save URI가 담긴다.
- 없을 경우 SC_NOT_FOUNT = 404 메서드가 응답 데이터에 저장된다.
//paramMap
Map<String, String> paramMap = createParamMap(request);
// 매배변수를 request로 하고, request 저장소에 있는 key, value 값을 Map<String, String> 형태로 반환한다.
// 즉, 회원가입 form을 통해 저장된 파라미터의 key, value값을 반환하는 것이다.
ModelView mv = controller.process(paramMap);
// createParamMap을 통해 저장된 파라미터 key, value들을 ModelView를 참조형으로 하는 참조변수 mv에 저장한다.
// 현재 MemberFormControllerV3의 객체를 사용하고 있다.
// 현재 위의 코드는 ModelView mv = new ModelView("new-form"); 와 동일하다.
.......
private static Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
return paramMap;
- paramMap을 컬렉션 변수에 createParamMap메서드를 통해 반환되는 paramMap이 저장된다.
- createParamMap은 request를 통해 전달된 파라미터의 key, value 값들이 paramMap에 저장된다.
- ModelView를 참조형으로 하는 mv 참조 변수는 process(paramMap)메서드를 실행하게 되는데 현재 controller 참조 변수는
에 의해 MemberSaveControllerV3의 객체가 생성되어 있는 상태다.
public class MemberSaveControllerV3 implements ControllerV3 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap) {
String username = paramMap.get("username");
int age = Integer.parseInt(paramMap.get("age"));
Member member = new Member(username, age);
memberRepository.save(member);
ModelView mv = new ModelView("save-result");
mv.getModel().put("member", member);
return mv;
}
}
- 위의 process 메서드는 paramMap에 담겨있는 각, key에 대한 value 값들을 뽑아내는 작업을 한다.
- 변수를 통해 저장한 value 값들을 member 객체를 통해 Member 저장소에 해당하는 memberRepository에 저장한다.
- mv 참조변수에는 "save-result"의 viewName을 저장하고, getModel을 통해 member라는 key값에 memberRepository에 저장된 member 객체를 저장하고, 최종적으로 mv 객체를 반환한다.
username : baek
age : 29
- paramMap에 위의 정보가 저장되어 있을 것이다.
//new-form
String viewName = mv.getViewName();//논리 이름 new-form 이것밖에 못 가져온다.
// /WEB-INF ~~~ 로 만들어진다.
// 매개변수를 포함한 생성자를 통해 해당 viewName이 new-form으로 전달된다.
MyView view = viewResolver(viewName);
//viewResolver라는 메서드를 통해 "/WEB-INF/views/new-form.jsp"의 값이 viewPath로 저장된다.
view.render(mv.getModel(), request, response);
}
...
private static MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" + viewName + ".jsp");
}
---------------------
public String getViewName() {
return viewName;
}
---------------------
public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// view.render(mv.getModel(), request, response); 해당 값들이 넘어온다. getModel을 통해 입력된 파라미터 key, value 값들이 HashMap으로 저장되어 넘어온다.
modelToRequestAttribute(model, request);
// 해당 메서드를 통해 JSP로 데이터를 넘기기 위해 request.setAttribute를 통해 request 저장소에 저장한다.
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
private static void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
model.forEach((key, value) -> request.setAttribute(key,value));
}
- mv의 viewName 변수에는 "save-result"가 담겨있다.
- viewResolver를 통해 "/WEB-INF/views/save-result.jsp"의 값이 view 객체의 viewName 값에 저장된다.
- mv.getModel를 통해 process() 메서드를 통해 저장된 "member"의 객체 "member"를 호출한다.
- modelToRequestAttribute(model, request) 메서드를 통해 model객체 담긴 key, value값을 request 저장소에 저장한다. setAttribute를 통해 저장하게되면 jsp에서 해당 데이터들을 사용할 수 있다.
- 현재 request 저장소에는 key = id, value = 1 / key = username, value = 29 / key = age, value = 29의 값이 저장되어 있다.
- 해당 데이터를 viewPath("/WEB-INF/views/save-result.jsp") jsp로 연결되며, dispatcher.forward(request, response)를 통해 해당 저장소에 저장된 데이터들이 jsp 파일로 전달된다.
<%@ 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>
- 위 jsp 페이를 통해 해당 URI에 대해 아래와 같은 화면을 보여준다.
출처 : 인프런 - 우아한 형제들 기술이사 김영한의 스프링 완전 정복 (스프링 핵심원리 - 기본 편)
'Programming > Servlet, JSP' 카테고리의 다른 글
Spring - Servlet + JSP를 이용한 MVC 동작 과정 정리 V5 (0) | 2023.06.16 |
---|---|
Spring - Servlet + JSP를 이용한 MVC 동작 과정 정리 V4 (0) | 2023.06.16 |
HttpServletRequest (1) | 2023.06.14 |
Servlet - 서블릿, JSP, MVC 패턴 (0) | 2023.06.14 |
Spring - Servlet (0) | 2023.06.13 |