diff --git a/src/main/java/com/diy/app/LectureConfig.java b/src/main/java/com/diy/app/LectureConfig.java index ab4fbbc3..54ddd24a 100644 --- a/src/main/java/com/diy/app/LectureConfig.java +++ b/src/main/java/com/diy/app/LectureConfig.java @@ -1,7 +1,14 @@ package com.diy.app; +import com.diy.framework.web.context.annotation.Bean; import com.diy.framework.web.context.annotation.Component; +import com.diy.framework.web.mvc.ModelAndView; +import com.diy.framework.web.mvc.controller.Controller; @Component public class LectureConfig { + @Bean(name = "/lectures/new") + public Controller lectureFormController() { + return params -> new ModelAndView("lecture-registration"); + } } diff --git a/src/main/java/com/diy/framework/web/mvc/DispatcherServlet.java b/src/main/java/com/diy/framework/web/mvc/DispatcherServlet.java index 774825cc..76980bb1 100644 --- a/src/main/java/com/diy/framework/web/mvc/DispatcherServlet.java +++ b/src/main/java/com/diy/framework/web/mvc/DispatcherServlet.java @@ -38,11 +38,14 @@ public void init(final ServletConfig config) throws ServletException { ApplicationContext applicationContext = new ApplicationContext("com.diy"); + // 1) 애너테이션 매핑(METHOD + URL) AnnotationHandlerMapping annotationHandlerMapping = new AnnotationHandlerMapping(applicationContext); annotationHandlerMapping.initialize(); handlerMappings.add(annotationHandlerMapping); - SimpleControllerHandlerMapping simpleHandlerMapping = new SimpleControllerHandlerMapping(); + // 2) 인터페이스 매핑(URL) + SimpleControllerHandlerMapping simpleHandlerMapping = new SimpleControllerHandlerMapping(applicationContext); + simpleHandlerMapping.initialize(); handlerMappings.add(simpleHandlerMapping); handlerAdapters.add(new AnnotationHandlerAdapter()); diff --git a/src/main/java/com/diy/framework/web/mvc/handler/SimpleControllerHandlerMapping.java b/src/main/java/com/diy/framework/web/mvc/handler/SimpleControllerHandlerMapping.java index 7b4bd064..7e794be2 100644 --- a/src/main/java/com/diy/framework/web/mvc/handler/SimpleControllerHandlerMapping.java +++ b/src/main/java/com/diy/framework/web/mvc/handler/SimpleControllerHandlerMapping.java @@ -1,5 +1,6 @@ package com.diy.framework.web.mvc.handler; +import com.diy.framework.web.context.ApplicationContext; import com.diy.framework.web.mvc.controller.Controller; import java.util.HashMap; @@ -7,6 +8,21 @@ public class SimpleControllerHandlerMapping implements HandlerMapping { private final Map controllers = new HashMap<>(); + private final ApplicationContext applicationContext; + + public SimpleControllerHandlerMapping(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + public void initialize() { + for (Map.Entry entry : applicationContext.getAllBeans().entrySet()) { + Object bean = entry.getValue(); + if (bean instanceof Controller) { + // 빈 이름을 그대로 매핑 키로 사용 + controllers.put(entry.getKey(), (Controller) bean); + } + } + } public void put(String key, Controller controller) { controllers.put(key, controller); @@ -14,6 +30,9 @@ public void put(String key, Controller controller) { @Override public Object getHandler(String key) { - return controllers.get(key); + // DispatcherServlet 은 "GET /lectures" 처럼 "METHOD path" 로 조회하지만, + // 인터페이스 매핑은 path(URL)만 키로 가진다. HTTP Method 를 떼고 path 로만 조회한다. + String path = key.contains(" ") ? key.split(" ", 2)[1] : key; + return controllers.get(path); } } diff --git a/src/test/java/com/diy/framework/web/beans/factory/ApplicationContextTest.java b/src/test/java/com/diy/framework/web/beans/factory/ApplicationContextTest.java index 9dcc9419..f2f06329 100644 --- a/src/test/java/com/diy/framework/web/beans/factory/ApplicationContextTest.java +++ b/src/test/java/com/diy/framework/web/beans/factory/ApplicationContextTest.java @@ -3,6 +3,10 @@ import com.diy.app.LectureController; import com.diy.app.LectureRepository; import com.diy.framework.web.context.ApplicationContext; +import com.diy.framework.web.mvc.controller.Controller; +import com.diy.framework.web.mvc.handler.AnnotationHandlerMapping; +import com.diy.framework.web.mvc.handler.HandlerMethod; +import com.diy.framework.web.mvc.handler.SimpleControllerHandlerMapping; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -37,4 +41,37 @@ void controllerAnnotationRegistration() { assertThat(controller).isInstanceOf(LectureController.class); } + + @Test + @DisplayName("인터페이스 기반 컨트롤러는 빈 이름(URL)으로 등록되고 HTTP Method 와 무관하게 매핑된다") + void interfaceControllerMapping() { + ApplicationContext context = new ApplicationContext("com.diy"); + + Object controller = context.getBean("/lectures/new"); + assertThat(controller).isInstanceOf(Controller.class); + + SimpleControllerHandlerMapping mapping = new SimpleControllerHandlerMapping(context); + mapping.initialize(); + + assertThat(mapping.getHandler("GET /lectures/new")).isSameAs(controller); + assertThat(mapping.getHandler("POST /lectures/new")).isSameAs(controller); + } + + @Test + @DisplayName("애너테이션 기반 컨트롤러는 URL과 HTTP Method 조합으로 매핑된다") + void annotationControllerMapping() { + ApplicationContext context = new ApplicationContext("com.diy"); + + AnnotationHandlerMapping mapping = new AnnotationHandlerMapping(context); + mapping.initialize(); + + Object getHandler = mapping.getHandler("GET /lectures"); + Object postHandler = mapping.getHandler("POST /lectures"); + + assertThat(getHandler).isInstanceOf(HandlerMethod.class); + assertThat(postHandler).isInstanceOf(HandlerMethod.class); + + assertThat(((HandlerMethod) getHandler).getMethod().getName()).isEqualTo("list"); + assertThat(((HandlerMethod) postHandler).getMethod().getName()).isEqualTo("create"); + } }