Skip to content

Commit

Permalink
[MVC 구현하기 - 2단계] 무민(박무현) 미션 제출합니다. (#440)
Browse files Browse the repository at this point in the history
* refactor: forEach 제거

* chore: legacy controller 패키지 이동

* feat: HandlerMapping 생성

* refactor: ModelAndView view 타입 수정

* feat: HandlerAdapter 생성

* feat: HandlerExecutor 생성

* test: ControllerAdapter 테스트

* test: HandlerExecutionAdapter 테스트

* test: HandlerExecutor 테스트

* refactor: 객체 분리에 따른 DispatcherServlet 수정

* test: DispatcherServlet 테스트

* feat: MvcRegisterController 생성

* test: MvcRegisterController 테스트

* feat: MvcLoginController 생성

* test: MvcLoginController 테스트

* feat: MvcLogoutController 생성

* test: MvcLogoutController 테스트

* refactor: var 수정

* refactor: 중복 코드 ControllerTest 분리

* feat: MvcForwardController 생성

* test: MvcForwardController 테스트

* refactor: controller 한번만 인스턴스화 하도록 수정

* refactor: 로그 위치 변경

* refactor: Scanner 분리

* refactor: handler가 null일 때 수정

* refactor: 마지막줄 개행 추가

* refactor: handlerMapping 공존
  • Loading branch information
parkmuhyeun authored Sep 21, 2023
1 parent 674e092 commit 05db874
Show file tree
Hide file tree
Showing 33 changed files with 990 additions and 46 deletions.
18 changes: 18 additions & 0 deletions app/src/main/java/com/techcourse/ControllerAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.techcourse;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;

public class ControllerAdapter implements HandlerAdapter {

@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}

@Override
public String adapt(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return ((Controller) handler).execute(request, response);
}
}
29 changes: 22 additions & 7 deletions app/src/main/java/com/techcourse/DispatcherServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,48 @@ public class DispatcherServlet extends HttpServlet {

private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class);
private static final String NOT_FOUND_VIEW = "404.jsp";

private ManualHandlerMapping manualHandlerMapping;
private HandlerMappings handlerMappings;
private HandlerExecutor handlerExecutor;

public DispatcherServlet() {
}

public DispatcherServlet(HandlerMappings handlerMappings, HandlerExecutor handlerExecutor) {
this.handlerMappings = handlerMappings;
this.handlerExecutor = handlerExecutor;
}

@Override
public void init() {
manualHandlerMapping = new ManualHandlerMapping();
manualHandlerMapping.initialize();
handlerMappings = new HandlerMappings();
handlerExecutor = new HandlerExecutor();
handlerMappings.init();
}

@Override
protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
final String requestURI = request.getRequestURI();
log.debug("Method : {}, Request URI : {}", request.getMethod(), requestURI);
log.debug("Method : {}, Request URI : {}", request.getMethod(), request.getRequestURI());

try {
final var controller = manualHandlerMapping.getHandler(requestURI);
final var viewName = controller.execute(request, response);
String viewName = findViewName(request, response);

move(viewName, request, response);
} catch (Throwable e) {
log.error("Exception : {}", e.getMessage(), e);
throw new ServletException(e.getMessage());
}
}

private String findViewName(HttpServletRequest request, HttpServletResponse response) throws Exception {
Object handler = handlerMappings.getHandler(request);
if (handler == null) {
return NOT_FOUND_VIEW;
}
return handlerExecutor.execute(request, response, handler);
}

private void move(final String viewName, final HttpServletRequest request, final HttpServletResponse response) throws Exception {
if (viewName.startsWith(JspView.REDIRECT_PREFIX)) {
response.sendRedirect(viewName.substring(JspView.REDIRECT_PREFIX.length()));
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/com/techcourse/HandlerAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.techcourse;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public interface HandlerAdapter {

boolean supports(Object handler);

String adapt(HttpServletRequest request, final HttpServletResponse response, Object handler) throws Exception;
}
20 changes: 20 additions & 0 deletions app/src/main/java/com/techcourse/HandlerExecutionAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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.tobe.HandlerExecution;

public class HandlerExecutionAdapter implements HandlerAdapter {

@Override
public boolean supports(Object handler) {
return (handler instanceof HandlerExecution);
}

@Override
public String adapt(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
ModelAndView handle = ((HandlerExecution) handler).handle(request, response);
return (String) handle.getView();
}
}
23 changes: 23 additions & 0 deletions app/src/main/java/com/techcourse/HandlerExecutor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.techcourse;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.util.Set;

public class HandlerExecutor {

private static final Set<HandlerAdapter> handlerAdapters = Set.of(
new ControllerAdapter(),
new HandlerExecutionAdapter()
);

public String execute(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
for (HandlerAdapter handlerAdapter : handlerAdapters) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter.adapt(request, response, handler);
}
}
throw new IllegalArgumentException("Not found handler adapter for handler : " + handler);
}
}
31 changes: 31 additions & 0 deletions app/src/main/java/com/techcourse/HandlerMappings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.techcourse;

