-
Notifications
You must be signed in to change notification settings - Fork 302
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 구현하기 - 1단계] 에단(김석호) 미션 제출합니다. #426
Changes from 12 commits
52ee778
e7c21ab
30ab29a
8a4416d
daa434e
aba8abf
f93ddc3
34fd98b
20523ea
db76110
fb2e96b
a9bad5c
ea04873
b15d0c7
ce3c569
7df0ffb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,11 @@ | ||
# @MVC 구현하기 | ||
|
||
## 학습테스트 | ||
- [x] ReflectionTest | ||
- [x] ServletTest | ||
- [x] FilterTest | ||
|
||
## 요구 사항 | ||
- [x] AnnotationHandlerMappingTest 성공 테스트로 변경 | ||
- [x] get() 성공 테스트로 변경 | ||
- [x] post() 성공 테스트로 변경 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,14 @@ | ||
package web.org.springframework.web.bind.annotation; | ||
|
||
import java.util.Arrays; | ||
|
||
public enum RequestMethod { | ||
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE | ||
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE; | ||
|
||
public static RequestMethod from(final String method) { | ||
return Arrays.stream(values()) | ||
.filter(value -> value.name().equalsIgnoreCase(method)) | ||
.findAny() | ||
.orElseThrow(() -> new IllegalArgumentException("지원하지 않는 RequestMethod 입니다.")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,9 +3,11 @@ | |
import jakarta.servlet.http.HttpServletRequest; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import web.org.springframework.web.bind.annotation.RequestMethod; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
public class AnnotationHandlerMapping { | ||
|
||
|
@@ -21,9 +23,19 @@ public AnnotationHandlerMapping(final Object... basePackage) { | |
|
||
public void initialize() { | ||
log.info("Initialized AnnotationHandlerMapping!"); | ||
final Map<HandlerKey, HandlerExecution> handlerExecutions = Objects.requireNonNull(HandlerExecutionFactory.create(basePackage)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 생성 책임을 분리하셨군요 👍 |
||
this.handlerExecutions.putAll(handlerExecutions); | ||
} | ||
|
||
public Object getHandler(final HttpServletRequest request) { | ||
return null; | ||
final String requestURI = request.getRequestURI(); | ||
final String method = request.getMethod(); | ||
final HandlerKey targetKey = new HandlerKey(requestURI, RequestMethod.from(method)); | ||
|
||
if (handlerExecutions.containsKey(targetKey)) { | ||
return handlerExecutions.get(targetKey); | ||
} | ||
|
||
return new IllegalArgumentException("처리 할 수 없는 요청 입니다."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HandlerExecutions에서 해당 메서드와 uri가 없으면 예외를 반환하네요?? 와우.. Optional, Null을 사용하지 않고 해당 방식으로 구현하신 이유가 무엇일까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 처리할 수 없는 메서드면 예외를 반환하는게 좋다고 생각해서 이렇게 구현했습니다. |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,9 +4,22 @@ | |
import jakarta.servlet.http.HttpServletResponse; | ||
import webmvc.org.springframework.web.servlet.ModelAndView; | ||
|
||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Method; | ||
|
||
public class HandlerExecution { | ||
|
||
private final Class<?> controller; | ||
private final Method method; | ||
|
||
public HandlerExecution(final Class<?> controller, final Method method) { | ||
this.controller = controller; | ||
this.method = method; | ||
} | ||
|
||
public ModelAndView handle(final HttpServletRequest request, final HttpServletResponse response) throws Exception { | ||
return null; | ||
final Constructor<?> constructor = controller.getDeclaredConstructor(); | ||
final Object instance = constructor.newInstance(); | ||
return (ModelAndView) method.invoke(instance, request, response); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 매번 같은 인스턴스인데 요청이 들어올 때마다 새로운 인스턴스를 생성하면 객체 생성 비용에서 단점이 있다고 생각합니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 크게 고민하지 못했던것 같아요. 수정해서 반영하겠습니다 |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package webmvc.org.springframework.web.servlet.mvc.tobe; | ||
|
||
import context.org.springframework.stereotype.Controller; | ||
import org.reflections.Reflections; | ||
import web.org.springframework.web.bind.annotation.RequestMapping; | ||
import web.org.springframework.web.bind.annotation.RequestMethod; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
public class HandlerExecutionFactory { | ||
|
||
public static Map<HandlerKey, HandlerExecution> create(final Object... basePackage) { | ||
final Map<HandlerKey, HandlerExecution> handlerExecutions = new HashMap<>(); | ||
|
||
final Reflections reflections = new Reflections(basePackage); | ||
|
||
final Set<Class<?>> controllers = reflections.getTypesAnnotatedWith(Controller.class); | ||
for (final Class<?> controller : controllers) { | ||
|
||
for (final Method method : controller.getDeclaredMethods()) { | ||
if (method.isAnnotationPresent(RequestMapping.class)) { | ||
|
||
final RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); | ||
final String requestUrl = requestMapping.value(); | ||
final RequestMethod[] requestMethods = requestMapping.method(); | ||
|
||
for (final RequestMethod requestMethod : requestMethods) { | ||
final HandlerKey handlerKey = new HandlerKey(requestUrl, requestMethod); | ||
final HandlerExecution handlerExecution = new HandlerExecution(controller, method); | ||
handlerExecutions.put(handlerKey, handlerExecution); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return handlerExecutions; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package web.org.springframework.web.bind.annotation; | ||
|
||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.ValueSource; | ||
|
||
import static org.assertj.core.api.Assertions.assertThatCode; | ||
|
||
class RequestMethodTest { | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = {"GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE"}) | ||
void String을_알맞는_RequestMethod로_변환_할_수_있다(final String method) { | ||
// when, then | ||
assertThatCode(() -> RequestMethod.from(method)) | ||
.doesNotThrowAnyException(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오호 valueOf 안쓰시고 정팩메를 정의하셨네요 ! 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
예외 메세지를 custom 하려고 이렇게 했습니다. 다만 모디 글을 보니 switch 문도 나쁘지 않을 것 같아서 다음단계에서 바꿔보려고 합니다!