Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
56 changes: 41 additions & 15 deletions app/src/main/java/com/techcourse/DispatcherServlet.java
Original file line number Diff line number Diff line change
@@ -1,51 +1,77 @@
package com.techcourse;

import com.interface21.webmvc.servlet.ModelAndView;
import com.interface21.webmvc.servlet.View;
import com.interface21.webmvc.servlet.mvc.tobe.HandlerAdapter;
import com.interface21.webmvc.servlet.mvc.tobe.HandlerAdapterRegistry;
import com.interface21.webmvc.servlet.mvc.tobe.HandlerMapping;
import com.interface21.webmvc.servlet.mvc.tobe.HandlerMappingRegistry;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.interface21.webmvc.servlet.view.JspView;

public class DispatcherServlet extends HttpServlet {

private static final String BASE_PACKAGE = "com.techcourse.controller";
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class);

private ManualHandlerMapping manualHandlerMapping;
private final HandlerAdapterRegistry handlerAdapterRegistry;
private final HandlerMappingRegistry handlerMappingRegistry;

public DispatcherServlet() {
handlerAdapterRegistry = new HandlerAdapterRegistry();
handlerMappingRegistry = new HandlerMappingRegistry(BASE_PACKAGE);
}

@Override
public void init() {
manualHandlerMapping = new ManualHandlerMapping();
manualHandlerMapping.initialize();
handlerAdapterRegistry.initialize();
handlerMappingRegistry.initialize();
}

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

try {
final var controller = manualHandlerMapping.getHandler(requestURI);
final var viewName = controller.execute(request, response);
move(viewName, request, response);
Object handler = findHandler(request);
HandlerAdapter handlerAdapter = findHandlerAdapter(handler);
ModelAndView modelAndView = handlerAdapter.handle(request, response, handler);
renderViewWithModel(request, response, modelAndView);
} catch (Throwable e) {
log.error("Exception : {}", e.getMessage(), e);
throw new ServletException(e.getMessage());
}
}

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;
}
private Object findHandler(HttpServletRequest request) {
return handlerMappingRegistry.getHandler(request)
.orElseThrow(() -> new IllegalArgumentException(
"No handler found for request URI: " + request.getRequestURI()));
}

private HandlerAdapter findHandlerAdapter(Object handler) {
return handlerAdapterRegistry.getHandlerAdapter(handler).orElseThrow(
() -> new IllegalArgumentException(
"No handler adapter found for handler: " + handler.getClass()));
}

private void renderViewWithModel(HttpServletRequest request, HttpServletResponse response,
ModelAndView modelAndView)
throws Exception {
Map<String, Object> model = modelAndView.getModel();
View view = modelAndView.getView();
view.render(model, request, response);
}

