#22 mvc: annotation based

This commit is contained in:
haerong22
2022-10-12 23:57:50 +09:00
parent dd97887635
commit c4b7873125
10 changed files with 159 additions and 14 deletions

View File

@@ -0,0 +1,23 @@
package org.example.mvc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class AnnotationHandler {
private final Class<?> clazz;
private final Method tagetMethod;
public AnnotationHandler(Class<?> clazz, Method targetMethod) {
this.clazz = clazz;
this.tagetMethod = targetMethod;
}
public String handle(HttpServletRequest request, HttpServletResponse response) throws Exception {
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
Object handler = declaredConstructor.newInstance();
return (String) tagetMethod.invoke(handler, request, response);
}
}

View File

@@ -0,0 +1,19 @@
package org.example.mvc;
import org.example.mvc.view.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AnnotationHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof AnnotationHandler;
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String viewName = ((AnnotationHandler) handler).handle(request, response);
return new ModelAndView(viewName);
}
}

View File

@@ -0,0 +1,49 @@
package org.example.mvc;
import org.example.mvc.annotation.Controller;
import org.example.mvc.annotation.RequestMapping;
import org.example.mvc.controller.HandlerKey;
import org.example.mvc.controller.RequestMethod;
import org.reflections.Reflections;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class AnnotationHandlerMapping implements HandlerMapping {
private final Object[] basePackage;
private Map<HandlerKey, AnnotationHandler> handlers = new HashMap<>();
public AnnotationHandlerMapping(Object... basePackage) {
this.basePackage = basePackage;
}
public void init() {
Reflections reflections = new Reflections(basePackage);
Set<Class<?>> classes = reflections.getTypesAnnotatedWith(Controller.class);
classes.forEach(clazz -> {
Arrays.stream(clazz.getDeclaredMethods()).forEach(method -> {
RequestMapping requestMapping = method.getDeclaredAnnotation(RequestMapping.class);
Arrays.stream(getRequestMethods(requestMapping))
.forEach(requestMethod -> handlers.put(
new HandlerKey(requestMethod, requestMapping.value()), new AnnotationHandler(clazz, method)
));
});
});
}
private RequestMethod[] getRequestMethods(RequestMapping requestMapping) {
return requestMapping.method();
}
@Override
public Object findHandler(HandlerKey handlerKey) {
return handlers.get(handlerKey);
}
}

View File

@@ -1,6 +1,5 @@
package org.example.mvc; package org.example.mvc;
import org.example.mvc.controller.Controller;
import org.example.mvc.controller.HandlerKey; import org.example.mvc.controller.HandlerKey;
import org.example.mvc.controller.RequestMethod; import org.example.mvc.controller.RequestMethod;
import org.example.mvc.view.JspViewResolver; import org.example.mvc.view.JspViewResolver;
@@ -10,7 +9,6 @@ import org.example.mvc.view.ViewResolver;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
@@ -18,7 +16,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
@WebServlet("/") @WebServlet("/")
@@ -26,16 +23,27 @@ public class DispatcherServlet extends HttpServlet {
private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class); private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class);
private RequestMappingHandlerMapping requestMappingHandlerMapping; private List<HandlerMapping> handlerMappings;
private List<ViewResolver> viewResolvers; private List<ViewResolver> viewResolvers;
private List<HandlerAdapter> handlerAdapters; private List<HandlerAdapter> handlerAdapters;
@Override @Override
public void init() throws ServletException { public void init() throws ServletException {
requestMappingHandlerMapping = new RequestMappingHandlerMapping(); RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();
requestMappingHandlerMapping.init(); requestMappingHandlerMapping.init();
handlerAdapters = List.of(new SimpleControllerHandlerAdaptor()); AnnotationHandlerMapping annotationHandlerMapping = new AnnotationHandlerMapping();
annotationHandlerMapping.init();
handlerMappings = List.of(
requestMappingHandlerMapping,
annotationHandlerMapping
);
handlerAdapters = List.of(
new SimpleControllerHandlerAdapter(),
new AnnotationHandlerAdapter()
);
viewResolvers = Collections.singletonList(new JspViewResolver()); viewResolvers = Collections.singletonList(new JspViewResolver());
} }
@@ -43,9 +51,15 @@ public class DispatcherServlet extends HttpServlet {
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
log.info("[DispatcherServlet] service started."); log.info("[DispatcherServlet] service started.");
String requestURI = req.getRequestURI();
RequestMethod requestMethod = RequestMethod.valueOf(req.getMethod());
try { try {
Controller handler = Object handler = handlerMappings.stream()
requestMappingHandlerMapping.findHandler(new HandlerKey(RequestMethod.valueOf(req.getMethod()), req.getRequestURI())); .filter(hm -> hm.findHandler(new HandlerKey(requestMethod, requestURI)) != null)
.map(hm -> hm.findHandler(new HandlerKey(requestMethod, requestURI)))
.findFirst()
.orElseThrow(() -> new ServletException("No handler for [" + requestMethod + ", " + requestURI + "]"));
if (handler == null) { if (handler == null) {
resp.sendError(404); resp.sendError(404);

View File

@@ -0,0 +1,7 @@
package org.example.mvc;
import org.example.mvc.controller.HandlerKey;
public interface HandlerMapping {
Object findHandler(HandlerKey handlerKey);
}

View File

@@ -5,12 +5,12 @@ import org.example.mvc.controller.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class RequestMappingHandlerMapping { public class RequestMappingHandlerMapping implements HandlerMapping {
private Map<HandlerKey, Controller> mappings = new HashMap<>(); private Map<HandlerKey, Controller> mappings = new HashMap<>();
void init() { void init() {
mappings.put(new HandlerKey(RequestMethod.GET, "/"), new HomeController()); // mappings.put(new HandlerKey(RequestMethod.GET, "/"), new HomeController());
mappings.put(new HandlerKey(RequestMethod.GET, "/users"), new UserListController()); mappings.put(new HandlerKey(RequestMethod.GET, "/users"), new UserListController());
mappings.put(new HandlerKey(RequestMethod.POST, "/users"), new UserCreateController()); mappings.put(new HandlerKey(RequestMethod.POST, "/users"), new UserCreateController());
mappings.put(new HandlerKey(RequestMethod.GET, "/user/form"), new ForwardController("/user/form")); mappings.put(new HandlerKey(RequestMethod.GET, "/user/form"), new ForwardController("/user/form"));

View File

@@ -6,7 +6,7 @@ import org.example.mvc.view.ModelAndView;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
public class SimpleControllerHandlerAdaptor implements HandlerAdapter { public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override @Override
public boolean supports(Object handler) { public boolean supports(Object handler) {
return (handler instanceof Controller); return (handler instanceof Controller);

View File

@@ -0,0 +1,11 @@
package org.example.mvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}

View File

@@ -0,0 +1,17 @@
package org.example.mvc.annotation;
import org.example.mvc.controller.RequestMethod;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value() default "";
RequestMethod[] method() default {};
}

View File

@@ -1,11 +1,16 @@
package org.example.mvc.controller; package org.example.mvc.controller;
import org.example.mvc.annotation.Controller;
import org.example.mvc.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
public class HomeController implements Controller{ @Controller
@Override public class HomeController {
@RequestMapping(value = "/",method = RequestMethod.GET)
public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return "home.jsp"; return "home";
} }
} }