-
Notifications
You must be signed in to change notification settings - Fork 302
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MVC 구현하기 2단계] 포이(김보준) 미션 제출합니다. (#446)
* feat: 어노테이션 기반의 HandlerMapping을 기존의 app 패키지에서 사용할 수 있도록 추가 * feat: Reflection을 통해 핸들러 매핑을 추가하도록 변경
- Loading branch information
Showing
19 changed files
with
280 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 15 additions & 8 deletions
23
app/src/main/java/com/techcourse/ManualHandlerMapping.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/DispatcherServlet.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package webmvc.org.springframework.web.servlet.mvc; | ||
|
||
import core.org.springframework.util.ReflectionUtils; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.http.HttpServlet; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
import org.reflections.Reflections; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping; | ||
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapter; | ||
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMapping; | ||
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerNotFoundException; | ||
import webmvc.org.springframework.web.servlet.view.JspView; | ||
|
||
public class DispatcherServlet extends HttpServlet { | ||
|
||
private static final long serialVersionUID = 1L; | ||
private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class); | ||
private static final String INTERNAL_BASE_PACKAGE = "webmvc.org.springframework.web.servlet.mvc"; | ||
|
||
private final Object[] externalBasePackages; | ||
private final List<HandlerMapping> handlerMappings; | ||
private final List<HandlerAdapter> handlerAdapters; | ||
|
||
public DispatcherServlet(Object... externalBasePackages) { | ||
this.externalBasePackages = externalBasePackages; | ||
this.handlerMappings = new ArrayList<>(); | ||
this.handlerAdapters = new ArrayList<>(); | ||
} | ||
|
||
@Override | ||
public void init() { | ||
final var reflections = new Reflections(externalBasePackages, INTERNAL_BASE_PACKAGE); | ||
initHandlerMappings(reflections); | ||
initHandlerAdapters(reflections); | ||
} | ||
|
||
private void initHandlerMappings(final Reflections reflections) { | ||
final var handlerMappingSubTypes = reflections.getSubTypesOf(HandlerMapping.class); | ||
addHandlerMappings(handlerMappingSubTypes); | ||
handlerMappings.forEach(HandlerMapping::initialize); | ||
} | ||
|
||
private void addHandlerMappings(final Set<Class<? extends HandlerMapping>> handlerMappingSubTypes) { | ||
for (final var handlerMappingSubType : handlerMappingSubTypes) { | ||
if (handlerMappingSubType.isInterface()) { | ||
continue; | ||
} | ||
// exclude pre-defined handler mapping | ||
if (handlerMappingSubType.equals(AnnotationHandlerMapping.class)) { | ||
handlerMappings.add(new AnnotationHandlerMapping(externalBasePackages)); | ||
continue; | ||
} | ||
handlerMappings.add(ReflectionUtils.instantiate(handlerMappingSubType)); | ||
} | ||
} | ||
|
||
private void initHandlerAdapters(final Reflections reflections) { | ||
final var handlerAdapterSubTypes = reflections.getSubTypesOf(HandlerAdapter.class); | ||
addHandlerAdapters(handlerAdapterSubTypes); | ||
} | ||
|
||
private void addHandlerAdapters(final Set<Class<? extends HandlerAdapter>> handlerAdapterSubTypes) { | ||
for (final var reflectionsSubTypeOf : handlerAdapterSubTypes) { | ||
if (reflectionsSubTypeOf.isInterface()) { | ||
continue; | ||
} | ||
handlerAdapters.add(ReflectionUtils.instantiate(reflectionsSubTypeOf)); | ||
} | ||
} | ||
|
||
@Override | ||
protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException { | ||
log.debug("Method : {}, Request URI : {}", request.getMethod(), request.getRequestURI()); | ||
final var handler = getHandler(request); | ||
final var handlerAdapter = getHandlerAdapter(handler); | ||
try { | ||
final var modelAndView = handlerAdapter.handle(request, response, handler); | ||
move(modelAndView.getViewName(), 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(mapping -> mapping.getHandler(request)) | ||
.filter(Objects::nonNull) | ||
.findAny() | ||
.orElseThrow(() -> new HandlerNotFoundException("Not found handler for request URI : " + request.getRequestURI())); | ||
} | ||
|
||
private HandlerAdapter getHandlerAdapter(final Object handler) { | ||
return handlerAdapters.stream() | ||
.filter(adapter -> adapter.supports(handler)) | ||
.findAny() | ||
.orElseThrow(() -> new HandlerNotFoundException("Not found handler adapter for handler : " + handler)); | ||
} | ||
|
||
private void move(final String viewName, final HttpServletRequest request, final HttpServletResponse response) throws Exception { | ||
if (viewName.startsWith(JspView.REDIRECT_PREFIX)) { | ||
response.sendRedirect(viewName.substring(JspView.REDIRECT_PREFIX.length())); | ||
return; | ||
} | ||
|
||
final var requestDispatcher = request.getRequestDispatcher(viewName); | ||
requestDispatcher.forward(request, response); | ||
} | ||
} |
Oops, something went wrong.