From dd7d7de946b6915f1d1652e0ba02ac2145d579dc Mon Sep 17 00:00:00 2001 From: DEOKWOO KIM Date: Wed, 27 Sep 2023 13:56:21 +0900 Subject: [PATCH] =?UTF-8?q?[MVC=EA=B5=AC=ED=98=84=20/=203=EB=8B=A8?= =?UTF-8?q?=EA=B3=84]=20=EB=A1=9C=EC=9D=B4(=EA=B9=80=EB=8D=95=EC=9A=B0)=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20=EC=A0=9C=EC=B6=9C=ED=95=A9=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.=20(#631)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: JspView 클래스 구현 및 DispatcherServlet 로직 수정 * feat: JsonView 클래스 구현 및 MediaType 추가 * feat: legacy mvc 제거 및 legacy 컨트롤러 어노테이션 기반으로 변경 * feat: stream을 적용하여 메서드 로직 변경(망고 피드백 반영) * refactor: DispatcherServletInitializer 패키지 변경 --- .../DispatcherServletInitializer.java | 3 +- .../com/techcourse/ManualHandlerAdapter.java | 24 ------------ .../com/techcourse/ManualHandlerMapping.java | 39 ------------------- .../controller/LoginController.java | 30 +++++++------- .../controller/LoginViewController.java | 17 +++++--- .../controller/LogoutController.java | 15 ++++--- .../controller/RegisterController.java | 15 ++++--- .../controller/RegisterViewController.java | 15 ++++--- .../org/springframework/http/MediaType.java | 1 + .../web/servlet}/DispatcherServlet.java | 18 ++------- .../web/servlet/mvc/asis/Controller.java | 8 ---- .../servlet/mvc/asis/ForwardController.java | 20 ---------- .../mvc/tobe/HandlerAdapterRegistry.java | 10 ++--- .../web/servlet/view/JsonView.java | 15 +++++++ .../web/servlet/view/JspView.java | 19 +++++---- 15 files changed, 94 insertions(+), 155 deletions(-) delete mode 100644 app/src/main/java/com/techcourse/ManualHandlerAdapter.java delete mode 100644 app/src/main/java/com/techcourse/ManualHandlerMapping.java rename {app/src/main/java/com/techcourse => mvc/src/main/java/webmvc/org/springframework/web/servlet}/DispatcherServlet.java (75%) delete mode 100644 mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java delete mode 100644 mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java diff --git a/app/src/main/java/com/techcourse/DispatcherServletInitializer.java b/app/src/main/java/com/techcourse/DispatcherServletInitializer.java index ba6abbfcf1..fe9b5b1a6c 100644 --- a/app/src/main/java/com/techcourse/DispatcherServletInitializer.java +++ b/app/src/main/java/com/techcourse/DispatcherServletInitializer.java @@ -4,6 +4,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import web.org.springframework.web.WebApplicationInitializer; +import webmvc.org.springframework.web.servlet.DispatcherServlet; import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerAdapter; import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping; @@ -22,10 +23,8 @@ public void onStartup(final ServletContext servletContext) { final var dispatcherServlet = new DispatcherServlet(); dispatcherServlet.addHandlerMapping(new AnnotationHandlerMapping("com.techcourse")); - dispatcherServlet.addHandlerMapping(new ManualHandlerMapping()); dispatcherServlet.addHandlerAdapter(new AnnotationHandlerAdapter()); - dispatcherServlet.addHandlerAdapter(new ManualHandlerAdapter()); dispatcherServlet.init(); diff --git a/app/src/main/java/com/techcourse/ManualHandlerAdapter.java b/app/src/main/java/com/techcourse/ManualHandlerAdapter.java deleted file mode 100644 index b65357d88b..0000000000 --- a/app/src/main/java/com/techcourse/ManualHandlerAdapter.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.techcourse; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapter; -import webmvc.org.springframework.web.servlet.view.JspView; - -public class ManualHandlerAdapter implements HandlerAdapter { - - @Override - public boolean isSupport(Object handler) { - return handler instanceof Controller; - } - - @Override - public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - Controller controller = (Controller) handler; - String viewName = controller.execute(request, response); - return new ModelAndView(new JspView(viewName)); - } - -} diff --git a/app/src/main/java/com/techcourse/ManualHandlerMapping.java b/app/src/main/java/com/techcourse/ManualHandlerMapping.java deleted file mode 100644 index a8e3bb7a36..0000000000 --- a/app/src/main/java/com/techcourse/ManualHandlerMapping.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.techcourse; - -import com.techcourse.controller.*; -import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; -import webmvc.org.springframework.web.servlet.mvc.asis.ForwardController; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMapping; - -import java.util.HashMap; -import java.util.Map; - -public class ManualHandlerMapping implements HandlerMapping { - - private static final Logger log = LoggerFactory.getLogger(ManualHandlerMapping.class); - - private static final Map controllers = new HashMap<>(); - - @Override - public void initialize() { - controllers.put("/", new ForwardController("/index.jsp")); - controllers.put("/login", new LoginController()); - controllers.put("/login/view", new LoginViewController()); - controllers.put("/logout", new LogoutController()); - controllers.put("/register/view", new RegisterViewController()); - controllers.put("/register", new RegisterController()); - - log.info("Initialized Handler Mapping!"); - controllers.keySet() - .forEach(path -> log.info("Path : {}, Controller : {}", path, controllers.get(path).getClass())); - } - - @Override - public Object getHandler(final HttpServletRequest request) { - String requestURI = request.getRequestURI(); - return controllers.get(requestURI); - } -} diff --git a/app/src/main/java/com/techcourse/controller/LoginController.java b/app/src/main/java/com/techcourse/controller/LoginController.java index 0428fe109e..c7006839b9 100644 --- a/app/src/main/java/com/techcourse/controller/LoginController.java +++ b/app/src/main/java/com/techcourse/controller/LoginController.java @@ -2,36 +2,40 @@ import com.techcourse.domain.User; import com.techcourse.repository.InMemoryUserRepository; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; -public class LoginController implements Controller { +@Controller +public class LoginController { private static final Logger log = LoggerFactory.getLogger(LoginController.class); - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { - if (UserSession.isLoggedIn(req.getSession())) { - return "redirect:/index.jsp"; + @RequestMapping(value = "/login", method = RequestMethod.POST) + public ModelAndView login(final HttpServletRequest request, final HttpServletResponse response) { + if (UserSession.isLoggedIn(request.getSession())) { + return new ModelAndView(new JspView("redirect:/index.jsp")); } - - return InMemoryUserRepository.findByAccount(req.getParameter("account")) + return InMemoryUserRepository.findByAccount(request.getParameter("account")) .map(user -> { log.info("User : {}", user); - return login(req, user); + return tryLogin(request, user); }) - .orElse("redirect:/401.jsp"); + .orElse(new ModelAndView(new JspView("redirect:/401.jsp"))); } - private String login(final HttpServletRequest request, final User user) { + private ModelAndView tryLogin(final HttpServletRequest request, final User user) { if (user.checkPassword(request.getParameter("password"))) { final var session = request.getSession(); session.setAttribute(UserSession.SESSION_KEY, user); - return "redirect:/index.jsp"; + return new ModelAndView(new JspView("redirect:/index.jsp")); } - return "redirect:/401.jsp"; + return new ModelAndView(new JspView("redirect:/401.jsp")); } } diff --git a/app/src/main/java/com/techcourse/controller/LoginViewController.java b/app/src/main/java/com/techcourse/controller/LoginViewController.java index 86ec26cdce..dfdb0a45f9 100644 --- a/app/src/main/java/com/techcourse/controller/LoginViewController.java +++ b/app/src/main/java/com/techcourse/controller/LoginViewController.java @@ -1,22 +1,27 @@ package com.techcourse.controller; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; -public class LoginViewController implements Controller { +@Controller +public class LoginViewController { private static final Logger log = LoggerFactory.getLogger(LoginViewController.class); - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { + @RequestMapping(value = "/login/view", method = RequestMethod.GET) + public ModelAndView getLoginView(final HttpServletRequest req, final HttpServletResponse res) { return UserSession.getUserFrom(req.getSession()) .map(user -> { log.info("logged in {}", user.getAccount()); - return "redirect:/index.jsp"; + return new ModelAndView(new JspView("redirect:/index.jsp")); }) - .orElse("/login.jsp"); + .orElse(new ModelAndView(new JspView("/login.jsp"))); } } diff --git a/app/src/main/java/com/techcourse/controller/LogoutController.java b/app/src/main/java/com/techcourse/controller/LogoutController.java index 4642fd9450..478dc8c0c8 100644 --- a/app/src/main/java/com/techcourse/controller/LogoutController.java +++ b/app/src/main/java/com/techcourse/controller/LogoutController.java @@ -1,15 +1,20 @@ package com.techcourse.controller; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; -public class LogoutController implements Controller { +@Controller +public class LogoutController { - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { + @RequestMapping(value = "/logout", method = RequestMethod.GET) + public ModelAndView logout(final HttpServletRequest req, final HttpServletResponse res) { final var session = req.getSession(); session.removeAttribute(UserSession.SESSION_KEY); - return "redirect:/"; + return new ModelAndView(new JspView("redirect:/")); } } diff --git a/app/src/main/java/com/techcourse/controller/RegisterController.java b/app/src/main/java/com/techcourse/controller/RegisterController.java index da62e5e8e9..46f7befaf3 100644 --- a/app/src/main/java/com/techcourse/controller/RegisterController.java +++ b/app/src/main/java/com/techcourse/controller/RegisterController.java @@ -2,20 +2,25 @@ import com.techcourse.domain.User; import com.techcourse.repository.InMemoryUserRepository; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; -public class RegisterController implements Controller { +@Controller +public class RegisterController { - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { + @RequestMapping(value = "/register", method = RequestMethod.POST) + public ModelAndView register(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"; + return new ModelAndView(new JspView("redirect:/index.jsp")); } } diff --git a/app/src/main/java/com/techcourse/controller/RegisterViewController.java b/app/src/main/java/com/techcourse/controller/RegisterViewController.java index 136962136d..845370e75d 100644 --- a/app/src/main/java/com/techcourse/controller/RegisterViewController.java +++ b/app/src/main/java/com/techcourse/controller/RegisterViewController.java @@ -1,13 +1,18 @@ package com.techcourse.controller; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; -public class RegisterViewController implements Controller { +@Controller +public class RegisterViewController { - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { - return "/register.jsp"; + @RequestMapping(value = "/register/view", method = RequestMethod.GET) + public ModelAndView getRegisterView(final HttpServletRequest req, final HttpServletResponse res) { + return new ModelAndView(new JspView("/register.jsp")); } } diff --git a/mvc/src/main/java/web/org/springframework/http/MediaType.java b/mvc/src/main/java/web/org/springframework/http/MediaType.java index 3a31f51d33..6a5eccc237 100644 --- a/mvc/src/main/java/web/org/springframework/http/MediaType.java +++ b/mvc/src/main/java/web/org/springframework/http/MediaType.java @@ -2,4 +2,5 @@ public class MediaType { public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8"; + public static final String TEXT_PLAIN_UTF8_VALUE = "text/plain;charset=UTF-8"; } diff --git a/app/src/main/java/com/techcourse/DispatcherServlet.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/DispatcherServlet.java similarity index 75% rename from app/src/main/java/com/techcourse/DispatcherServlet.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/DispatcherServlet.java index d1dee5a0cd..5c4a72b5a0 100644 --- a/app/src/main/java/com/techcourse/DispatcherServlet.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/DispatcherServlet.java @@ -1,4 +1,4 @@ -package com.techcourse; +package webmvc.org.springframework.web.servlet; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; @@ -6,12 +6,10 @@ import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import webmvc.org.springframework.web.servlet.ModelAndView; import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapter; import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapterRegistry; import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMapping; import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMappingRegistry; -import webmvc.org.springframework.web.servlet.view.JspView; public class DispatcherServlet extends HttpServlet { @@ -52,22 +50,12 @@ protected void service(final HttpServletRequest request, final HttpServletRespon ModelAndView modelAndView = handlerAdapter.handle(request, response, handler); - JspView view = (JspView) modelAndView.getView(); - move(view.getView(), request, response); + View view = modelAndView.getView(); + view.render(modelAndView.getModel(), request, response); } catch (Throwable e) { log.error("Exception : {}", e.getMessage(), e); throw new ServletException(e.getMessage()); } } - - 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); - } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java deleted file mode 100644 index bdd1fde780..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java +++ /dev/null @@ -1,8 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -public interface Controller { - String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception; -} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java deleted file mode 100644 index cd8f1ef371..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java +++ /dev/null @@ -1,20 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import java.util.Objects; - -public class ForwardController implements Controller { - - private final String path; - - public ForwardController(final String path) { - this.path = Objects.requireNonNull(path); - } - - @Override - public String execute(final HttpServletRequest request, final HttpServletResponse response) { - return path; - } -} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapterRegistry.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapterRegistry.java index df99b85c65..337694caa5 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapterRegistry.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapterRegistry.java @@ -16,11 +16,9 @@ public void addHandlerAdapter(HandlerAdapter handlerAdapter) { } public HandlerAdapter getHandlerAdapter(Object handler) { - for (HandlerAdapter handlerAdapter : this.handlerAdapters) { - if (handlerAdapter.isSupport(handler)) { - return handlerAdapter; - } - } - throw new IllegalArgumentException("해당 handler를 찾을 수 없습니다."); + return this.handlerAdapters.stream() + .filter(handlerAdapter -> handlerAdapter.isSupport(handler)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("해당 handler를 찾을 수 없습니다.")); } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java index b42c3466f0..0c8fd7c649 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java @@ -1,14 +1,29 @@ package webmvc.org.springframework.web.servlet.view; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import web.org.springframework.http.MediaType; import webmvc.org.springframework.web.servlet.View; import java.util.Map; public class JsonView implements View { + private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final int DEFAULT_RETURN_SIZE = 1; + @Override public void render(final Map model, final HttpServletRequest request, HttpServletResponse response) throws Exception { + String jsonValue = MAPPER.writeValueAsString(model); + + if (model.size() == DEFAULT_RETURN_SIZE) { + response.setContentType(MediaType.TEXT_PLAIN_UTF8_VALUE); + response.getWriter().write(jsonValue); + return; + } + + response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + response.getWriter().write(jsonValue); } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java index 81e7f338a4..1453d05f31 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java @@ -1,5 +1,6 @@ package webmvc.org.springframework.web.servlet.view; +import jakarta.servlet.RequestDispatcher; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; @@ -14,25 +15,29 @@ public class JspView implements View { public static final String REDIRECT_PREFIX = "redirect:"; - private final String view; + private final String viewName; - public JspView(String view) { - this.view = view; + public JspView(String viewName) { + this.viewName = viewName; } @Override public void render(final Map model, final HttpServletRequest request, final HttpServletResponse response) throws Exception { - // todo model.keySet().forEach(key -> { log.debug("attribute name : {}, value : {}", key, model.get(key)); request.setAttribute(key, model.get(key)); }); - // todo + if (viewName.startsWith(REDIRECT_PREFIX)) { + response.sendRedirect(viewName.substring(JspView.REDIRECT_PREFIX.length())); + return; + } + RequestDispatcher requestDispatcher = request.getRequestDispatcher(viewName); + requestDispatcher.forward(request, response); } - public String getView() { - return view; + public String getViewName() { + return viewName; } }