Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MVC - Step 2] 베디 미션 제출합니다 #54

Merged
merged 29 commits into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2de338c
feat: JsonView
dpudpu Oct 8, 2019
ce08dea
feat: jackson 학습테스트 Object to Map
dpudpu Oct 8, 2019
53bef85
feat: WebRequest - request, response 관리
dpudpu Oct 8, 2019
067f43b
refactor: resolver, adapter - Request 대신 WebRequest 가지게 변경
dpudpu Oct 8, 2019
d45916a
feat: json 처리용 ResponseBody 추가
dpudpu Oct 8, 2019
7090de7
feat: RequestBodyAdapter
dpudpu Oct 8, 2019
77a8905
feat: RequestBodyMethodArgumentResolver
dpudpu Oct 8, 2019
7b65385
feat: UserApiController (json으로 회원가입, 조회, 수정)
dpudpu Oct 8, 2019
9b5b650
feat: 요구사항 2단계 완료 (레거시 코드 없이도 돌아가게 하기)
dpudpu Oct 8, 2019
5c9bed2
refactor: rename HttpServletHandlerMethodArgumentResolver -> HttpServ…
dpudpu Oct 8, 2019
66cf7b3
feat: ViewResolver, View 구현 및 적용
dpudpu Oct 8, 2019
dad9448
refactor: ViewResolver 구현에 따른 Controller viewName suffix 제거
dpudpu Oct 8, 2019
ac2a4fd
refactor: MethodParameter getAnnotation() 추가 (캡슐화)
dpudpu Oct 8, 2019
c1e086f
refactor: DefaultHandlerMethodArgumentResolver - 두개로 나눔
dpudpu Oct 8, 2019
d88b0f9
style: 포맷팅
dpudpu Oct 8, 2019
aedf578
docs: update README.md
dpudpu Oct 8, 2019
6710694
feat: AbstractRequestMappingAdapter
dpudpu Oct 8, 2019
2f6a602
style: JsonView 불필요한 주석 제거
dpudpu Oct 8, 2019
44342f4
refactor: ObjectMethodArgumentResolver 기본 생성자로만 매핑하게 변경
dpudpu Oct 9, 2019
09c5dcc
refactor: AbstractRequestMappingAdapter - RequestMappingAdapter 상속으로 변경
dpudpu Oct 9, 2019
52c24cd
feat: HandlerInterceptor
dpudpu Oct 9, 2019
ac3adfd
feat: InterceptorRegistration
dpudpu Oct 9, 2019
6f370a3
feat: InterceptorRegistry
dpudpu Oct 9, 2019
1de15eb
fix: ObjectMethodArgumentResolver private 기본생성자도 생성가능하게 변경
dpudpu Oct 9, 2019
585649b
fix: JspView.render() model 값 setAttribute에 추가
dpudpu Oct 9, 2019
050131e
feat: Interceptor DispatcherServlet 에 적용
dpudpu Oct 9, 2019
bbdb6e3
feat: MeasuringInterceptor - Controller 성능측적 미션 완료
dpudpu Oct 9, 2019
607c519
feat: LoginInterceptor
dpudpu Oct 9, 2019
1479768
docs: update README.md
dpudpu Oct 9, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
- [x] DispatcherServlet 에 적용하기
- [ ] 성능 측정 ServletFilter 구현해보기
- [x] /users/{id} - url 요청 가능하게 하기

- [ ] handlerMappings, adapters 등.. 포장하기
- [x] 모든 클래스 이름 점검 (ex. HandlerMethodArgumentResolver)
- [ ] ResponseEntity 직접 구현하기
## 추가 미션
- [ ] 다른 템플릿 엔진 지원하기
- [ ] 인터셉터 구현하기
Expand Down
49 changes: 31 additions & 18 deletions nextstep-mvc/src/main/java/nextstep/mvc/DispatcherServlet.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package nextstep.mvc;

import nextstep.mvc.tobe.exception.HandlerAdapterNotSupportedException;
import nextstep.mvc.tobe.exception.HandlerNotFoundException;
import nextstep.mvc.tobe.ModelAndView;
import nextstep.mvc.tobe.WebRequest;
import nextstep.mvc.tobe.WebRequestContext;
import nextstep.mvc.tobe.adapter.HandlerAdapter;
import nextstep.mvc.tobe.adapter.HandlerExecutionAdapter;
import nextstep.mvc.tobe.ModelAndView;
import nextstep.mvc.tobe.adapter.ResponseBodyAdapter;
import nextstep.mvc.tobe.adapter.SimpleControllerAdapter;
import nextstep.mvc.tobe.exception.HandlerAdapterNotSupportedException;
import nextstep.mvc.tobe.exception.HandlerNotFoundException;
import nextstep.mvc.tobe.mapping.HandlerMapping;
import nextstep.mvc.tobe.view.View;
import nextstep.mvc.tobe.viewresolver.ViewResolver;
import nextstep.mvc.tobe.viewresolver.ViewResolverManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
Expand All @@ -28,40 +33,46 @@
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);
private static final String DEFAULT_REDIRECT_PREFIX = "redirect:";

