Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MVC 구현하기 - 2단계] 무민(박무현) 미션 제출합니다. #440

Merged
merged 27 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ce31af2
refactor: forEach 제거
parkmuhyeun Sep 14, 2023
3356dd2
chore: legacy controller 패키지 이동
parkmuhyeun Sep 14, 2023
c01a460
feat: HandlerMapping 생성
parkmuhyeun Sep 14, 2023
ff180ef
refactor: ModelAndView view 타입 수정
parkmuhyeun Sep 14, 2023
e617f1f
feat: HandlerAdapter 생성
parkmuhyeun Sep 14, 2023
1d02199
feat: HandlerExecutor 생성
parkmuhyeun Sep 14, 2023
ac05369
test: ControllerAdapter 테스트
parkmuhyeun Sep 14, 2023
125898d
test: HandlerExecutionAdapter 테스트
parkmuhyeun Sep 14, 2023
d4c4999
test: HandlerExecutor 테스트
parkmuhyeun Sep 14, 2023
d5a1785
refactor: 객체 분리에 따른 DispatcherServlet 수정
parkmuhyeun Sep 14, 2023
1f19ab4
test: DispatcherServlet 테스트
parkmuhyeun Sep 14, 2023
3917685
feat: MvcRegisterController 생성
parkmuhyeun Sep 14, 2023
be4ac06
test: MvcRegisterController 테스트
parkmuhyeun Sep 14, 2023
af4f14d
feat: MvcLoginController 생성
parkmuhyeun Sep 14, 2023
2dafe09
test: MvcLoginController 테스트
parkmuhyeun Sep 14, 2023
a424c65
feat: MvcLogoutController 생성
parkmuhyeun Sep 14, 2023
1a25792
test: MvcLogoutController 테스트
parkmuhyeun Sep 14, 2023
b421e0c
refactor: var 수정
parkmuhyeun Sep 14, 2023
4c80be3
refactor: 중복 코드 ControllerTest 분리
parkmuhyeun Sep 14, 2023
c800cab
feat: MvcForwardController 생성
parkmuhyeun Sep 14, 2023
0e90672
test: MvcForwardController 테스트
parkmuhyeun Sep 14, 2023
0e3a094
refactor: controller 한번만 인스턴스화 하도록 수정
parkmuhyeun Sep 19, 2023
ed2c28d
refactor: 로그 위치 변경
parkmuhyeun Sep 19, 2023
103b192
refactor: Scanner 분리
parkmuhyeun Sep 19, 2023
4b5b471
refactor: handler가 null일 때 수정
parkmuhyeun Sep 19, 2023
e483ea6
refactor: 마지막줄 개행 추가
parkmuhyeun Sep 19, 2023
9cb027d
refactor: handlerMapping 공존
parkmuhyeun Sep 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
parkmuhyeun marked this conversation as resolved.
Show resolved Hide resolved
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
Loading