티스토리 뷰
http 서버 구현하기 미션을 하고 있다. 진행하면서 @GetMapping, @PostMapping 등으로 메소드 실행 분기처리를 하고 싶어졌다. 그래서 작성하는 Method 단위의 커스텀 어노테이션 만들기
1. 어노테이션 정의
- @interface로 어노테이션을 정의한다.
- 메타 어노테이션을 정의한다.
- @Target: ElementType.METHOD, ElementType.FIELD 등으로 다양하게 어디에 적용할 어노테이션인지 정의할 수 있다.
- @Retention: 런타임에도 참조할 수 있게 RetentionPolicy.RUNTIME 으로 해준다. 이것 역시 컴파일을 기준으로 언제 참조 가능한지 설정해 줄 수 있다.
- CustomAnnotation 참고 블로그
- 이번 경우에서는 path라는 속성으로 uri을 정의해 줄 것이므로 해당 내용을 넣어준다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface GetMapping {
String path() default "";
}
2. 어노테이션 사용할 곳에 붙이기
- 메소드를 설정한 뒤, 해당 어노테이션을 붙이고 path에 지정할 uri 를 설정해 주었다.
public class Controller {
private final HttpService service;
public Controller() {
this.service = new HttpService();
}
@GetMapping(path = "/")
public String basic(String uri) {
return ResponseEntity
.responseBody("Hello world!")
.build();
}
@GetMapping(path = "/login")
public String login(String uri) throws IOException {
return ResponseEntity
.responseResource(uri)
.build();
}
}
3. 어노테이션이 있는 메소드 실행하기
- 메소드를 실행히길 설정을 해준다.
- Controller.class.getDeclaredMethods() 로 Controller 클래스에 선언된 메소드들을 불러올 수 있다.
- 해당 method 들을 돌면서 어노테이션이 존재하면 해당 path 와 일치하는지 여부를 확인한다.
- method.getAnnotation(PostMapping.class).path() : 어노테이션에 path 로 설정했으므로 .path()로 해당 요소를 불러올 수 있다.
- 메소드가 private 이라면 method.setAccessible(true); 를 해주어야 하지만 public 이므로 생략한다.
- method.invoke(obj, ...args) 로 해당 메소드를 실행하고 반환값을 반환한다.
- 매핑된 Controller가 없다면, 그냥 해당 소스를 찾아 리턴해주게 한다.
class FrontController{
// ...
public String response() throws Exception {
final String httpMethod = requestLine.getHttpMethod();
final String uri = requestLine.getUri();
Controller controller = new Controller();
if (HttpMethod.GET.equals(httpMethod)) {
return getMapping(uri, controller);
}
if (HttpMethod.POST.equals(httpMethod)) {
return postMapping(uri, controller);
}
throw new HttpException("설정되어 있지 않은 http 메소드입니다.");
}
private String getMapping(String uri, Controller controller) throws Exception {
for (Method method : Controller.class.getDeclaredMethods()) {
if (matchGetMapping(method, uri)) {
return (String) method.invoke(controller, uri);
}
}
Set<String> declaredGetMappings = collectDeclaredGetMappings();
if (!declaredGetMappings.contains(uri)) {
return ResponseEntity
.responseResource(uri)
.build();
}
throw new HttpException("잘못된 http get 요청입니다.");
}
private boolean matchGetMapping(Method method, String uri) {
if (method.isAnnotationPresent(GetMapping.class)) {
String path = method.getAnnotation(GetMapping.class).path();
return path.equals(uri);
}
return false;
}
// ...
}
참고
'우아한테크코스 > 레벨4, 레벨5' 카테고리의 다른 글
[팀 프로젝트] private configuration 설정파일 정보 문서화 (0) | 2021.09.27 |
---|---|
[팀 프로젝트] GM 로그 관리를 위한 ELK Stack 설정 방법 문서화 (0) | 2021.09.27 |
[팀 프로젝트] gpu-is-mine 적용된 로깅 정책 파악하기 (0) | 2021.09.25 |
[http 서버 구현미션] HTTP/1.1 프로토콜 (0) | 2021.09.24 |
[http 서버 구현미션] File, inputStream, outputStream (0) | 2021.09.21 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 인증
- 모의면접준비
- python
- 네트워크
- DB
- java
- 카카오
- OS
- React
- 코드스쿼드
- 회고
- Spring
- 우아한테크코스
- TIL
- JPA
- 우테코수업
- JS
- 내부코드
- CS
- TCP/IP
- 알고리즘
- 마스터즈코스
- 개발공부일지
- 운영체제
- 객체지향
- 글쓰기미션
- Transaction
- 월간회고
- 학습로그
- javascript
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함