Skip to content

Commit

Permalink
[MVC 구현하기 - 2단계] 유콩(김유빈) 미션 제출합니다 (#251)
Browse files Browse the repository at this point in the history
* docs: 2단계 체크리스트 작성

* refactor: controller 패키지 이동

* refactor: mapping 과 adapter 패키지 분리

* feat: ControllerScanner 로 @controller 붙은 객체 조회

* feat: HandlerMappingRegistry 에서 HandlerMapping 처리

* feat: HandlerAdapterRegistry 에서 HandlerAdapter 처리

* test: 요청 및 응답 객체 픽스쳐 생성

* refactor: final 키워드 추가 및 불필요한 선언 삭제

* refactor: BDDMockito 메서드로 변경

* refactor: 테스트에서만 사용하는 생성자 제거

* refactor: getter 가 아닌 메서드 이용하여 render

* refactor: 에러메시지 변경
  • Loading branch information
kyukong authored Sep 26, 2022
1 parent 16b867b commit 5ffd82c
Show file tree
Hide file tree
Showing 33 changed files with 450 additions and 188 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@
## 🚀 1단계 - @MVC 프레임워크 구현하기
- [x] AnnotationHandlerMappingTest가 정상 동작한다.
- [x] DispatcherServlet에서 HandlerMapping 인터페이스를 활용하여 AnnotationHandlerMapping과 ManualHandlerMapping 둘다 처리할 수 있다.

## 🚀 2단계 - 점진적인 리팩터링
- [x] ControllerScanner 클래스에서 @Controller가 붙은 클래스를 찾을 수 있다.
- [x] HandlerMappingRegistry 클래스에서 HandlerMapping을 처리하도록 구현했다.
- [x] HandlerAdapterRegistry 클래스에서 HandlerAdapter를 처리하도록 구현했다.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import jakarta.servlet.ServletContext;
import nextstep.mvc.DispatcherServlet;
import nextstep.mvc.controller.tobe.AnnotationHandlerAdapter;
import nextstep.mvc.controller.tobe.AnnotationHandlerMapping;
import nextstep.mvc.handleradapter.AnnotationHandlerAdapter;
import nextstep.mvc.handleradapter.ManualHandlerAdapter;
import nextstep.mvc.handlermapping.AnnotationHandlerMapping;
import nextstep.web.WebApplicationInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/com/techcourse/ManualHandlerMapping.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import com.techcourse.controller.*;
import jakarta.servlet.http.HttpServletRequest;
import nextstep.mvc.HandlerMapping;
import nextstep.mvc.controller.asis.Controller;
import nextstep.mvc.controller.asis.ForwardController;
import nextstep.mvc.handlermapping.HandlerMapping;
import nextstep.mvc.controller.Controller;
import com.techcourse.controller.ForwardController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package nextstep.mvc.controller.asis;
package com.techcourse.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.controller.Controller;

import java.util.Objects;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.techcourse.repository.InMemoryUserRepository;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.controller.asis.Controller;
import nextstep.mvc.controller.Controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.controller.asis.Controller;
import nextstep.mvc.controller.Controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.controller.asis.Controller;
import nextstep.mvc.controller.Controller;

public class LogoutController implements Controller {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.techcourse.repository.InMemoryUserRepository;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.controller.asis.Controller;
import nextstep.mvc.controller.Controller;

public class RegisterController implements Controller {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.controller.asis.Controller;
import nextstep.mvc.controller.Controller;

public class RegisterViewController implements Controller {

Expand Down
50 changes: 12 additions & 38 deletions mvc/src/main/java/nextstep/mvc/DispatcherServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,33 @@
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.handleradapter.HandlerAdapter;
import nextstep.mvc.handleradapter.HandlerAdapterRegistry;
import nextstep.mvc.handlermapping.HandlerMapping;
import nextstep.mvc.handlermapping.HandlerMappingRegistry;
import nextstep.mvc.view.ModelAndView;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class DispatcherServlet extends HttpServlet {

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

private final List<HandlerMapping> handlerMappings;
private final List<HandlerAdapter> handlerAdapters;
private final HandlerMappingRegistry handlerMappings;
private final HandlerAdapterRegistry handlerAdapters;

public DispatcherServlet() {
this.handlerMappings = new ArrayList<>();
this.handlerAdapters = new ArrayList<>();
this.handlerMappings = new HandlerMappingRegistry();
this.handlerAdapters = new HandlerAdapterRegistry();
}

@Override
public void init() {
handlerMappings.forEach(HandlerMapping::initialize);
handlerMappings.init();
}

public void addHandlerMapping(final HandlerMapping handlerMapping) {
Expand All @@ -45,39 +46,12 @@ protected void service(final HttpServletRequest request, final HttpServletRespon
log.debug("Method : {}, Request URI : {}", request.getMethod(), request.getRequestURI());

try {
final Object handler = getHandler(request);
final ModelAndView modelAndView = getModelAndView(handler, request, response);
final Map<String, Object> model = modelAndView.getModel();
modelAndView.getView().render(model, request, response);
final Object handler = handlerMappings.getHandler(request);
final ModelAndView modelAndView = handlerAdapters.getModelAndView(handler, request, response);
modelAndView.render(request, response);
} catch (Throwable e) {
log.error("Exception : {}", e.getMessage(), e);
throw new ServletException(e.getMessage());
}
}

private Object getHandler(final HttpServletRequest request) {
return handlerMappings.stream()
.map(handlerMapping -> handlerMapping.getHandler(request))
.filter(Objects::nonNull)
.findFirst()
.orElseThrow();
}

private ModelAndView getModelAndView(final Object handler, final HttpServletRequest request, final HttpServletResponse response) {
return handlerAdapters.stream()
.filter(handlerAdapter -> handlerAdapter.supports(handler))
.map(handlerAdapter -> getModelAndView(handler, request, response, handlerAdapter))
.findFirst()
.orElseThrow();
}

private ModelAndView getModelAndView(final Object handler,
final HttpServletRequest request, final HttpServletResponse response, final HandlerAdapter handlerAdapter
){
try {
return handlerAdapter.handle(request, response, handler);
} catch (Exception e) {
throw new IllegalArgumentException(String.format("적절하지 않은 handler 입니다. [%s]", handler));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package nextstep.mvc.controller.asis;
package nextstep.mvc.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand Down
41 changes: 41 additions & 0 deletions mvc/src/main/java/nextstep/mvc/controller/ControllerScanner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package nextstep.mvc.controller;

import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import nextstep.web.annotation.Controller;

public class ControllerScanner {

private static final Logger log = LoggerFactory.getLogger(ControllerScanner.class);

private ControllerScanner() {
}

public static Map<Class<?>, Object> getControllers(final Object... basePackage) {
final Reflections reflections = new Reflections(basePackage);
final Set<Class<?>> controllers = reflections.getTypesAnnotatedWith(Controller.class);

return controllers.stream()
.collect(Collectors.toMap(
Function.identity(),
ControllerScanner::initController
));
}

private static Object initController(final Class<?> clazz) {
try {
return clazz.getDeclaredConstructors()[0]
.newInstance();
} catch (Exception e) {
log.error(e.getMessage());
throw new IllegalArgumentException(String.format("생성자가 존재하지 않습니다. [%s]", clazz.getName()));
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package nextstep.mvc.controller.tobe;
package nextstep.mvc.handleradapter;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.HandlerAdapter;
import nextstep.mvc.handlermapping.HandlerExecution;
import nextstep.mvc.view.ModelAndView;
import nextstep.web.annotation.Controller;

public class AnnotationHandlerAdapter implements HandlerAdapter {

@Override
public boolean supports(final Object handler) {
return handler.getClass().isAnnotationPresent(Controller.class);
return handler instanceof HandlerExecution;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package nextstep.mvc;
package nextstep.mvc.handleradapter;

import nextstep.mvc.view.ModelAndView;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package nextstep.mvc.handleradapter;

import java.util.ArrayList;
import java.util.List;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.view.ModelAndView;

public class HandlerAdapterRegistry {

private final List<HandlerAdapter> handlerAdapters;

public HandlerAdapterRegistry() {
this.handlerAdapters = new ArrayList<>();
}

public void add(final HandlerAdapter handlerAdapter) {
handlerAdapters.add(handlerAdapter);
}

public ModelAndView getModelAndView(final Object handler, final HttpServletRequest request, final HttpServletResponse response) {
return handlerAdapters.stream()
.filter(handlerAdapter -> handlerAdapter.supports(handler))
.map(handlerAdapter -> getModelAndView(handler, request, response, handlerAdapter))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(String.format("적절한 handler 가 존재하지 않습니다. [%s]", handler)));
}

private ModelAndView getModelAndView(final Object handler,
final HttpServletRequest request, final HttpServletResponse response, final HandlerAdapter handlerAdapter
){
try {
return handlerAdapter.handle(request, response, handler);
} catch (Exception e) {
throw new IllegalArgumentException(e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.techcourse;
package nextstep.mvc.handleradapter;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nextstep.mvc.HandlerAdapter;
import nextstep.mvc.controller.asis.Controller;
import nextstep.mvc.controller.Controller;
import nextstep.mvc.view.ModelAndView;

public class ManualHandlerAdapter implements HandlerAdapter {
Expand Down
Loading

0 comments on commit 5ffd82c

Please sign in to comment.