From 6df6eb20154b4fe849de3443e76b4060b545feb6 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Sun, 29 Sep 2024 23:00:29 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20UserController=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/controller/UserController.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 app/src/main/java/com/techcourse/controller/UserController.java 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..cd1bc3d338 --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/UserController.java @@ -0,0 +1,32 @@ +package com.techcourse.controller; + +import com.interface21.context.stereotype.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.JsonView; +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; + +@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; + } +} From 26165441c2d435fb77c493271db823bd59cdb7c1 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Sun, 29 Sep 2024 23:00:42 +0900 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20JsonView=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webmvc/servlet/view/JsonView.java | 18 +++++ .../webmvc/servlet/view/JsonViewTest.java | 66 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 mvc/src/test/java/com/interface21/webmvc/servlet/view/JsonViewTest.java diff --git a/mvc/src/main/java/com/interface21/webmvc/servlet/view/JsonView.java b/mvc/src/main/java/com/interface21/webmvc/servlet/view/JsonView.java index 5da6bdb2eb..a7fe43b673 100644 --- a/mvc/src/main/java/com/interface21/webmvc/servlet/view/JsonView.java +++ b/mvc/src/main/java/com/interface21/webmvc/servlet/view/JsonView.java @@ -1,5 +1,8 @@ package com.interface21.webmvc.servlet.view; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.interface21.web.http.MediaType; import com.interface21.webmvc.servlet.View; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -8,7 +11,22 @@ public class JsonView implements View { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public JsonView() { + } + @Override public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + String json = serialize(model); + response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + response.getWriter().write(json); + } + + private String serialize(Map model) throws JsonProcessingException { + if (model.size() == 1) { + return objectMapper.writeValueAsString(model.values().iterator().next()); + } + return objectMapper.writeValueAsString(model); } } diff --git a/mvc/src/test/java/com/interface21/webmvc/servlet/view/JsonViewTest.java b/mvc/src/test/java/com/interface21/webmvc/servlet/view/JsonViewTest.java new file mode 100644 index 0000000000..a18d908616 --- /dev/null +++ b/mvc/src/test/java/com/interface21/webmvc/servlet/view/JsonViewTest.java @@ -0,0 +1,66 @@ +package com.interface21.webmvc.servlet.view; + +import com.interface21.web.http.MediaType; +import com.interface21.webmvc.servlet.View; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +class JsonViewTest { + + @DisplayName("Map에 저장된 데이터를 json으로 직렬화 성공") + @Test + void serialize() throws Exception { + //given + View jsonView = new JsonView(); + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + when(response.getWriter()).thenReturn(printWriter); + + Map model = new HashMap<>(); + model.put("name", "capy"); + model.put("age", 26); + + //when + jsonView.render(model, request, response); + printWriter.flush(); + String jsonOutput = stringWriter.toString(); + + //then + String expectedJson = "{\"name\":\"capy\",\"age\":26}"; + assertThat(jsonOutput).isEqualTo(expectedJson); + } + + @DisplayName("직렬화 시 response의 contentType을 APPLICATION_JSON_UTF8_VALUE으로 설정 성공") + @Test + void serialize_contentType() throws Exception { + //given + View jsonView = new JsonView(); + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + when(response.getWriter()).thenReturn(printWriter); + + Map model = new HashMap<>(); + + //when + jsonView.render(model, request, response); + + //then + verify(response).setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + } +} From b033bc16c0ff6f40b4c61ba1724fb1ad9c62c0fa Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Sun, 29 Sep 2024 23:24:50 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20RequestMapping=EC=9D=B4=20?= =?UTF-8?q?=EB=B6=99=EC=9D=80=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A7=8C=20?= =?UTF-8?q?=EC=8A=A4=EC=BA=94=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webmvc/servlet/mvc/tobe/AnnotationHandlerMapping.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mvc/src/main/java/com/interface21/webmvc/servlet/mvc/tobe/AnnotationHandlerMapping.java b/mvc/src/main/java/com/interface21/webmvc/servlet/mvc/tobe/AnnotationHandlerMapping.java index e154290509..0a1bf8af07 100644 --- a/mvc/src/main/java/com/interface21/webmvc/servlet/mvc/tobe/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/com/interface21/webmvc/servlet/mvc/tobe/AnnotationHandlerMapping.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; +import java.util.Arrays; public class AnnotationHandlerMapping implements HandlerMapping { @@ -29,9 +30,9 @@ public void initialize() { } private void scanClass(Class c) { - for (Method method : c.getDeclaredMethods()) { - registerRequestMappingHandlerExecution(c, method); - } + Arrays.stream(c.getDeclaredMethods()) + .filter(method -> method.isAnnotationPresent(RequestMapping.class)) + .forEach(method -> registerRequestMappingHandlerExecution(c, method)); } private void registerRequestMappingHandlerExecution(Class c, Method method) { From a0ae7611e507d666e95d9baa659d7563ca9d159b Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Mon, 30 Sep 2024 13:45:49 +0900 Subject: [PATCH 04/10] =?UTF-8?q?refactor:=20legacy=20MVC=EB=A5=BC=20?= =?UTF-8?q?=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HandlerAdaptersInitializer.java | 2 - .../HandlerMappingsInitializer.java | 1 - .../com/techcourse/ManualHandlerMapping.java | 37 ---- .../controller/ForwardController.java | 18 ++ .../controller/LoginController.java | 35 +++- .../controller/LoginViewController.java | 22 --- .../controller/LogoutController.java | 17 +- app/src/main/webapp/index.html | 187 +++++++++--------- app/src/main/webapp/index.jsp | 170 ++++++++-------- app/src/main/webapp/register.jsp | 111 ++++++----- .../webmvc/servlet/mvc/asis/Controller.java | 8 - .../servlet/mvc/asis/ForwardController.java | 20 -- .../mvc/tobe/ManualHandlerAdapter.java | 23 --- 13 files changed, 298 insertions(+), 353 deletions(-) delete mode 100644 app/src/main/java/com/techcourse/ManualHandlerMapping.java create mode 100644 app/src/main/java/com/techcourse/controller/ForwardController.java delete mode 100644 app/src/main/java/com/techcourse/controller/LoginViewController.java delete mode 100644 mvc/src/main/java/com/interface21/webmvc/servlet/mvc/asis/Controller.java delete mode 100644 mvc/src/main/java/com/interface21/webmvc/servlet/mvc/asis/ForwardController.java delete mode 100644 mvc/src/main/java/com/interface21/webmvc/servlet/mvc/tobe/ManualHandlerAdapter.java diff --git a/app/src/main/java/com/techcourse/HandlerAdaptersInitializer.java b/app/src/main/java/com/techcourse/HandlerAdaptersInitializer.java index 94a5f96889..a42c8a032e 100644 --- a/app/src/main/java/com/techcourse/HandlerAdaptersInitializer.java +++ b/app/src/main/java/com/techcourse/HandlerAdaptersInitializer.java @@ -2,7 +2,6 @@ import com.interface21.webmvc.servlet.mvc.tobe.AnnotationHandlerAdapter; import com.interface21.webmvc.servlet.mvc.tobe.HandlerAdapters; -import com.interface21.webmvc.servlet.mvc.tobe.ManualHandlerAdapter; public class HandlerAdaptersInitializer { @@ -11,7 +10,6 @@ public HandlerAdaptersInitializer() { public HandlerAdapters initialize() { HandlerAdapters handlerAdapters = new HandlerAdapters(); - handlerAdapters.addHandlerAdapter(new ManualHandlerAdapter()); handlerAdapters.addHandlerAdapter(new AnnotationHandlerAdapter()); return handlerAdapters; } diff --git a/app/src/main/java/com/techcourse/HandlerMappingsInitializer.java b/app/src/main/java/com/techcourse/HandlerMappingsInitializer.java index 04b39bd457..8bed32df19 100644 --- a/app/src/main/java/com/techcourse/HandlerMappingsInitializer.java +++ b/app/src/main/java/com/techcourse/HandlerMappingsInitializer.java @@ -10,7 +10,6 @@ public HandlerMappingsInitializer() { public HandlerMappings initialize() { HandlerMappings handlerMappings = new HandlerMappings(); - handlerMappings.addHandlerMapping(new ManualHandlerMapping()); handlerMappings.addHandlerMapping(new AnnotationHandlerMapping("com.techcourse.controller")); handlerMappings.initialize(); return handlerMappings; 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 ee9645ed58..0000000000 --- a/app/src/main/java/com/techcourse/ManualHandlerMapping.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.techcourse; - -import com.interface21.webmvc.servlet.mvc.tobe.HandlerMapping; -import com.techcourse.controller.*; -import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.interface21.webmvc.servlet.mvc.asis.Controller; -import com.interface21.webmvc.servlet.mvc.asis.ForwardController; - -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<>(); - - 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 Object findHandler(HttpServletRequest request) { - String requestURI = request.getRequestURI(); - log.debug("Request Mapping Uri : {}", requestURI); - return 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..7c5c093754 --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/ForwardController.java @@ -0,0 +1,18 @@ +package com.techcourse.controller; + +import com.interface21.context.stereotype.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.JspView; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Controller +public class ForwardController { + + @RequestMapping(value = "/", method = RequestMethod.GET) + public ModelAndView forward(HttpServletRequest request, HttpServletResponse response) { + 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 index 3a9cec2c63..e4f7e682c4 100644 --- a/app/src/main/java/com/techcourse/controller/LoginController.java +++ b/app/src/main/java/com/techcourse/controller/LoginController.java @@ -1,30 +1,47 @@ package com.techcourse.controller; +import com.interface21.context.stereotype.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.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; import jakarta.servlet.http.HttpSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class LoginController implements Controller { +@Controller +public class LoginController { private static final Logger log = LoggerFactory.getLogger(LoginController.class); - @Override - public String execute(HttpServletRequest req, HttpServletResponse res) throws Exception { - if (UserSession.isLoggedIn(req.getSession())) { - return "redirect:/index.jsp"; + @RequestMapping(value = "/login", method = RequestMethod.GET) + public ModelAndView loginView(HttpServletRequest request, HttpServletResponse response) { + return new ModelAndView(new JspView(UserSession.getUserFrom(request.getSession()) + .map(user -> { + log.info("logged in {}", user.getAccount()); + return "redirect:/index.jsp"; + }) + .orElse("/login.jsp") + )); + } + + @RequestMapping(value = "/login", method = RequestMethod.POST) + public ModelAndView login(HttpServletRequest request, HttpServletResponse response) { + if (UserSession.isLoggedIn(request.getSession())) { + new ModelAndView(new JspView("redirect:/index.jsp")); } - return InMemoryUserRepository.findByAccount(req.getParameter("account")) + return new ModelAndView(new JspView(InMemoryUserRepository.findByAccount(request.getParameter("account")) .map(user -> { log.info("User : {}", user); - return login(req, user); + return login(request, user); }) - .orElse("redirect:/401.jsp"); + .orElse("redirect:/401.jsp") + )); } private String login(HttpServletRequest request, User user) { diff --git a/app/src/main/java/com/techcourse/controller/LoginViewController.java b/app/src/main/java/com/techcourse/controller/LoginViewController.java deleted file mode 100644 index 841c4d7ba1..0000000000 --- a/app/src/main/java/com/techcourse/controller/LoginViewController.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.techcourse.controller; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.interface21.webmvc.servlet.mvc.asis.Controller; - -public class LoginViewController implements Controller { - - private static final Logger log = LoggerFactory.getLogger(LoginViewController.class); - - @Override - public String execute(HttpServletRequest req, HttpServletResponse res) throws Exception { - return UserSession.getUserFrom(req.getSession()) - .map(user -> { - log.info("logged in {}", user.getAccount()); - return "redirect:/index.jsp"; - }) - .orElse("/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 c6bd831ea9..b68ee3cf60 100644 --- a/app/src/main/java/com/techcourse/controller/LogoutController.java +++ b/app/src/main/java/com/techcourse/controller/LogoutController.java @@ -1,16 +1,21 @@ package com.techcourse.controller; +import com.interface21.context.stereotype.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.JspView; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import com.interface21.webmvc.servlet.mvc.asis.Controller; import jakarta.servlet.http.HttpSession; -public class LogoutController implements Controller { +@Controller +public class LogoutController { - @Override - public String execute(HttpServletRequest req, HttpServletResponse res) throws Exception { - HttpSession session = req.getSession(); + @RequestMapping(value = "/logout", method = RequestMethod.GET) + public ModelAndView loginView(HttpServletRequest request, HttpServletResponse response) { + HttpSession session = request.getSession(); session.removeAttribute(UserSession.SESSION_KEY); - return "redirect:/"; + return new ModelAndView(new JspView("redirect:/")); } } diff --git a/app/src/main/webapp/index.html b/app/src/main/webapp/index.html index 95df361069..207ce8e3a6 100644 --- a/app/src/main/webapp/index.html +++ b/app/src/main/webapp/index.html @@ -1,105 +1,112 @@ - - - - - - - 대시보드 - - - - - +
+
+ +
+
+
+
+

대시보드

+ +
+
+
+
+ + Bar Chart
-
-
-
- - Pie Chart -
-
-
+
+
-
- +
+
+ + + + + + + + + + diff --git a/app/src/main/webapp/index.jsp b/app/src/main/webapp/index.jsp index 142ee3d104..7d53adfbb2 100644 --- a/app/src/main/webapp/index.jsp +++ b/app/src/main/webapp/index.jsp @@ -1,97 +1,105 @@ <%@ page contentType="text/html;charset=UTF-8" %> - - <%@ include file="include/header.jspf" %> - 대시보드 - - -