From 892d3ba5389da151f7bce4cc1741bc7e53243eb0 Mon Sep 17 00:00:00 2001 From: Guga Date: Mon, 25 Sep 2023 19:00:00 +0900 Subject: [PATCH] =?UTF-8?q?[MVC=20=EA=B5=AC=ED=98=84=ED=95=98=EA=B8=B0=20-?= =?UTF-8?q?=203=EB=8B=A8=EA=B3=84]=20=ED=91=B8=EC=9A=B0(=EB=B0=B1=EC=8A=B9?= =?UTF-8?q?=EC=A4=80)=20=EB=AF=B8=EC=85=98=20=EC=A0=9C=EC=B6=9C=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.=20=20(#606)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: UserController 추가 * feat: objectMapper 추가 및 사용법 테스트 * chore: 사용하지 않는 테스트 필드 삭제 * feat: JsonView 구현 * refactor: interface Controller 기반 Controller 를 annotation 기반으로 변경 * feat: ExceptionHandler 생성 * refactor: legacy interface Controller 삭제 --- app/build.gradle | 1 + .../DispatcherServletInitializer.java | 9 +- .../com/techcourse/ManualHandlerMapping.java | 40 ------- .../controller/ForwardController.java | 18 +++ .../controller/LoginController.java | 54 +++++++++ .../controller/LogoutController.java | 22 ++++ .../{annotaion => }/RegisterController.java | 2 +- .../RegisterViewController.java | 2 +- .../techcourse/controller/UserController.java | 32 +++++ .../controller/regacy/ForwardController.java | 20 ---- .../controller/regacy/LoginController.java | 41 ------- .../regacy/LoginViewController.java | 26 ---- .../controller/regacy/LogoutController.java | 16 --- .../com/techcourse/DispatcherServletTest.java | 87 -------------- .../techcourse/ManualHandlerMappingTest.java | 40 ------- .../java/com/techcourse/ObjectMapperTest.java | 51 ++++++++ .../controller/regacy/ControllerTest.java | 34 ------ .../regacy/LoginControllerTest.java | 112 ------------------ .../regacy/LoginViewControllerTest.java | 69 ----------- .../web/servlet/mvc/asis/Controller.java | 9 -- .../mvc/asis/InterfaceControllerAdapter.java | 27 ----- .../AnnotationControllerAdapter.java | 3 +- .../servlet/mvc/tobe}/DispatcherServlet.java | 9 +- .../servlet/mvc/tobe/ExceptionHandler.java | 24 ++++ .../mvc/{asis => tobe}/HandlerAdapter.java | 2 +- .../HandlerAdapterRegistry.java | 2 +- .../mvc/tobe/HandlerMappingRegistry.java | 8 +- .../servlet/mvc/tobe/NotFoundController.java | 13 -- .../exception/HandlerNotFoundException.java | 5 + .../web/servlet/view/JsonView.java | 34 +++++- .../asis/AnnotationControllerAdapterTest.java | 1 + .../asis/InterfaceControllerAdapterTest.java | 55 --------- .../web/servlet/view/JsonViewTest.java | 82 +++++++++++++ 33 files changed, 338 insertions(+), 612 deletions(-) delete mode 100644 app/src/main/java/com/techcourse/ManualHandlerMapping.java create mode 100644 app/src/main/java/com/techcourse/controller/ForwardController.java create mode 100644 app/src/main/java/com/techcourse/controller/LoginController.java create mode 100644 app/src/main/java/com/techcourse/controller/LogoutController.java rename app/src/main/java/com/techcourse/controller/{annotaion => }/RegisterController.java (95%) rename app/src/main/java/com/techcourse/controller/{annotaion => }/RegisterViewController.java (93%) create mode 100644 app/src/main/java/com/techcourse/controller/UserController.java delete mode 100644 app/src/main/java/com/techcourse/controller/regacy/ForwardController.java delete mode 100644 app/src/main/java/com/techcourse/controller/regacy/LoginController.java delete mode 100644 app/src/main/java/com/techcourse/controller/regacy/LoginViewController.java delete mode 100644 app/src/main/java/com/techcourse/controller/regacy/LogoutController.java delete mode 100644 app/src/test/java/com/techcourse/DispatcherServletTest.java delete mode 100644 app/src/test/java/com/techcourse/ManualHandlerMappingTest.java create mode 100644 app/src/test/java/com/techcourse/ObjectMapperTest.java delete mode 100644 app/src/test/java/com/techcourse/controller/regacy/ControllerTest.java delete mode 100644 app/src/test/java/com/techcourse/controller/regacy/LoginControllerTest.java delete mode 100644 app/src/test/java/com/techcourse/controller/regacy/LoginViewControllerTest.java 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/InterfaceControllerAdapter.java rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/{asis => tobe}/AnnotationControllerAdapter.java (86%) rename {app/src/main/java/com/techcourse => mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe}/DispatcherServlet.java (86%) create mode 100644 mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ExceptionHandler.java rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/{asis => tobe}/HandlerAdapter.java (85%) rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/{asis => tobe}/HandlerAdapterRegistry.java (90%) delete mode 100644 mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundController.java create mode 100644 mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/exception/HandlerNotFoundException.java delete mode 100644 mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/asis/InterfaceControllerAdapterTest.java create mode 100644 mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JsonViewTest.java diff --git a/app/build.gradle b/app/build.gradle index 81e0d33944..17e9e97cbb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,6 +21,7 @@ dependencies { implementation "org.apache.tomcat.embed:tomcat-embed-jasper:10.1.13" implementation "ch.qos.logback:logback-classic:1.2.12" implementation "org.apache.commons:commons-lang3:3.13.0" + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2' testImplementation "org.assertj:assertj-core:3.24.2" testImplementation "org.junit.jupiter:junit-jupiter-api:5.7.2" diff --git a/app/src/main/java/com/techcourse/DispatcherServletInitializer.java b/app/src/main/java/com/techcourse/DispatcherServletInitializer.java index 96237242f9..3aa31412e7 100644 --- a/app/src/main/java/com/techcourse/DispatcherServletInitializer.java +++ b/app/src/main/java/com/techcourse/DispatcherServletInitializer.java @@ -4,10 +4,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import web.org.springframework.web.WebApplicationInitializer; -import webmvc.org.springframework.web.servlet.mvc.asis.AnnotationControllerAdapter; -import webmvc.org.springframework.web.servlet.mvc.asis.HandlerAdapterRegistry; -import webmvc.org.springframework.web.servlet.mvc.asis.InterfaceControllerAdapter; +import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationControllerAdapter; import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping; +import webmvc.org.springframework.web.servlet.mvc.tobe.DispatcherServlet; +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; @@ -39,8 +39,6 @@ public void onStartup(final ServletContext servletContext) { private HandlerMappingRegistry getHandlerMappingRegistry() { HandlerMappingRegistry registry = new HandlerMappingRegistry(); - registry.addHandlerMapping( - getInitializedHandlerMapping(new ManualHandlerMapping())); registry.addHandlerMapping( getInitializedHandlerMapping(new AnnotationHandlerMapping("com"))); return registry; @@ -54,7 +52,6 @@ private HandlerMapping getInitializedHandlerMapping(HandlerMapping handlerMappin private HandlerAdapterRegistry getHandlerAdapterRegistry() { HandlerAdapterRegistry registry = new HandlerAdapterRegistry(); registry.addHandlerAdapter(new AnnotationControllerAdapter()); - registry.addHandlerAdapter(new InterfaceControllerAdapter()); return registry; } } 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 e145a6083b..0000000000 --- a/app/src/main/java/com/techcourse/ManualHandlerMapping.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.techcourse; - -import com.techcourse.controller.regacy.ForwardController; -import com.techcourse.controller.regacy.LoginController; -import com.techcourse.controller.regacy.LoginViewController; -import com.techcourse.controller.regacy.LogoutController; -import jakarta.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMapping; - -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()); - - log.info("Initialized Handler Mapping!"); - controllers.keySet() - .forEach(path -> log.info("Path : {}, Controller : {}", path, controllers.get(path).getClass())); - } - - @Override - public Optional getHandler(HttpServletRequest httpServletRequest) { - String requestURI = httpServletRequest.getRequestURI(); - log.debug("Request Mapping Uri : {}", requestURI); - return Optional.ofNullable(controllers.get(requestURI)); - } -} diff --git a/app/src/main/java/com/techcourse/controller/ForwardController.java b/app/src/main/java/com/techcourse/controller/ForwardController.java new file mode 100644 index 0000000000..6971ab56ce --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/ForwardController.java @@ -0,0 +1,18 @@ +package com.techcourse.controller; + +import context.org.springframework.stereotype.Controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +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; + +@Controller +public class ForwardController { + + @RequestMapping(value = "/", method = {RequestMethod.GET}) + public ModelAndView forwardView(HttpServletRequest req, HttpServletResponse res) { + return new ModelAndView(new JspView("/index.jsp")); + } +} diff --git a/app/src/main/java/com/techcourse/controller/LoginController.java b/app/src/main/java/com/techcourse/controller/LoginController.java new file mode 100644 index 0000000000..1514e3774e --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/LoginController.java @@ -0,0 +1,54 @@ +package com.techcourse.controller; + +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 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; + +@Controller +public class LoginController { + + Logger log = LoggerFactory.getLogger(LoginController.class); + + @RequestMapping(value = "/login", method = {RequestMethod.GET}) + public ModelAndView loginView(HttpServletRequest req, HttpServletResponse res) { + if (UserSession.isLoggedIn(req.getSession())) { + return modelAndJspViewFor("redirect:index.jsp"); + } + return new ModelAndView(new JspView("/login.jsp")); + } + + @RequestMapping(value = "/login", method = {RequestMethod.POST}) + public ModelAndView handleLogin(HttpServletRequest req, HttpServletResponse res) { + if (UserSession.isLoggedIn(req.getSession())) { + return modelAndJspViewFor("redirect:index.jsp"); + } + + return InMemoryUserRepository.findByAccount(req.getParameter("account")) + .map(user -> { + log.info("User : {}", user); + return login(req, user); + }) + .orElseGet(() -> modelAndJspViewFor("redirect:/401.jsp")); + } + + private ModelAndView login(final HttpServletRequest request, final User user) { + if (user.checkPassword(request.getParameter("password"))) { + final var session = request.getSession(); + session.setAttribute(UserSession.SESSION_KEY, user); + return modelAndJspViewFor("redirect:/index.jsp"); + } + return modelAndJspViewFor("redirect:/401.jsp"); + } + + private ModelAndView modelAndJspViewFor(String path) { + return new ModelAndView(new JspView(path)); + } +} diff --git a/app/src/main/java/com/techcourse/controller/LogoutController.java b/app/src/main/java/com/techcourse/controller/LogoutController.java new file mode 100644 index 0000000000..13f95302f7 --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/LogoutController.java @@ -0,0 +1,22 @@ +package com.techcourse.controller; + +import context.org.springframework.stereotype.Controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +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; + +@Controller +public class LogoutController { + + + @RequestMapping(value = "/logout", method = {RequestMethod.GET}) + public ModelAndView logout(HttpServletRequest req, HttpServletResponse res) { + final var session = req.getSession(); + session.removeAttribute(UserSession.SESSION_KEY); + return new ModelAndView(new JspView("redirect:/")); + } + +} diff --git a/app/src/main/java/com/techcourse/controller/annotaion/RegisterController.java b/app/src/main/java/com/techcourse/controller/RegisterController.java similarity index 95% rename from app/src/main/java/com/techcourse/controller/annotaion/RegisterController.java rename to app/src/main/java/com/techcourse/controller/RegisterController.java index 1af4ec3632..880c4e5e1a 100644 --- a/app/src/main/java/com/techcourse/controller/annotaion/RegisterController.java +++ b/app/src/main/java/com/techcourse/controller/RegisterController.java @@ -1,4 +1,4 @@ -package com.techcourse.controller.annotaion; +package com.techcourse.controller; import com.techcourse.domain.User; import com.techcourse.repository.InMemoryUserRepository; diff --git a/app/src/main/java/com/techcourse/controller/annotaion/RegisterViewController.java b/app/src/main/java/com/techcourse/controller/RegisterViewController.java similarity index 93% rename from app/src/main/java/com/techcourse/controller/annotaion/RegisterViewController.java rename to app/src/main/java/com/techcourse/controller/RegisterViewController.java index e954e0f2b9..626281af28 100644 --- a/app/src/main/java/com/techcourse/controller/annotaion/RegisterViewController.java +++ b/app/src/main/java/com/techcourse/controller/RegisterViewController.java @@ -1,4 +1,4 @@ -package com.techcourse.controller.annotaion; +package com.techcourse.controller; import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; diff --git a/app/src/main/java/com/techcourse/controller/UserController.java b/app/src/main/java/com/techcourse/controller/UserController.java new file mode 100644 index 0000000000..cada0cc189 --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/UserController.java @@ -0,0 +1,32 @@ +package com.techcourse.controller; + +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 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.JsonView; + +@Controller +public class UserController { + + private static final Logger log = LoggerFactory.getLogger(UserController.class); + + @RequestMapping(value = "/api/user", method = RequestMethod.GET) + public ModelAndView show(HttpServletRequest request, HttpServletResponse response) { + final String account = request.getParameter("account"); + log.debug("user id : {}", account); + + final ModelAndView modelAndView = new ModelAndView(new JsonView()); + final User user = InMemoryUserRepository.findByAccount(account) + .orElseThrow(); + + modelAndView.addObject("user", user); + return modelAndView; + } +} diff --git a/app/src/main/java/com/techcourse/controller/regacy/ForwardController.java b/app/src/main/java/com/techcourse/controller/regacy/ForwardController.java deleted file mode 100644 index fa274783d2..0000000000 --- a/app/src/main/java/com/techcourse/controller/regacy/ForwardController.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.techcourse.controller.regacy; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.util.Objects; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; - -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/app/src/main/java/com/techcourse/controller/regacy/LoginController.java b/app/src/main/java/com/techcourse/controller/regacy/LoginController.java deleted file mode 100644 index 952ae74098..0000000000 --- a/app/src/main/java/com/techcourse/controller/regacy/LoginController.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.techcourse.controller.regacy; - -import com.techcourse.controller.UserSession; -import com.techcourse.domain.User; -import com.techcourse.repository.InMemoryUserRepository; -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; - -public class LoginController implements Controller { - - private static final Logger log = LoggerFactory.getLogger(LoginController.class); - - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) { - if (!"POST".equals(req.getMethod())) { - return "redirect:/login.jsp"; - } - if (UserSession.isLoggedIn(req.getSession())) { - return "redirect:/index.jsp"; - } - - return InMemoryUserRepository.findByAccount(req.getParameter("account")) - .map(user -> { - log.info("User : {}", user); - return login(req, user); - }) - .orElse("redirect:/401.jsp"); - } - - private String login(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 "redirect:/401.jsp"; - } -} diff --git a/app/src/main/java/com/techcourse/controller/regacy/LoginViewController.java b/app/src/main/java/com/techcourse/controller/regacy/LoginViewController.java deleted file mode 100644 index 7188713170..0000000000 --- a/app/src/main/java/com/techcourse/controller/regacy/LoginViewController.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.techcourse.controller.regacy; - -import com.techcourse.controller.UserSession; -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; - -public class LoginViewController implements Controller { - - private static final Logger log = LoggerFactory.getLogger(LoginViewController.class); - - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) { - if (!"GET".equals(req.getMethod())) { - return "/404.jsp"; - } - return UserSession.getUserFrom(req.getSession()) - .map(user -> { - log.info("logged in {}", user.getAccount()); - return "redirect:/index.jsp"; - }) - .orElseGet(() -> "/login.jsp"); - } -} diff --git a/app/src/main/java/com/techcourse/controller/regacy/LogoutController.java b/app/src/main/java/com/techcourse/controller/regacy/LogoutController.java deleted file mode 100644 index 4ab0a39223..0000000000 --- a/app/src/main/java/com/techcourse/controller/regacy/LogoutController.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.techcourse.controller.regacy; - -import com.techcourse.controller.UserSession; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; - -public class LogoutController implements Controller { - - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) { - final var session = req.getSession(); - session.removeAttribute(UserSession.SESSION_KEY); - return "redirect:/"; - } -} diff --git a/app/src/test/java/com/techcourse/DispatcherServletTest.java b/app/src/test/java/com/techcourse/DispatcherServletTest.java deleted file mode 100644 index 9f3486224e..0000000000 --- a/app/src/test/java/com/techcourse/DispatcherServletTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.techcourse; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Optional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.View; -import webmvc.org.springframework.web.servlet.mvc.asis.HandlerAdapter; -import webmvc.org.springframework.web.servlet.mvc.asis.HandlerAdapterRegistry; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMappingRegistry; - -class DispatcherServletTest { - - @Mock - HttpServletRequest request; - - @Mock - HttpServletResponse response; - - @Mock - HandlerAdapterRegistry mockHandlerAdapterRegistry; - - @Mock - HandlerMappingRegistry mockHandlerMappingRegistry; - - @Captor - ArgumentCaptor urlCaptor; - - DispatcherServlet dispatcherServlet; - - @BeforeEach - void setting() { - MockitoAnnotations.openMocks(this); - dispatcherServlet = new DispatcherServlet(mockHandlerMappingRegistry, mockHandlerAdapterRegistry); - } - - @Test - void noAdapterThrowException() throws ServletException, IOException { - // given - given(mockHandlerMappingRegistry.getHandler(any())) - .willReturn(Optional.of(new Object())); - given(mockHandlerAdapterRegistry.getHandlerAdapter(any())) - .willReturn(Optional.empty()); - - // when & then - assertThatThrownBy(() -> dispatcherServlet.service(request, response)) - .isInstanceOf(ServletException.class) - .hasMessage("핸들러를 처리할 어댑터가 없습니다."); - } - - @Test - void renderViewFromAdapter() throws Exception { - // given - given(mockHandlerMappingRegistry.getHandler(any())) - .willReturn(Optional.of(new Object())); - - HandlerAdapter mockHandlerAdapter = mock(HandlerAdapter.class); - View mockView = mock(View.class); - - given(mockHandlerAdapter.handle(any(), any(), any())) - .willReturn(new ModelAndView(mockView)); - - given(mockHandlerAdapterRegistry.getHandlerAdapter(any())) - .willReturn(Optional.of(mockHandlerAdapter)); - - // when - dispatcherServlet.service(request, response); - - // then - verify(mockView, times(1)).render(any(), any(), any()); - } -} diff --git a/app/src/test/java/com/techcourse/ManualHandlerMappingTest.java b/app/src/test/java/com/techcourse/ManualHandlerMappingTest.java deleted file mode 100644 index a70e276704..0000000000 --- a/app/src/test/java/com/techcourse/ManualHandlerMappingTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.techcourse; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; - -import jakarta.servlet.http.HttpServletRequest; -import java.util.Optional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -class ManualHandlerMappingTest { - - ManualHandlerMapping manualHandlerMapping; - - @Mock - HttpServletRequest httpServletRequest; - - @BeforeEach - void setting() { - MockitoAnnotations.openMocks(this); - manualHandlerMapping = new ManualHandlerMapping(); - } - - @ParameterizedTest - @ValueSource(strings = {"/", "/login", "/login/view", "/logout"}) - void findEnrolledControllers(String uri) { - // given - manualHandlerMapping.initialize(); - given(httpServletRequest.getRequestURI()).willReturn(uri); - - // when - Optional handler = manualHandlerMapping.getHandler(httpServletRequest); - - // then - assertThat(handler).isPresent(); - } -} diff --git a/app/src/test/java/com/techcourse/ObjectMapperTest.java b/app/src/test/java/com/techcourse/ObjectMapperTest.java new file mode 100644 index 0000000000..ceb5c9468c --- /dev/null +++ b/app/src/test/java/com/techcourse/ObjectMapperTest.java @@ -0,0 +1,51 @@ +package com.techcourse; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class ObjectMapperTest { + + ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void objectMapper를_통해서_json_타입으로_변환_가능() { + // given + Map data = new HashMap<>(); + data.put("data1", "key1"); + data.put("data2", new JunHo()); + JsonNode jsonNode = objectMapper.valueToTree(data); + String expected = "{\n" + + " \"data2\" : {\n" + + " \"names\" : [ \"junho\", \"junho2\" ],\n" + + " \"age\" : 100\n" + + " },\n" + + " \"data1\" : \"key1\"\n" + + "}"; + + // when + String actual = jsonNode.toPrettyString(); + + // then + assertThat(expected).isEqualTo(actual); + } + + private class JunHo { + + private List names = List.of("junho", "junho2"); + private Integer age = 100; + + public List getNames() { + return names; + } + + public Integer getAge() { + return age; + } + } +} diff --git a/app/src/test/java/com/techcourse/controller/regacy/ControllerTest.java b/app/src/test/java/com/techcourse/controller/regacy/ControllerTest.java deleted file mode 100644 index 479b93bd92..0000000000 --- a/app/src/test/java/com/techcourse/controller/regacy/ControllerTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.techcourse.controller.regacy; - -import static org.mockito.Mockito.mockStatic; - -import com.techcourse.controller.UserSession; -import com.techcourse.repository.InMemoryUserRepository; -import jakarta.servlet.http.HttpServletRequest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.MockitoAnnotations; - -public abstract class ControllerTest { - - @Mock - HttpServletRequest request; - - MockedStatic mockUserSession; - MockedStatic mockUserRepository; - - @BeforeEach - void setting() { - MockitoAnnotations.openMocks(this); - mockUserSession = mockStatic(UserSession.class); - mockUserRepository = mockStatic(InMemoryUserRepository.class); - } - - @AfterEach - void deleteStaticMock() { - mockUserSession.close(); - mockUserRepository.close(); - } -} diff --git a/app/src/test/java/com/techcourse/controller/regacy/LoginControllerTest.java b/app/src/test/java/com/techcourse/controller/regacy/LoginControllerTest.java deleted file mode 100644 index 720dc3ed8f..0000000000 --- a/app/src/test/java/com/techcourse/controller/regacy/LoginControllerTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.techcourse.controller.regacy; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.techcourse.controller.UserSession; -import com.techcourse.domain.User; -import com.techcourse.repository.InMemoryUserRepository; -import jakarta.servlet.http.HttpSession; -import java.util.Optional; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -class LoginControllerTest extends ControllerTest { - - LoginController loginController = new LoginController(); - - @ParameterizedTest - @ValueSource(strings = {"GET", "DELETE", "PUT", "PATCH"}) - void returnRedirectWhenMethodNotPost(String method) { - // given - given(request.getMethod()) - .willReturn(method); - String expect = "redirect:/login.jsp"; - - // when - String actual = loginController.execute(request, null); - - // then - assertThat(actual).isEqualTo(expect); - } - - @Test - void loginUserSendRedirect() { - // given - given(UserSession.isLoggedIn(any())) - .willReturn(true); - given(request.getMethod()) - .willReturn("POST"); - - String expect = "redirect:/index.jsp"; - - // when - String actual = loginController.execute(request, null); - - // then - assertThat(actual).isEqualTo(expect); - } - - @Test - void existUserRedirectIndex() { - // given - given(UserSession.isLoggedIn(any())) - .willReturn(false); - given(request.getMethod()) - .willReturn("POST"); - - HttpSession mockSession = mock(HttpSession.class); - given(request.getSession()) - .willReturn(mockSession); - - User mockUser = mock(User.class); - given(mockUser.checkPassword(any())) - .willReturn(true); - given(InMemoryUserRepository.findByAccount(any())) - .willReturn(Optional.of(mockUser)); - - String expect = "redirect:/index.jsp"; - - // when - String actual = loginController.execute(request, null); - - // then - assertAll( - () -> assertThat(actual).isEqualTo(expect), - () -> verify(mockSession, times(1)).setAttribute(any(), any()) - ); - } - - @Test - void invalidPassword40Redirect() { - // given - given(UserSession.isLoggedIn(any())) - .willReturn(false); - given(request.getMethod()) - .willReturn("POST"); - - HttpSession mockSession = mock(HttpSession.class); - given(request.getSession()) - .willReturn(mockSession); - - User mockUser = mock(User.class); - given(mockUser.checkPassword(any())) - .willReturn(false); - given(InMemoryUserRepository.findByAccount(any())) - .willReturn(Optional.of(mockUser)); - - String expect = "redirect:/401.jsp"; - - // when - String actual = loginController.execute(request, null); - - // then - assertThat(actual).isEqualTo(expect); - } -} diff --git a/app/src/test/java/com/techcourse/controller/regacy/LoginViewControllerTest.java b/app/src/test/java/com/techcourse/controller/regacy/LoginViewControllerTest.java deleted file mode 100644 index 4c2eb862fd..0000000000 --- a/app/src/test/java/com/techcourse/controller/regacy/LoginViewControllerTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.techcourse.controller.regacy; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import com.techcourse.controller.UserSession; -import com.techcourse.domain.User; -import java.util.Optional; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -class LoginViewControllerTest extends ControllerTest { - - LoginViewController loginViewController = new LoginViewController(); - - @ParameterizedTest - @ValueSource(strings = {"POST", "DELETE", "PUT", "PATCH"}) - void notGetSendRedirect(String method) { - // given - given(request.getMethod()) - .willReturn(method); - - String expect = "/404.jsp"; - - // when - String actual = loginViewController.execute(request, null); - - // then - assertThat(actual).isEqualTo(expect); - } - - @Test - void loggedInUserSendRedirect() { - // given - User mockUser = mock(User.class); - given(UserSession.getUserFrom(any())) - .willReturn(Optional.of(mockUser)); - given(request.getMethod()) - .willReturn("GET"); - - String expect = "redirect:/index.jsp"; - - // when - String actual = loginViewController.execute(request, null); - - // then - assertThat(actual).isEqualTo(expect); - } - - @Test - void loginUserSendRedirect() { - // given - given(UserSession.getUserFrom(any())) - .willReturn(Optional.empty()); - given(request.getMethod()) - .willReturn("GET"); - - String expect = "/login.jsp"; - - // when - String actual = loginViewController.execute(request, null); - - // then - assertThat(actual).isEqualTo(expect); - } -} 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 bc8b75900c..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java +++ /dev/null @@ -1,9 +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); -} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/InterfaceControllerAdapter.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/InterfaceControllerAdapter.java deleted file mode 100644 index 02ab6c3033..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/InterfaceControllerAdapter.java +++ /dev/null @@ -1,27 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.view.JspView; - -public class InterfaceControllerAdapter implements HandlerAdapter { - - @Override - public boolean support(Object object) { - return object instanceof Controller; - } - - @Override - public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) { - checkValidAdapter(handler); - String responsePath = ((Controller) handler).execute(request, response); - return new ModelAndView(new JspView(responsePath)); - } - - private void checkValidAdapter(Object handler) { - if (!(handler instanceof Controller)) { - throw new IllegalArgumentException("해당 Adapter 는 전달된 handler 를 처리할 수 없습니다."); - } - } -} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/AnnotationControllerAdapter.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationControllerAdapter.java similarity index 86% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/AnnotationControllerAdapter.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationControllerAdapter.java index ab86b20f2d..e3665a62ec 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/AnnotationControllerAdapter.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationControllerAdapter.java @@ -1,9 +1,8 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; +package webmvc.org.springframework.web.servlet.mvc.tobe; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; public class AnnotationControllerAdapter implements HandlerAdapter { diff --git a/app/src/main/java/com/techcourse/DispatcherServlet.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java similarity index 86% rename from app/src/main/java/com/techcourse/DispatcherServlet.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java index dec54821f6..6313dfad0d 100644 --- a/app/src/main/java/com/techcourse/DispatcherServlet.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java @@ -1,4 +1,4 @@ -package com.techcourse; +package webmvc.org.springframework.web.servlet.mvc.tobe; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; @@ -7,9 +7,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.mvc.asis.HandlerAdapter; -import webmvc.org.springframework.web.servlet.mvc.asis.HandlerAdapterRegistry; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMappingRegistry; +import webmvc.org.springframework.web.servlet.mvc.tobe.exception.HandlerNotFoundException; public class DispatcherServlet extends HttpServlet { @@ -18,6 +16,7 @@ public class DispatcherServlet extends HttpServlet { private final transient HandlerMappingRegistry handlerMappingRegistry; private final transient HandlerAdapterRegistry handlerAdapterRegistry; + private final transient ExceptionHandler exceptionHandler = new ExceptionHandler(); public DispatcherServlet(HandlerMappingRegistry handlerMappingRegistry, HandlerAdapterRegistry handlerAdapterRegistry) { this.handlerMappingRegistry = handlerMappingRegistry; @@ -46,6 +45,8 @@ protected void service(final HttpServletRequest request, final HttpServletRespon .orElseThrow(() -> new IllegalStateException("핸들러를 처리할 어댑터가 없습니다.")); ModelAndView modelAndView = handlerAdapter.handle(request, response, handler); modelAndView.getView().render(modelAndView.getModel(), request, response); + } catch (HandlerNotFoundException e) { + exceptionHandler.handle(e, request, response); } catch (Exception e) { logger.error("Exception : {}", e.getMessage(), e); throw new ServletException(e.getMessage()); diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ExceptionHandler.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ExceptionHandler.java new file mode 100644 index 0000000000..91bb4fe177 --- /dev/null +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ExceptionHandler.java @@ -0,0 +1,24 @@ +package webmvc.org.springframework.web.servlet.mvc.tobe; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Collections; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import webmvc.org.springframework.web.servlet.mvc.tobe.exception.HandlerNotFoundException; +import webmvc.org.springframework.web.servlet.view.JspView; + +public class ExceptionHandler { + + Logger logger = LoggerFactory.getLogger(ExceptionHandler.class); + + public void handle(HandlerNotFoundException e, HttpServletRequest request, HttpServletResponse response) { + try { + logger.info("{0} exception handled", e); + new JspView("/404.jsp") + .render(Collections.emptyMap(), request, response); + } catch (Exception ex) { + throw new IllegalArgumentException("exception handling failed"); + } + } +} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/HandlerAdapter.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapter.java similarity index 85% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/HandlerAdapter.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapter.java index a27c9ce424..44703ad205 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/HandlerAdapter.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapter.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; +package webmvc.org.springframework.web.servlet.mvc.tobe; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/HandlerAdapterRegistry.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapterRegistry.java similarity index 90% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/HandlerAdapterRegistry.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapterRegistry.java index 8475e5eb76..455deb1e34 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/HandlerAdapterRegistry.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerAdapterRegistry.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; +package webmvc.org.springframework.web.servlet.mvc.tobe; import java.util.ArrayList; import java.util.List; diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMappingRegistry.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMappingRegistry.java index f8b45d359d..0fcd72977e 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMappingRegistry.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMappingRegistry.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import webmvc.org.springframework.web.servlet.mvc.tobe.exception.HandlerNotFoundException; public class HandlerMappingRegistry { @@ -14,12 +15,11 @@ public void addHandlerMapping(HandlerMapping handlerMapping) { } public Object getHandler(HttpServletRequest httpServletRequest) { - Optional availableHandler = handlerMappings.stream() + return handlerMappings.stream() .map(handlerMapping -> handlerMapping.getHandler(httpServletRequest)) .filter(Optional::isPresent) .map(Optional::get) - .findAny(); - return availableHandler - .orElseGet(NotFoundController::new); + .findAny() + .orElseThrow(HandlerNotFoundException::new); } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundController.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundController.java deleted file mode 100644 index dbd4d28f96..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundController.java +++ /dev/null @@ -1,13 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; - -public class NotFoundController implements Controller { - - @Override - public String execute(HttpServletRequest req, HttpServletResponse res) { - return "/401.jsp"; - } -} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/exception/HandlerNotFoundException.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/exception/HandlerNotFoundException.java new file mode 100644 index 0000000000..0e812d5437 --- /dev/null +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/exception/HandlerNotFoundException.java @@ -0,0 +1,5 @@ +package webmvc.org.springframework.web.servlet.mvc.tobe.exception; + +public class HandlerNotFoundException extends RuntimeException { + +} 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..bc0a6a5ffa 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,42 @@ package webmvc.org.springframework.web.servlet.view; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.View; - +import java.io.IOException; import java.util.Map; +import java.util.Set; +import webmvc.org.springframework.web.servlet.View; public class JsonView implements View { + public static final int SINGLE_DATA_RESPONSE = 1; + public static final int NOT_RESPONSE_BODY = 0; + private static final String JSON_CONTENT_TYPE = "Application/json"; + private static final ObjectMapper objectMapper = new ObjectMapper(); + @Override - public void render(final Map model, final HttpServletRequest request, HttpServletResponse response) throws Exception { + public void render(final Map model, final HttpServletRequest request, HttpServletResponse response) + throws Exception { + Set responseData = model.keySet(); + if (responseData.size() == NOT_RESPONSE_BODY) { + return; + } + if (responseData.size() == SINGLE_DATA_RESPONSE) { + Object responseModel = model.get(responseData.iterator().next()); + responseBody(responseModel, response); + return; + } + responseBody(model, response); + } + + private void responseBody(Object responseModel, HttpServletResponse response) { + try { + response.setContentType(JSON_CONTENT_TYPE); + String responseBody = objectMapper.valueToTree(responseModel).toPrettyString(); + response.getWriter().write(responseBody); + } catch (IOException e) { + throw new RuntimeException(e); + } } } diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/asis/AnnotationControllerAdapterTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/asis/AnnotationControllerAdapterTest.java index baca1719b1..fa5fb12511 100644 --- a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/asis/AnnotationControllerAdapterTest.java +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/asis/AnnotationControllerAdapterTest.java @@ -10,6 +10,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationControllerAdapter; import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; import webmvc.org.springframework.web.servlet.view.JspView; diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/asis/InterfaceControllerAdapterTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/asis/InterfaceControllerAdapterTest.java deleted file mode 100644 index 7b271c3b8a..0000000000 --- a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/asis/InterfaceControllerAdapterTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; - - -class InterfaceControllerAdapterTest { - - InterfaceControllerAdapter interfaceControllerAdapter = new InterfaceControllerAdapter(); - - @Mock - Controller controller; - - @BeforeEach - void setting() { - MockitoAnnotations.openMocks(this); - } - - @Test - void invalidHandlerException() { - // given - Object invalidHandler = new HandlerExecution(null, null); - - // when & then - assertThatThrownBy(() -> interfaceControllerAdapter.handle(null, null, invalidHandler)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("해당 Adapter 는 전달된 handler 를 처리할 수 없습니다."); - } - - @Test - void validHandle() { - // given - String handlerResponse = "/response.jsp"; - given(controller.execute(any(), any())) - .willReturn(handlerResponse); - - // when - ModelAndView result = interfaceControllerAdapter.handle(null, null, controller); - - // then - assertThat(result) - .extracting("view") - .extracting("viewName") - .isEqualTo(handlerResponse); - } -} diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JsonViewTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JsonViewTest.java new file mode 100644 index 0000000000..aebbb2544f --- /dev/null +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JsonViewTest.java @@ -0,0 +1,82 @@ +package webmvc.org.springframework.web.servlet.view; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import jakarta.servlet.http.HttpServletResponse; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +class JsonViewTest { + + @Mock + HttpServletResponse response; + + @Captor + ArgumentCaptor responseBodyCaptor; + + @BeforeEach + void setting() { + MockitoAnnotations.openMocks(this); + response = mock(HttpServletResponse.class); + } + + @Test + void JsonView_출력_양식_테스트() throws Exception { + // given + PrintWriter mockWriter = mock(PrintWriter.class); + given(response.getWriter()) + .willReturn(mockWriter); + + JsonView jsonView = new JsonView(); + HashMap model = new HashMap<>(); + model.put("key1", "value1"); + model.put("key2", List.of("푸우", "주노")); + + String expect = "{\n" + + " \"key1\" : \"value1\",\n" + + " \"key2\" : [ \"푸우\", \"주노\" ]\n" + + "}"; + + // when + jsonView.render(model, null, response); + + // then + verify(response, times(1)).getWriter(); + verify(mockWriter).write(responseBodyCaptor.capture()); + assertThat(responseBodyCaptor.getValue()).isEqualTo(expect); + } + + @Test + void 전달_인자가_하나일_경우_data_만_출력한다() throws Exception { + + // given + PrintWriter mockWriter = mock(PrintWriter.class); + given(response.getWriter()) + .willReturn(mockWriter); + + JsonView jsonView = new JsonView(); + HashMap model = new HashMap<>(); + model.put("key1", "value1"); + + // when + jsonView.render(model, null, response); + + // then + verify(response, times(1)).getWriter(); + verify(mockWriter).write(responseBodyCaptor.capture()); + assertThat(responseBodyCaptor.getValue()).isEqualTo("\"value1\""); + + } + +}