-
Notifications
You must be signed in to change notification settings - Fork 304
[MVC 구현하기 - 2단계] 리비(이근희) 미션 제출합니다. #779
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
Changes from all commits
a63c0b4
72d2c84
a7b85bf
b88810f
396230b
7afb900
cfb38ea
9c2d0ca
a45941e
c00a55e
b872375
e708747
60da14b
24b4318
16f7583
973cb28
89e7045
92dc9ee
e572cfc
a1fe327
f1705f1
c037eaf
0e4f6f3
636b21f
84e7424
3ea2fba
7575bb6
df3008c
a9de050
6258284
723f5c4
f159ffe
7ed1d12
fea477e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,35 @@ | ||
package com.techcourse.controller; | ||
|
||
import com.interface21.web.bind.annotation.RequestMapping; | ||
import com.interface21.web.bind.annotation.RequestMethod; | ||
import com.interface21.webmvc.servlet.ModelAndView; | ||
import com.interface21.webmvc.servlet.View; | ||
import com.interface21.webmvc.servlet.view.JspView; | ||
import com.techcourse.domain.User; | ||
import com.techcourse.repository.InMemoryUserRepository; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import com.interface21.webmvc.servlet.mvc.asis.Controller; | ||
|
||
public class RegisterController implements Controller { | ||
@com.interface21.context.stereotype.Controller | ||
public class RegisterController { | ||
|
||
@Override | ||
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { | ||
private static final String REGISTER_JSP = "/register.jsp"; | ||
|
||
@RequestMapping(value = "/register", method = RequestMethod.GET) | ||
public ModelAndView registerPage(final HttpServletRequest req, final HttpServletResponse res) { | ||
JspView jspView = new JspView(REGISTER_JSP); | ||
return new ModelAndView(jspView); | ||
} | ||
|
||
@RequestMapping(value = "/register", method = RequestMethod.POST) | ||
public ModelAndView registerUser(final HttpServletRequest req, final HttpServletResponse res) { | ||
final var user = new User(2, | ||
req.getParameter("account"), | ||
req.getParameter("password"), | ||
req.getParameter("email")); | ||
InMemoryUserRepository.save(user); | ||
|
||
return "redirect:/index.jsp"; | ||
View view = new JspView("redirect:/index.jsp"); | ||
return new ModelAndView(view); | ||
Comment on lines
+32
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재는 이 부분을 웹 개발자가 직접 처리해야 하지만, 나중에 이 코드의 제어도 프레임워크가 역전할 수 있겠네요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아루처럼 한스텝씩 개발자의 편의사항을 위한 프레임워크를 고려하다 보면 결국 스프링의 구현에 가까워진다는 것이 너무 신기해요..! 별생각 없이 넘어갔던 부분인데 좋은 인사이트 주셔서 감사해요~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제어의 역전의 대표적인 예시로 프레임워크를 말할 수 있다면, 미션을 잘 해나간 것이라고 생각해요 🚀 |
||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,25 +2,28 @@ | |
|
||
import com.interface21.context.stereotype.Controller; | ||
import com.interface21.webmvc.servlet.exception.ControllerScanException; | ||
import java.lang.annotation.Annotation; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import org.reflections.Reflections; | ||
|
||
public class ControllerScanner { | ||
|
||
private static final Class<? extends Annotation> CONTROLLER_ANNOTATION = Controller.class; | ||
|
||
private final Object[] basePackage; | ||
private final Map<Class<?>, Object> controllers = new ConcurrentHashMap(); | ||
private final Map<Class<?>, Object> controllers = new HashMap<>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (스프링에서 병렬적으로 빈을 등록하면 어떨까? 에 대한 이슈도 10년 전에 올라왔었습니다 ㅎㅎ) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 많은 빈을 운용하는 경우 Spring 애플리케이션의 시작 시간이 점점 느려지고 있어 이슈를 열었던 사람이 있군요! 현재 스프링에서 병렬적으로 빈을 등록하지는 않고 백그라운드 작업등을 제공하고 있는 것으로 확인했어요~ |
||
|
||
public ControllerScanner(Object... basePackage) { | ||
this.basePackage = basePackage; | ||
scanControllers(); | ||
scanController(); | ||
} | ||
|
||
private void scanControllers() { | ||
private void scanController() { | ||
Reflections reflections = new Reflections(basePackage); | ||
Set<Class<?>> annotatedControllerTypes = reflections.getTypesAnnotatedWith(Controller.class); | ||
annotatedControllerTypes.forEach(this::addController); | ||
reflections.getTypesAnnotatedWith(CONTROLLER_ANNOTATION) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 어떤 대상을 스캔하는지 클래스 상단에서 보이면 좋겠다고 생각했어요..! |
||
.forEach(this::addController); | ||
} | ||
|
||
private void addController(Class<?> annotatedControllerType) { | ||
|
@@ -33,6 +36,6 @@ private void addController(Class<?> annotatedControllerType) { | |
} | ||
|
||
public Map<Class<?>, Object> getControllers() { | ||
return controllers; | ||
return Collections.unmodifiableMap(controllers); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍🏻 |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.interface21.webmvc.servlet.mvc.tobe.adapter; | ||
|
||
import com.interface21.webmvc.servlet.ModelAndView; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
|
||
public interface HandlerAdapter { | ||
|
||
boolean supports(Object handler); | ||
|
||
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.interface21.webmvc.servlet.mvc.tobe.adapter; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.NoSuchElementException; | ||
|
||
public class HandlerAdapterRegistry { | ||
|
||
private final List<HandlerAdapter> handlerAdapters = new ArrayList<>(); | ||
|
||
public HandlerAdapterRegistry() { | ||
} | ||
|
||
public void addHandlerAdapter(HandlerAdapter handlerAdapter) { | ||
handlerAdapters.add(handlerAdapter); | ||
} | ||
|
||
public HandlerAdapter getHandlerAdapter(Object handler) { | ||
return handlerAdapters.stream() | ||
.filter(handlerAdapter -> handlerAdapter.supports(handler)) | ||
.findFirst() | ||
.orElseThrow(() -> new NoSuchElementException("핸들러를 처리할 수 있는 Adapter를 찾지 못했습니다")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 재밌는 관점이네요~ 저는 핸들러를 찾는 쪽에서 직접 예외를 터뜨리는 게 낫다고 생각합니다. 그걸 호출하는 쪽에서 null을 잡는다면 객체의 책임이 분산된 결과 아닐까요!? 아루의 구현도 확인했는데요~ 아루는 저와 다른 생각을 하고 계신 것 같아요..! (추가적으로 스프링도 아루와 비슷한 생각을 한 것 같아요!) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ㅎㅎㅎ 저는
저는 개인적으로 객체 스스로간의 응집도를 조금 내려두고, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아루가 말씀하신 것처럼 하나의 메서드를 읽기 위해 여러 클래스의 명세를 참고해야 한다면 유지보수 비용이 있을 수 있겠습니다.. 다만 아직까지 저는 null 여부에 따른 분기를 선호하진 않아서 현행 유지하고자 합니다. |
||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.interface21.webmvc.servlet.mvc.tobe.adapter; | ||
|
||
import com.interface21.webmvc.servlet.ModelAndView; | ||
import com.interface21.webmvc.servlet.mvc.asis.Controller; | ||
import com.interface21.webmvc.servlet.view.JspView; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
|
||
public class ManualHandlerAdapter implements HandlerAdapter { | ||
|
||
@Override | ||
public boolean supports(Object handler) { | ||
return handler instanceof Controller; | ||
} | ||
|
||
@Override | ||
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) | ||
throws Exception { | ||
String viewName = ((Controller) handler).execute(request, response); | ||
JspView jspView = new JspView(viewName); | ||
return new ModelAndView(jspView); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.interface21.webmvc.servlet.mvc.tobe.adapter; | ||
|
||
import com.interface21.webmvc.servlet.ModelAndView; | ||
import com.interface21.webmvc.servlet.mvc.tobe.HandlerExecution; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
|
||
public class RequestMappingHandlerAdapter implements HandlerAdapter { | ||
|
||
@Override | ||
public boolean supports(Object handler) { | ||
return handler instanceof HandlerExecution; | ||
} | ||
|
||
@Override | ||
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) | ||
throws Exception { | ||
HandlerExecution handlerExecution = (HandlerExecution) handler; | ||
return handlerExecution.handle(request, response); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(생각해볼 점)
DispatcherServlet
은 우리가mvc
프레임워크에서 담당하는 것으로 알고 있죠. 왜 지금은 해당 파일을 프레임워크 패키지가 아니라, 웹 개발자가 다루는 패키지에 두었을까요?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
결국 웹개발자가 만들고 있는 것은 DispatcherServlet이라고 생각합니다~
저희가 만든 DispatcherServlet이 톰캣의 서블릿 컨테이너에 배포됨으로써 웹 서버가 동작하는 것이죠.
이와 같은 흐름으로 볼 때 DispatcherServlet을 클라이언트가 만드는 것이 위화감 없다는 것이 제 생각이에요!
다만 스프링에서 만든 mvc프레임워크는 저희의 코드로부터 DispatcherServlet을 만드는 과정을 추상화해놓았습니다.
때문에 지금까지 저희가 이와 같은 형태의 코드를 만나보지 못했던 것일테죠!
결론
제 결론은 이런데 어색한 부분이 있다면 아루가 코멘트 더해주시면 감사하겠습니다~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
거의 일치합니다 👍🏻 웹 개발자는 자신이 비즈니스 로직이 아닌 부분까지 구현하고 싶지 않았고, 그래서
DispatcherServlet
을 만들어 모든 처리를 위임했다고 볼 수도 있겠네요. 아직은 제어 권한이 웹 개발자에게 있다는 이야기군요! 💯