Skip to content

Commit cd71121

Browse files
authored
[MVC 구현하기 - 2단계] 망고(고재철) 미션 제출합니다. (#531)
* feat: HandlerMapping 인터페이스 구현 * feat: HandlerAdapter 인터페이스 및 ManualHandlerAdapter, AnnotationHandlerAdapter 구현 * feat: HandlerMappings, HandlerAdapters 구현 * feat: 인터페이스 기반, 어노테이션 기반 동시 지원하도록 DispatcherServlet 구현 * refactor: 어노테이션 방식으로 RegisterController 변경 * refactor: RegisterController URI 매핑 수정 * refactor: Override 어노테이션 추가
1 parent 223e029 commit cd71121

File tree

14 files changed

+193
-36
lines changed

14 files changed

+193
-36
lines changed

app/src/main/java/com/techcourse/DispatcherServlet.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,50 @@
66
import jakarta.servlet.http.HttpServletResponse;
77
import org.slf4j.Logger;
88
import org.slf4j.LoggerFactory;
9+
import webmvc.org.springframework.web.servlet.ModelAndView;
10+
import webmvc.org.springframework.web.servlet.mvc.asis.ManualHandlerAdapter;
11+
import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerAdapter;
12+
import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping;
913
import webmvc.org.springframework.web.servlet.view.JspView;
1014

1115
public class DispatcherServlet extends HttpServlet {
1216

1317
private static final long serialVersionUID = 1L;
1418
private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class);
1519

16-
private ManualHandlerMapping manualHandlerMapping;
20+
private final transient HandlerMappings handlerMappings;
21+
private final transient HandlerAdapters handlerAdapters;
1722

1823
public DispatcherServlet() {
24+
this.handlerMappings = new HandlerMappings();
25+
this.handlerAdapters = new HandlerAdapters();
1926
}
2027

2128
@Override
2229
public void init() {
23-
manualHandlerMapping = new ManualHandlerMapping();
24-
manualHandlerMapping.initialize();
30+
handlerMappings.addHandlerMapping(new ManualHandlerMapping());
31+
handlerMappings.addHandlerMapping(new AnnotationHandlerMapping());
32+
handlerAdapters.addHandlerAdapter(new ManualHandlerAdapter());
33+
handlerAdapters.addHandlerAdapter(new AnnotationHandlerAdapter());
2534
}
2635

2736
@Override
2837
protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
29-
final String requestURI = request.getRequestURI();
30-
log.debug("Method : {}, Request URI : {}", request.getMethod(), requestURI);
38+
log.debug("Method : {}, Request URI : {}", request.getMethod(), request.getRequestURI());
3139

3240
try {
33-
final var controller = manualHandlerMapping.getHandler(requestURI);
34-
final var viewName = controller.execute(request, response);
35-
move(viewName, request, response);
41+
final var handler = handlerMappings.getHandler(request);
42+
final var handlerAdapter = handlerAdapters.getHandlerAdapter(handler);
43+
final ModelAndView modelAndView = handlerAdapter.handle(request, response, handler);
44+
move(modelAndView, request, response);
3645
} catch (Throwable e) {
3746
log.error("Exception : {}", e.getMessage(), e);
3847
throw new ServletException(e.getMessage());
3948
}
4049
}
4150