final var requestDispatcher = request.getRequestDispatcher(viewName);
requestDispatcher.forward(request, response);
public void addHandlerMapping(HandlerMapping handlerMapping) {
handlerMappingRegistry.addHandlerMapping(handlerMapping);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.techcourse;

import com.interface21.web.WebApplicationInitializer;
import jakarta.servlet.ServletContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.interface21.web.WebApplicationInitializer;

/**
* 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 @@ -18,6 +18,7 @@ public class DispatcherServletInitializer implements WebApplicationInitializer {
@Override
public void onStartup(final ServletContext servletContext) {
final var dispatcherServlet = new DispatcherServlet();
dispatcherServlet.addHandlerMapping(new ManualHandlerMapping());

final var registration = servletContext.addServlet(DEFAULT_SERVLET_NAME, dispatcherServlet);
if (registration == null) {
Expand Down
24 changes: 13 additions & 11 deletions app/src/main/java/com/techcourse/ManualHandlerMapping.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package com.techcourse;

import com.techcourse.controller.*;
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 com.interface21.webmvc.servlet.mvc.tobe.HandlerMapping;
import com.techcourse.controller.LoginController;
import com.techcourse.controller.LoginViewController;
import com.techcourse.controller.LogoutController;
import jakarta.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ManualHandlerMapping {
public class ManualHandlerMapping implements HandlerMapping {

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

Expand All @@ -20,15 +23,14 @@ public void initialize() {
controllers.put("/login", new LoginController());
controllers.put("/login/view", new LoginViewController());
controllers.put("/logout", new LogoutController());
controllers.put("/register/view", new RegisterViewController());
controllers.put("/register", new RegisterController());

log.info("Initialized Handler Mapping!");
controllers.keySet()
.forEach(path -> log.info("Path : {}, Controller : {}", path, controllers.get(path).getClass()));
log.info("Initialized ManualHandlerMapping!");
controllers.forEach((path, controller) -> log.info("Path : {}, Controller : {}", path, controller.getClass()));
}

public Controller getHandler(final String requestURI) {
@Override
public Object 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,21 +1,31 @@
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;

public class RegisterController implements Controller {
@Controller
@RequestMapping("/register")
public class RegisterController {

@Override
public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception {
@RequestMapping(value = "/view", method = RequestMethod.GET)
public ModelAndView show() {
return new ModelAndView(new JspView("/register.jsp"));
}

@RequestMapping(method = RequestMethod.POST)
public ModelAndView save(final HttpServletRequest req) {
final var user = new User(2,
req.getParameter("account"),
req.getParameter("password"),
req.getParameter("email"));
InMemoryUserRepository.save(user);

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

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AnnotationHandlerMapping {
public class AnnotationHandlerMapping implements HandlerMapping {

private static final Logger log = LoggerFactory.getLogger(AnnotationHandlerMapping.class);
private static final String DELIMITER_PATH = "/";
Expand All @@ -27,10 +27,13 @@ public AnnotationHandlerMapping(final Object... basePackage) {
this.handlerExecutions = new HashMap<>();
}

@Override
public void initialize() {
log.info("Initialized AnnotationHandlerMapping!");
Reflections reflections = new Reflections(basePackage);
reflections.getTypesAnnotatedWith(Controller.class).forEach(this::assignHandlerByClass);

handlerExecutions.forEach((key, execution) -> log.info("Key : {}, Execution : {}", key, execution));
}

private void assignHandlerByClass(Class<?> clazz) {
Expand Down Expand Up @@ -64,6 +67,10 @@ private void assignHandlerByMethod(Class<?> clazz, Method method, String basePat
}

private String generateEndpoint(String basePath, String subPath) {
if (subPath.isBlank()) {
return String.join(DELIMITER_PATH, DELIMITER_PATH, basePath)
.replaceAll(REGEX_MANY_PATH_DELIMITER, DELIMITER_PATH);
}
return String.join(DELIMITER_PATH, DELIMITER_PATH, basePath, subPath)
.replaceAll(REGEX_MANY_PATH_DELIMITER, DELIMITER_PATH);
}
Expand All @@ -85,6 +92,7 @@ private HandlerExecution findHandlerExecution(Class<?> clazz, Method method) {
return null;
}

@Override
public Object getHandler(final HttpServletRequest request) {
RequestMethod requestMethod;
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.interface21.webmvc.servlet.mvc.tobe;

import com.interface21.webmvc.servlet.ModelAndView;
import com.interface21.webmvc.servlet.mvc.asis.Controller;
import com.interface21.webmvc.servlet.view.JspView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class ControllerHandlerAdapter implements HandlerAdapter {

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

@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String viewName = ((Controller) handler).execute(request, response);
return new ModelAndView(new JspView(viewName));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.interface21.webmvc.servlet.mvc.tobe;

import com.interface21.webmvc.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class ExecutionHandlerAdapter implements HandlerAdapter {

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

@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((HandlerExecution) handler).handle(request, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.interface21.webmvc.servlet.mvc.tobe;

import com.interface21.webmvc.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public interface HandlerAdapter {
boolean supports(Object handler);

ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.interface21.webmvc.servlet.mvc.tobe;

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

public class HandlerAdapterRegistry {

private final List<HandlerAdapter> handlerAdapters;

public HandlerAdapterRegistry() {
this.handlerAdapters = new ArrayList<>();
}

public void initialize() {
addHandlerAdapter(new ExecutionHandlerAdapter());
addHandlerAdapter(new ControllerHandlerAdapter());
}

public void addHandlerAdapter(HandlerAdapter handlerAdapter) {
handlerAdapters.add(handlerAdapter);
}

public Optional<HandlerAdapter> getHandlerAdapter(Object handler) {
return handlerAdapters.stream()
.filter(adapter -> adapter.supports(handler))
.findAny();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,12 @@ private Object decideArgumentByParameter(Class<?> param, List<Object> preparedAr
.findAny()
.orElse(null);
}

@Override
public String toString() {
return "HandlerExecution{" +
"method=" + method +
", controllerInstance=" + controllerInstance +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.interface21.webmvc.servlet.mvc.tobe;

import jakarta.servlet.http.HttpServletRequest;

public interface HandlerMapping {

void initialize();

Object getHandler(HttpServletRequest request);
}
Loading