private List<HandlerMapping> handlerMappings;
private List<HandlerAdapter> handlerAdapters;
private ViewResolverManager viewResolverManager;

public DispatcherServlet(HandlerMapping... handlerMappings) {
this.handlerMappings = Arrays.asList(handlerMappings);
this.handlerAdapters = Arrays.asList(new SimpleControllerAdapter(), new HandlerExecutionAdapter());
this.handlerAdapters = Arrays.asList(new SimpleControllerAdapter(), new ResponseBodyAdapter(), new HandlerExecutionAdapter());
this.viewResolverManager = new ViewResolverManager();
}

@Override
public void init() throws ServletException {
if (handlerMappings.isEmpty()) {
throw new IllegalArgumentException("HandlerMapping 은 최소한 하나는 있어야 합니다.");
}
handlerMappings.forEach(HandlerMapping::initialize);
}

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
logger.debug("Method : {}, Request URI : {}", req.getMethod(), req.getRequestURI());
final WebRequest webRequest = new WebRequestContext(req, resp);

final Object handler = getHandler(req);

final HandlerAdapter handlerAdapter = getHandlerAdapter(handler);

final ModelAndView mav = handlerAdapter.handle(req, resp, handler);
final ModelAndView mav = handlerAdapter.handle(webRequest, handler);

// TODO ViewResolver (2단계)
move(mav, req, resp);
final View view = viewResolverManager.resolveView(mav.getView());

