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단계] 호이(이건호) 미션 제출합니다. #604

Merged
merged 10 commits into from
Sep 30, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import web.org.springframework.web.WebApplicationInitializer;
import webmvc.org.springframework.web.servlet.mvc.asis.ManualHandlerAdapter;
import webmvc.org.springframework.web.servlet.mvc.DispatcherServlet;
import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerAdapter;
import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping;
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapters;
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMappings;

/**
* Base class for {@link WebApplicationInitializer}
* implementations that register a {@link DispatcherServlet} in the servlet context.
* Base class for {@link WebApplicationInitializer} implementations that register a {@link DispatcherServlet} in the
* servlet context.
*/
public class DispatcherServletInitializer implements WebApplicationInitializer {

Expand All @@ -23,11 +23,9 @@ public class DispatcherServletInitializer implements WebApplicationInitializer {
@Override
public void onStartup(final ServletContext servletContext) {
final HandlerMappings handlerMappings = new HandlerMappings();
handlerMappings.add(new ManualHandlerMapping());
handlerMappings.add(new AnnotationHandlerMapping());
handlerMappings.add(new AnnotationHandlerMapping(this.getClass().getPackageName()));

final HandlerAdapters handlerAdapters = new HandlerAdapters();
handlerAdapters.add(new ManualHandlerAdapter());
handlerAdapters.add(new AnnotationHandlerAdapter());

final var dispatcherServlet = new DispatcherServlet(handlerMappings, handlerAdapters);
Expand Down
39 changes: 0 additions & 39 deletions app/src/main/java/com/techcourse/ManualHandlerMapping.java

This file was deleted.

17 changes: 17 additions & 0 deletions app/src/main/java/com/techcourse/controller/ForwardController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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;

@Controller
public class ForwardController {

@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView execute(final HttpServletRequest request, final HttpServletResponse response) {
return new ModelAndView(JspViews.toIndexPage());
}
}
25 changes: 25 additions & 0 deletions app/src/main/java/com/techcourse/controller/JspViews.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.techcourse.controller;

import webmvc.org.springframework.web.servlet.view.JspView;

public class JspViews {

private JspViews() {
}

public static JspView toIndexPage() {
return new JspView("/index.jsp");
}

public static JspView toLoginPage() {
return new JspView("/login.jsp");
}

public static JspView to401Page() {
return new JspView("/401.jsp");
}

public static JspView toRegisterPage() {
return new JspView("/register.jsp");
}
}
32 changes: 23 additions & 9 deletions app/src/main/java/com/techcourse/controller/LoginController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,50 @@

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;

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.GET)
public ModelAndView loginPage(final HttpServletRequest req, final HttpServletResponse res) {
return UserSession.getUserFrom(req.getSession())
.map(user -> {
log.info("logged in {}", user.getAccount());
return new ModelAndView(JspViews.toIndexPage());
})
.orElse(new ModelAndView(JspViews.toLoginPage()));
}

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

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

private String login(final HttpServletRequest request, final User user) {
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 "redirect:/index.jsp";
return new ModelAndView(JspViews.toIndexPage());
}
return "redirect:/401.jsp";
return new ModelAndView(JspViews.to401Page());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
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;
import webmvc.org.springframework.web.servlet.ModelAndView;

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

@Override
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public ModelAndView execute(final HttpServletRequest req, final HttpServletResponse res) {
final var session = req.getSession();
session.removeAttribute(UserSession.SESSION_KEY);
return "redirect:/";
return new ModelAndView(JspViews.toIndexPage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
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 RegisterController {
Expand All @@ -21,11 +20,11 @@ public ModelAndView save(HttpServletRequest req, HttpServletResponse res) {
req.getParameter("email"));
InMemoryUserRepository.save(user);

return new ModelAndView(new JspView("/index.jsp"));
return new ModelAndView(JspViews.toIndexPage());
}

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

This file was deleted.

32 changes: 32 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,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.info("user id : {}", account);

final ModelAndView modelAndView = new ModelAndView(new JsonView());
final User user = InMemoryUserRepository.findByAccount(account)
.orElseThrow();

modelAndView.addObject("user", user);
return modelAndView;
}
}
2 changes: 1 addition & 1 deletion app/src/main/webapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<!-- before login -->
<div class="navbar-nav d-none d-md-inline-block ms-auto me-0 me-md-3 my-2 my-md-0">
<a class="nav-link" href="/login/view" role="button"><i class="fas fa-user fa-fw"></i>&nbsp;로그인</a>
<a class="nav-link" href="/login" role="button"><i class="fas fa-user fa-fw"></i>&nbsp;로그인</a>
</div>
<!-- before login -->

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/webapp/index.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
</div>
<% } else { %>
<div class="navbar-nav d-none d-md-inline-block ms-auto me-0 me-md-3 my-2 my-md-0">
<a class="nav-link" href="/login/view" role="button"><i class="fas fa-user fa-fw"></i>&nbsp;로그인</a>
<a class="nav-link" href="/login" role="button"><i class="fas fa-user fa-fw"></i>&nbsp;로그인</a>
</div>
<% } %>
</nav>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/webapp/register.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
</form>
</div>
<div class="card-footer text-center py-3">
<div class="small"><a href="/login/view">이미 가입하셨나요? 로그인 하러가기</a></div>
<div class="small"><a href="/login">이미 가입하셨나요? 로그인 하러가기</a></div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package webmvc.org.springframework.web.servlet;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -30,4 +32,12 @@ public Map<String, Object> getModel() {
public View getView() {
return view;
}

public void render(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (view.isRedirect()) {
response.sendRedirect(view.getViewName());
return;
}
view.render(model, request, response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@

public interface View {
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;

boolean isRedirect();

String getViewName();
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.techcourse;
package webmvc.org.springframework.web.servlet.mvc;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import webmvc.org.springframework.web.servlet.ModelAndView;
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapter;
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerAdapters;
import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMappings;
Expand Down Expand Up @@ -38,7 +39,8 @@ protected void service(final HttpServletRequest request, final HttpServletRespon
final Object handler = handlerMappings.getHandler(request);
final HandlerAdapter handlerAdapter = handlerAdapters.getHandlerAdapter(handler);

handlerAdapter.execute(request, response, handler);
final ModelAndView mav = handlerAdapter.execute(request, response, handler);
mav.render(request, response);
} catch (Throwable e) {
Comment on lines +42 to +43

Choose a reason for hiding this comment

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

(단순 질문입니다)
HandlerAdapter에서 view를 rendering하는 역할까지 부여하는 것에 대해서는 어떻게 생각하시나요?
이렇게 구현하신 이유가 궁금합니다!

Copy link
Author

Choose a reason for hiding this comment

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

이 부분을 구현할 때 3가지 방법이 있을 거 같습니다.

1번

handlerAdapter.execute(request, response, handler);

2번

final ModelAndView mav = handlerAdapter.execute(request, response, handler);
mav.render(request, response);

3번

final ModelAndView mav = handlerAdapter.execute(request, response, handler);
final Map<String, Object> model = mav.getModel();
final View view = mav.getView();
view.render(model, request, response);

1번을 사용하면 코드가 깔끔해지지만 HandlerAdapter가 너무 많은 책임을 갖게 되고...
3번을 사용하면 책임 분리가 잘 되었지만 응집성이 초큼 떨어지는 거 같습니다..

그래서 적당한.. 2번 방식을.. 사실 ModelAndView의 책임을 어디까지로 보는게 맞는지 잘 모르겠네요..
(Model도 View에 사용하는 데이터이니... 렌더링 해줘도 되지않을....)

그래도 2번이 아닌 1번과 3번을 선택해야 한다면 3번을 선택할 거 같습니다..!

말랑의 생각도 궁금합니다!

log.error("Exception : {}", e.getMessage(), e);
throw new ServletException(e.getMessage());
Expand Down

This file was deleted.

Loading
Loading