42-
private void move(final String viewName, final HttpServletRequest request, final HttpServletResponse response) throws Exception {
51+
private void move(final ModelAndView modelAndView, final HttpServletRequest request, final HttpServletResponse response) throws Exception {
52+
final String viewName = modelAndView.getView().getViewName();
4353
if (viewName.startsWith(JspView.REDIRECT_PREFIX)) {
4454
response.sendRedirect(viewName.substring(JspView.REDIRECT_PREFIX.length()));
4555
return;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.techcourse;
2+
3+
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapter;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
8+
public class HandlerAdapters {
9+
10+
private final List<HandlerAdapter> adapters;
11+
12+
public HandlerAdapters() {
13+
this.adapters = new ArrayList<>();
14+
}
15+
16+
public void addHandlerAdapter(final HandlerAdapter handlerAdapter) {
17+
adapters.add(handlerAdapter);
18+
}
19+
20+
public HandlerAdapter getHandlerAdapter(final Object handler) {
21+
return adapters.stream()
22+
.filter(it -> it.supports(handler))
23+
.findFirst()
24+
.orElseThrow(IllegalArgumentException::new);
25+
}
26+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.techcourse;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMapping;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.Objects;
9+
10+
public class HandlerMappings {
11+
12+
private final List<HandlerMapping> mappings;
13+
14+
public HandlerMappings() {
15+
this.mappings = new ArrayList<>();
16+
}
17+
18+
public void addHandlerMapping(final HandlerMapping handlerMapping) {
19+
handlerMapping.initialize();
20+
mappings.add(handlerMapping);
21+
}
22+
23+
public Object getHandler(final HttpServletRequest request) {
24+
return mappings.stream()
25+
.map(it -> it.getHandler(request))
26+
.filter(Objects::nonNull)
27+
.findFirst()
28+
.orElseThrow(IllegalStateException::new);
29+
}
30+
}

app/src/main/java/com/techcourse/ManualHandlerMapping.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,39 @@
11
package com.techcourse;
22

3-
import com.techcourse.controller.*;
3+
import com.techcourse.controller.LoginController;
4+
import com.techcourse.controller.LoginViewController;
5+
import com.techcourse.controller.LogoutController;
6+
import jakarta.servlet.http.HttpServletRequest;
47
import org.slf4j.Logger;
58
import org.slf4j.LoggerFactory;
69
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;
710
import webmvc.org.springframework.web.servlet.mvc.asis.ForwardController;
11+
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMapping;
812

913
import java.util.HashMap;
1014
import java.util.Map;
1115

12-
public class ManualHandlerMapping {
16+
public class ManualHandlerMapping implements HandlerMapping {
1317

1418
private static final Logger log = LoggerFactory.getLogger(ManualHandlerMapping.class);
1519

1620
private static final Map<String, Controller> controllers = new HashMap<>();
1721

22+
@Override
1823
public void initialize() {
1924
controllers.put("/", new ForwardController("/index.jsp"));
2025
controllers.put("/login", new LoginController());
2126
controllers.put("/login/view", new LoginViewController());
2227
controllers.put("/logout", new LogoutController());
23-
controllers.put("/register/view", new RegisterViewController());
24-
controllers.put("/register", new RegisterController());
2528

2629
log.info("Initialized Handler Mapping!");
2730
controllers.keySet()
2831
.forEach(path -> log.info("Path : {}, Controller : {}", path, controllers.get(path).getClass()));
2932
}
3033

31-
public Controller getHandler(final String requestURI) {
34+
@Override
35+
public Controller getHandler(final HttpServletRequest request) {
36+
final String requestURI = request.getRequestURI();
3237
log.debug("Request Mapping Uri : {}", requestURI);
3338
return controllers.get(requestURI);
3439
}

app/src/main/java/com/techcourse/controller/RegisterController.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,30 @@
22

33
import com.techcourse.domain.User;
44
import com.techcourse.repository.InMemoryUserRepository;
5+
import context.org.springframework.stereotype.Controller;
56
import jakarta.servlet.http.HttpServletRequest;
67
import jakarta.servlet.http.HttpServletResponse;
7-
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;
8+
import web.org.springframework.web.bind.annotation.RequestMapping;
9+
import web.org.springframework.web.bind.annotation.RequestMethod;
10+
import webmvc.org.springframework.web.servlet.ModelAndView;
11+
import webmvc.org.springframework.web.servlet.view.JspView;
812

9-
public class RegisterController implements Controller {
13+
@Controller
14+
public class RegisterController {
1015

11-
@Override
12-
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
16+
@RequestMapping(value = "/register", method = RequestMethod.POST)
17+
public ModelAndView save(final HttpServletRequest request, final HttpServletResponse response) {
1318
final var user = new User(2,
14-
req.getParameter("account"),
15-
req.getParameter("password"),
16-
req.getParameter("email"));
19+
request.getParameter("account"),
20+
request.getParameter("password"),
21+
request.getParameter("email"));
1722
InMemoryUserRepository.save(user);
1823

19-
return "redirect:/index.jsp";
24+
return new ModelAndView(new JspView("redirect:/index.jsp"));
25+
}
26+
27+
@RequestMapping(value = "/register/view", method = RequestMethod.GET)
28+
public ModelAndView show(final HttpServletRequest request, final HttpServletResponse response) {
29+
return new ModelAndView(new JspView("/register.jsp"));
2030
}
2131
}

app/src/main/java/com/techcourse/controller/RegisterViewController.java

Lines changed: 0 additions & 13 deletions
This file was deleted.

mvc/src/main/java/webmvc/org/springframework/web/servlet/View.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@
77

88
public interface View {
99
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
10+
11+
String getViewName();
1012
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package webmvc.org.springframework.web.servlet.mvc.asis;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
import webmvc.org.springframework.web.servlet.ModelAndView;
6+
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapter;
7+
import webmvc.org.springframework.web.servlet.view.JspView;
8+
9+
public class ManualHandlerAdapter implements HandlerAdapter {
10+
11+
@Override
12+
public boolean supports(final Object handler) {
13+
return handler instanceof Controller;
14+
}
15+
16+
@Override
17+
public ModelAndView handle(final HttpServletRequest request, final HttpServletResponse response, final Object handler)
18+
throws Exception {
19+
final var controller = (Controller) handler;
20+
final String viewName = controller.execute(request, response);
21+
return new ModelAndView(new JspView(viewName));
22+
}
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package webmvc.org.springframework.web.servlet.mvc.tobe;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
import webmvc.org.springframework.web.servlet.ModelAndView;
6+
7+
public class AnnotationHandlerAdapter implements HandlerAdapter {
8+
9+
@Override
10+
public boolean supports(final Object handler) {
11+
return handler instanceof HandlerExecution;
12+
}
13+
14+
@Override
15+
public ModelAndView handle(final HttpServletRequest request, final HttpServletResponse response, final Object handler)
16+
throws Exception {
17+
final var handlerExecution = (HandlerExecution) handler;
18+
return handlerExecution.handle(request, response);
19+
}
20+
}

mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import java.util.*;
1313
import java.util.stream.Collectors;
1414

15-
public class AnnotationHandlerMapping {
15+
public class AnnotationHandlerMapping implements HandlerMapping {
1616

1717
private static final Logger log = LoggerFactory.getLogger(AnnotationHandlerMapping.class);
1818

@@ -24,6 +24,7 @@ public AnnotationHandlerMapping(final Object... basePackage) {
2424
this.handlerExecutions = new HashMap<>();
2525
}
2626

27+
@Override
2728
public void initialize() {
2829
final var reflections = new Reflections(basePackage);
2930
final Set<Class<?>> controllerClasses = reflections.getTypesAnnotatedWith(Controller.class);
@@ -57,6 +58,7 @@ private void addHandlerExecution(final Method method, final RequestMapping reque
5758
}
5859
}
5960

61+
@Override
6062
public Object getHandler(final HttpServletRequest request) {
6163
final String requestURI = request.getRequestURI();
6264
final var requestMethod = RequestMethod.valueOf(request.getMethod());

0 commit comments

Comments
 (0)