import jakarta.servlet.http.HttpServletRequest;
import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping;
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMapping;

import java.util.ArrayList;
import java.util.List;

public class HandlerMappings {

private List<HandlerMapping> handlerMappings = new ArrayList<>();

public void init() {
handlerMappings.add(new AnnotationHandlerMapping());
handlerMappings.add(new ManualHandlerMapping());
for (HandlerMapping handlerMapping : handlerMappings) {
handlerMapping.initialize();
}
}

public Object getHandler(HttpServletRequest request) {
for (HandlerMapping handlerMapping : handlerMappings) {
Object handler = handlerMapping.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
}
13 changes: 10 additions & 3 deletions app/src/main/java/com/techcourse/ManualHandlerMapping.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package com.techcourse;

import com.techcourse.controller.*;
import com.techcourse.controller.legacy.LoginController;
import com.techcourse.controller.legacy.LoginViewController;
import com.techcourse.controller.legacy.LogoutController;
import com.techcourse.controller.legacy.RegisterController;
import com.techcourse.controller.legacy.RegisterViewController;
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 {
public class ManualHandlerMapping implements HandlerMapping {

private static final Logger log = LoggerFactory.getLogger(ManualHandlerMapping.class);

Expand All @@ -28,7 +34,8 @@ public void initialize() {
.forEach(path -> log.info("Path : {}, Controller : {}", path, controllers.get(path).getClass()));
}

public Controller getHandler(final String requestURI) {
public Controller getHandler(HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.debug("Request Mapping Uri : {}", requestURI);
return controllers.get(requestURI);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.techcourse.controller;
package com.techcourse.controller.legacy;

import com.techcourse.controller.UserSession;
import com.techcourse.domain.User;
import com.techcourse.repository.InMemoryUserRepository;
import jakarta.servlet.http.HttpServletRequest;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.techcourse.controller;
package com.techcourse.controller.legacy;

import com.techcourse.controller.UserSession;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.techcourse.controller;
package com.techcourse.controller.legacy;

import com.techcourse.controller.UserSession;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.techcourse.controller;
package com.techcourse.controller.legacy;

import com.techcourse.domain.User;
import com.techcourse.repository.InMemoryUserRepository;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.techcourse.controller;
package com.techcourse.controller.legacy;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.techcourse.controller.mvc;

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;

@Controller
public class MvcForwardController {

private static final Logger log = LoggerFactory.getLogger(MvcForwardController.class);

@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView viewIndex(HttpServletRequest req, HttpServletResponse res) {
return new ModelAndView("/index.jsp");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.techcourse.controller.mvc;

import com.techcourse.controller.UserSession;
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 jakarta.servlet.http.HttpSession;
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;

@Controller
public class MvcLoginController {

private static final Logger log = LoggerFactory.getLogger(MvcLoginController.class);

@RequestMapping(value = "/login", method = RequestMethod.POST)
public ModelAndView loginUser(HttpServletRequest req, HttpServletResponse res) {
if (UserSession.isLoggedIn(req.getSession())) {
return new ModelAndView("redirect:/index.jsp");
}
return new ModelAndView(
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"))) {
HttpSession session = request.getSession();
session.setAttribute(UserSession.SESSION_KEY, user);
return "redirect:/index.jsp";
}
return "redirect:/401.jsp";
}

@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView viewLogin(HttpServletRequest req, HttpServletResponse res) {
return new ModelAndView(
UserSession.getUserFrom(req.getSession())
.map(user -> {
log.info("logged in {}", user.getAccount());
return "redirect:/index.jsp";
})
.orElse("/login.jsp")
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.techcourse.controller.mvc;

import com.techcourse.controller.UserSession;
import context.org.springframework.stereotype.Controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
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;

@Controller
public class MvcLogoutController {

private static final Logger log = LoggerFactory.getLogger(MvcLogoutController.class);

@RequestMapping(value = "/logout", method = RequestMethod.POST)
public ModelAndView logoutUser(HttpServletRequest req, HttpServletResponse res) {
HttpSession session = req.getSession();
session.removeAttribute(UserSession.SESSION_KEY);
return new ModelAndView("redirect:/");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.techcourse.controller.mvc;

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;

@Controller
public class MvcRegisterController {

private static final Logger log = LoggerFactory.getLogger(MvcRegisterController.class);

@RequestMapping(value = "/register", method = RequestMethod.POST)
public ModelAndView registerUser(HttpServletRequest req, HttpServletResponse res) {
User user = new User(2,
req.getParameter("account"),
req.getParameter("password"),
req.getParameter("email"));
InMemoryUserRepository.save(user);

return new ModelAndView("redirect:/index.jsp");
}

@RequestMapping(value = "/register", method = RequestMethod.GET)
public ModelAndView viewRegister(HttpServletRequest req, HttpServletResponse res) {
return new ModelAndView("/register.jsp");
}
}
Loading

0 comments on commit 05db874

Please sign in to comment.