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 구현하기 - 3단계] 여우(조승현) 미션 제출합니다 #618

Merged
merged 10 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import web.org.springframework.web.WebApplicationInitializer;
import webmvc.org.springframework.web.servlet.DispatcherServlet;

/**
* Base class for {@link WebApplicationInitializer}
Expand Down
39 changes: 0 additions & 39 deletions app/src/main/java/com/techcourse/ManualHandlerMapping.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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;

@Controller
public class IndexViewController {

@RequestMapping(value = "/", method = RequestMethod.GET)
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
return "/index.jsp";
}
}
20 changes: 13 additions & 7 deletions app/src/main/java/com/techcourse/controller/LoginController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,34 @@

import com.techcourse.domain.User;
import com.techcourse.repository.InMemoryUserRepository;
import context.org.springframework.stereotype.Controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import web.org.springframework.web.bind.annotation.RequestMapping;
import web.org.springframework.web.bind.annotation.RequestMethod;
import webmvc.org.springframework.web.servlet.ModelAndView;
import webmvc.org.springframework.web.servlet.view.JspView;

public class LoginController implements Controller {

@Controller
public class LoginController {

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

@Override
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ModelAndView execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
if (UserSession.isLoggedIn(req.getSession())) {
return "redirect:/index.jsp";
return new ModelAndView(new JspView("redirect:/index.jsp"));
}

return InMemoryUserRepository.findByAccount(req.getParameter("account"))
.map(user -> {
log.info("User : {}", user);
return login(req, user);
return new ModelAndView(new JspView(login(req, user)));
})
.orElse("redirect:/401.jsp");
.orElse(new ModelAndView(new JspView("redirect:/401.jsp")));
}

private String login(final HttpServletRequest request, final User user) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.techcourse.controller;

import context.org.springframework.stereotype.Controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;
import web.org.springframework.web.bind.annotation.RequestMapping;
import web.org.springframework.web.bind.annotation.RequestMethod;

public class LoginViewController implements Controller {
@Controller
public class LoginViewController {

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

@Override
@RequestMapping(value = "/login/view", method = RequestMethod.GET)
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
return UserSession.getUserFrom(req.getSession())
.map(user -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.techcourse.controller;

import context.org.springframework.stereotype.Controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;
import web.org.springframework.web.bind.annotation.RequestMapping;
import web.org.springframework.web.bind.annotation.RequestMethod;

public class LogoutController implements Controller {
@Controller
public class LogoutController {

@Override
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
final var session = req.getSession();
session.removeAttribute(UserSession.SESSION_KEY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import com.techcourse.domain.User;
import com.techcourse.repository.InMemoryUserRepository;
import context.org.springframework.stereotype.Controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;
import web.org.springframework.web.bind.annotation.RequestMapping;
import web.org.springframework.web.bind.annotation.RequestMethod;

public class RegisterController implements Controller {
@Controller
public class RegisterController {

@Override
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
final var user = new User(2,
req.getParameter("account"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.techcourse.controller;

import context.org.springframework.stereotype.Controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmvc.org.springframework.web.servlet.mvc.asis.Controller;
import web.org.springframework.web.bind.annotation.RequestMapping;
import web.org.springframework.web.bind.annotation.RequestMethod;

public class RegisterViewController implements Controller {
@Controller
public class RegisterViewController {

@Override
@RequestMapping(value = "/register/view", method = RequestMethod.GET)
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
return "/register.jsp";
}
Expand Down
33 changes: 33 additions & 0 deletions app/src/main/java/com/techcourse/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.techcourse.controlleradvisor;

import com.techcourse.exception.HandlerAdapterNotFoundException;
import com.techcourse.exception.HandlerNotFoundException;
import webmvc.org.springframework.web.servlet.exception.HandlerAdapterNotFoundException;
import webmvc.org.springframework.web.servlet.exception.HandlerNotFoundException;
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 web.org.springframework.http;

public class MediaType {
public static final String TEXT_PLAIN_UTF8_VALUE = "text/plain;charset=UTF-8";
public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8";
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.techcourse;
package webmvc.org.springframework.web.servlet;

import com.techcourse.controlleradapter.ControllerHandlerAdapter;
import com.techcourse.exception.HandlerAdapterNotFoundException;
import com.techcourse.exception.HandlerNotFoundException;
import webmvc.org.springframework.web.servlet.exception.HandlerAdapterNotFoundException;
import webmvc.org.springframework.web.servlet.exception.HandlerNotFoundException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -11,13 +10,10 @@
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import webmvc.org.springframework.web.servlet.ExceptionHandlerMapping;
import webmvc.org.springframework.web.servlet.HandlerMapping;
import webmvc.org.springframework.web.servlet.mvc.HandlerAdapter;
import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationExceptionHandlerMapping;
import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping;
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecutionHandlerAdapter;
import webmvc.org.springframework.web.servlet.view.JspView;

public class DispatcherServlet extends HttpServlet {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DispatcherServlet에서 필요한 필드인 exceptionHandlerMappings, handlerMappings, handlerAdaptersDispatcherServletInitializer에서 주입 시켜주시는 것에 대해 어떻게 생각하시나요?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가적으로 미션 2 힌트를 보셨을까요?
해당 미션 힌트에는HandlerAdapterRegistryHandlerMappingRegitry가 있었는데, 적용하지 않은 이유가 있을까요?
적용한다면 findHandler, findHandlerAdaptor 역할을 넘길 수 있을지도..?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2단계 진행 도중 힌트가 삭제돼서 Registry의 존재를 잊고 있었네요!
Registrty들을 사용해서 HandlerMapping들과 HandlerAdapter에 대한 관리 책임을 외부로 옮겼습니다.
혹시 DispatcherServlet 입장에서는
본인이 사용하는 객체에 대한 책임이 외부로 옮겨지는 것이니
이런 걸 IOC라고 부르는 걸까요? IOC가 무엇인지 개념이 잘 안 잡혀 있어서.. 🥹

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IOC 중 DI에 대한 이야기였습니다.
사실 의견을 여쭤본 이유가 예전 레벨 1, 2 때는 보통 객체의 필드들을 외부에서 생성해 의존성 주입을 시켜줬던 기억이 있어 저는 그렇게 진행하게 되었습니다.
그런데 여러 pr을 보다보니 저와 비슷하게 진행한 크루들도 있고 그렇지 않은 크루들도 있는 것 같아 여우의 의견도 궁금해 질문드리게 되었습니디!

Expand All @@ -29,13 +25,11 @@ public class DispatcherServlet extends HttpServlet {
);

private List<HandlerMapping> handlerMappings = List.of(
new ManualHandlerMapping(),
new AnnotationHandlerMapping("com/techcourse")
);

private List<HandlerAdapter> handlerAdapters = List.of(
new HandlerExecutionHandlerAdapter(),
new ControllerHandlerAdapter()
new HandlerExecutionHandlerAdapter()
);

public DispatcherServlet() {
Expand All @@ -60,8 +54,8 @@ protected void service(final HttpServletRequest request, final HttpServletRespon
final Object handler = findHandler(request);

final HandlerAdapter handlerAdapter = findHandlerAdaptor(handler);
final String viewPath = handlerAdapter.invoke(handler, request, response);
move(viewPath, request, response);
final ModelAndView modelAndView = handlerAdapter.invoke(handler, request, response);
modelAndView.getView().render(modelAndView.getModel(), request, response);
} catch (Throwable e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

view와 model을 가져오지 않고 ModelAndView에서 render를 수행해주는 방향으로 가면 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오,, 캡슐화!

handleException(request, response, e);
}
Expand All @@ -86,19 +80,8 @@ private HandlerAdapter findHandlerAdaptor(final Object handler) {
throw new HandlerAdapterNotFoundException("Handler Adaptor Not found");
}

private void move(final String viewName, final HttpServletRequest request, final HttpServletResponse response) throws Exception {
if (viewName.startsWith(JspView.REDIRECT_PREFIX)) {
response.sendRedirect(viewName.substring(JspView.REDIRECT_PREFIX.length()));
return;
}

final var requestDispatcher = request.getRequestDispatcher(viewName);
requestDispatcher.forward(request, response);
}

private void handleException(final HttpServletRequest request, final HttpServletResponse response, final Throwable e) {
try {
Object handler = null;
try {Object handler = null;
for (ExceptionHandlerMapping exceptionHandlerMapping : exceptionHandlerMappings) {
final Object foundHandler = findExceptionHandler(e, exceptionHandlerMapping);
if (Objects.nonNull(foundHandler)) {
Expand All @@ -111,8 +94,8 @@ private void handleException(final HttpServletRequest request, final HttpServlet
throw new ServletException("ExceptionHandler Not Found.");
}
final HandlerAdapter handlerAdapter = findHandlerAdaptor(handler);
final String viewPath = handlerAdapter.invoke(handler, request, response);
move(viewPath, request, response);
final ModelAndView modelAndView = handlerAdapter.invoke(handler, request, response);
modelAndView.getView().render(modelAndView.getModel(), request, response);
} catch (Exception exception) {
log.error("Exception caused in ExceptionHandler");
throw new RuntimeException(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.techcourse.exception;
package webmvc.org.springframework.web.servlet.exception;

public class DispatcherServletException extends RuntimeException {
public DispatcherServletException(final String message) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.techcourse.exception;
package webmvc.org.springframework.web.servlet.exception;

public class HandlerAdapterNotFoundException extends DispatcherServletException {
public HandlerAdapterNotFoundException(final String message) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.techcourse.exception;
package webmvc.org.springframework.web.servlet.exception;

public class HandlerNotFoundException extends DispatcherServletException {
public HandlerNotFoundException(final String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmvc.org.springframework.web.servlet.ModelAndView;

public interface HandlerAdapter {

boolean support(Object handler);

String invoke(Object handler, HttpServletRequest request, HttpServletResponse response) throws Exception;
ModelAndView invoke(Object handler, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

This file was deleted.

Loading
Loading