view.render(mav.getModel(), req, resp);

} catch (HandlerNotFoundException e) {
logger.error("not support uri: {} ", req.getRequestURI());
resp.sendError(SC_NOT_FOUND);
} catch (Exception e) {
logger.error(e.getMessage());
logger.error("Exception: {}", e.getMessage());
resp.sendError(SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
}
Expand All @@ -81,13 +92,15 @@ private HandlerAdapter getHandlerAdapter(final Object handler) {
.orElseThrow(HandlerAdapterNotSupportedException::new);
}

private void move(ModelAndView mav, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
final String viewName = mav.getViewName();
if (viewName.startsWith(DEFAULT_REDIRECT_PREFIX)) {
resp.sendRedirect(viewName.substring(DEFAULT_REDIRECT_PREFIX.length()));
return;
}
RequestDispatcher rd = req.getRequestDispatcher(viewName);
rd.forward(req, resp);
public void addHandlerMapping(final HandlerMapping handlerMapping) {
handlerMappings.add(handlerMapping);
}

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

public void addViewResolver(final ViewResolver viewResolver) {
viewResolverManager.addViewResolver(viewResolver);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public Map<String, Object> getModel() {
return Collections.unmodifiableMap(model);
}

public View getView() {
return view instanceof View ? (View) view : null;
public Object getView() {
return view;
}

public String getViewName() {
Expand Down
12 changes: 12 additions & 0 deletions nextstep-mvc/src/main/java/nextstep/mvc/tobe/WebRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package nextstep.mvc.tobe;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface WebRequest {
HttpServletRequest getRequest();

HttpServletResponse getResponse();

String getRequestURI();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package nextstep.mvc.tobe;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class WebRequestContext implements WebRequest {
private final HttpServletRequest req;
private final HttpServletResponse resp;

public WebRequestContext(final HttpServletRequest req, final HttpServletResponse resp) {
this.req = req;
this.resp = resp;
}

@Override
public HttpServletRequest getRequest() {
return req;
}

@Override
public HttpServletResponse getResponse() {
return resp;
}

@Override
public String getRequestURI() {
return req.getRequestURI();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package nextstep.mvc.tobe.adapter;

import nextstep.mvc.tobe.ModelAndView;
import nextstep.mvc.tobe.WebRequest;
import nextstep.mvc.tobe.handler.HandlerExecution;
import nextstep.mvc.tobe.resolver.HandlerMethodArgumentResolverComposite;
import nextstep.mvc.tobe.resolver.MethodParameters;

public abstract class AbstractRequestMappingAdapter implements HandlerAdapter {
private HandlerMethodArgumentResolverComposite argumentResolvers;

public AbstractRequestMappingAdapter() {
argumentResolvers = HandlerMethodArgumentResolverComposite.getInstance();
}

@Override
public ModelAndView handle(final WebRequest webRequest, final Object handler) throws Exception {
final HandlerExecution handlerExecution = (HandlerExecution) handler;
final MethodParameters methodParameters = new MethodParameters(handlerExecution.getMethod());

final Object[] values = methodParameters.getMethodParams().stream()
.map(parameter -> argumentResolvers.resolveArgument(webRequest, parameter))
.toArray();

final Object result = handlerExecution.execute(values);

return resolveReturn(result);
}

protected abstract ModelAndView resolveReturn(final Object result);


}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package nextstep.mvc.tobe.adapter;

import nextstep.mvc.tobe.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import nextstep.mvc.tobe.WebRequest;

public interface HandlerAdapter {
ModelAndView handle(final HttpServletRequest req, final HttpServletResponse resp, final Object handler) throws Exception;
ModelAndView handle(final WebRequest webRequest, final Object handler) throws Exception;

boolean supports(final Object handler);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,11 @@

import nextstep.mvc.tobe.ModelAndView;
import nextstep.mvc.tobe.handler.HandlerExecution;
import nextstep.mvc.tobe.resolver.HandlerMethodArgumentResolverComposite;
import nextstep.mvc.tobe.resolver.MethodParameters;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HandlerExecutionAdapter implements HandlerAdapter {
private HandlerMethodArgumentResolverComposite argumentResolvers;

public HandlerExecutionAdapter() {
argumentResolvers = new HandlerMethodArgumentResolverComposite();
}
public class HandlerExecutionAdapter extends AbstractRequestMappingAdapter {

@Override
public ModelAndView handle(final HttpServletRequest req, final HttpServletResponse resp, final Object handler) throws Exception {
final HandlerExecution handlerExecution = (HandlerExecution) handler;
final MethodParameters methodParameters = new MethodParameters(handlerExecution.getMethod());

final Object[] values = methodParameters.getMethodParams().stream()
.map(parameter -> {
if (parameter.isSameType(HttpServletRequest.class)) {
return req;
}
if (parameter.isSameType(HttpServletResponse.class)) {
return resp;
}
return argumentResolvers.resolveArgument(req, parameter);
})
.toArray();

final Object result = handlerExecution.execute(values);

return parseModelAndView(result);
}

private ModelAndView parseModelAndView(final Object result) {
protected ModelAndView resolveReturn(final Object result) {
if (result instanceof String) {
return new ModelAndView(String.valueOf(result));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package nextstep.mvc.tobe.adapter;

public interface RequestMappingAdapter extends HandlerAdapter {
ssosso marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package nextstep.mvc.tobe.adapter;

import nextstep.mvc.tobe.ModelAndView;
import nextstep.mvc.tobe.handler.HandlerExecution;
import nextstep.mvc.tobe.view.JsonView;
import nextstep.web.annotation.ResponseBody;

public class ResponseBodyAdapter extends AbstractRequestMappingAdapter {

@Override
protected ModelAndView resolveReturn(final Object result) {
return new ModelAndView(new JsonView(result));
}

@Override
public boolean supports(final Object handler) {
return ((HandlerExecution) handler).isAnnotationPresent(ResponseBody.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@

import nextstep.mvc.asis.Controller;
import nextstep.mvc.tobe.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import nextstep.mvc.tobe.WebRequest;

public class SimpleControllerAdapter implements HandlerAdapter {

@Override
public ModelAndView handle(final HttpServletRequest req, final HttpServletResponse resp, final Object handler) throws Exception {
public ModelAndView handle(final WebRequest webRequest, final Object handler) throws Exception {
final Controller controller = (Controller) handler;
final String viewName = String.valueOf((controller.execute(req, resp)));
final String viewName = String.valueOf((controller.execute(webRequest.getRequest(), webRequest.getResponse())));
return new ModelAndView(viewName);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package nextstep.mvc.tobe.exception;

public class RequestBodyMethodArgumentResolverException extends RuntimeException {
public RequestBodyMethodArgumentResolverException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nextstep.mvc.tobe.handler;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
Expand All @@ -24,4 +25,8 @@ public Parameter[] getParameters() {
public Method getMethod() {
return method;
}

public boolean isAnnotationPresent(final Class<? extends Annotation> annotation) {
return method.isAnnotationPresent(annotation);
}
}
Loading