Nuwa Project - Custom Annotation
작업을 진행을 하던 도중 갑작스럽게 매번 쓰던 토큰 값을 가져오는 로직 간단하게 할 수 없을까 생각을 했습니다.
@RequestHeader("Authorization") String accessToken
@RequestHeader처럼 어노테이션으로 만들어서 쓰자란 생각이 들었습니다.
토큰 값을 가져와서 이메일을 꺼내 쓰는 일이 자주 있었습니다. 아니면 id값이라던지 등등
이 때 매번 헤더에서 토큰 값 가져와 -> 서비스로 넘겨서 email 추출 -> email 사용
이렇게 되었는데 전역적으로 설정하고 어노테이션으로 이메일만 바로 가져오면 훨씬 코드가 보기 좋을 것 같다고 생각했습니다.
이제 어노테이션으로 만들어보겠습니다.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface MemberEmail {
}
다음과 같이 어노테이션 인터페이스를 만들었습니다.
인터페이스를 이용할 argumentresolver를 생성을 해줘야 합니다.
@RequiredArgsConstructor
public class MemberEmailHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
private final JwtUtil jwtUtil;
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameter().getAnnotation(MemberEmail.class) != null
&& parameter.getParameterType().equals(String.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String accessToken = webRequest.getHeader("Authorization");
if (!jwtUtil.verifyToken(accessToken)) {
throw new JwtException(JWT_EXPIRED);
}
return jwtUtil.getEmail(accessToken);
}
}
HandleMethodArgumentResolver를 상속 받은 후에 필수 구현 메소드를 오버라이드 해줍니다.
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final JwtUtil jwtUtil;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new MemberEmailHandlerMethodArgumentResolver(jwtUtil));
}
}
그 후에 config 설정까지 해주시면 어노테이션을 사용할 수 있습니다!
해당 어노테이션 구현 중 Spring Data를 사용할 때 Paging을 할 때
PageRequest.of() 를 사용해서 page, size, sort 값을 넣어주곤 했습니다.
페이징을 하는 조회 코드는 엄청 많기 때문에 이러한 값을 넣어주는 코드를 매번 파라미터로 받는 것은
너무 고통이라고 생각했습니다.
저는 이미 토큰 값에서 이메일을 가져오는 어노테이션을 만들었고 페이징에 대한 어노테이션도 가능하다고 생각했습니다.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomPageable {
int page() default 1;
int size() default 20;
String sortBy() default "createdAt";
}
RequestParam으로 받던 정보를 입력합니다.
default는 사용하시는 기준에 맞춰서 쓰시면 됩니다.
public class CustomPageableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(CustomPageable.class) != null;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
CustomPageable customPageable = parameter.getParameterAnnotation(CustomPageable.class);
assert customPageable != null;
int page = customPageable.page() - 1;
int size = customPageable.size();
String sortBy = customPageable.sortBy();
return PageRequest.of(page, size, Sort.by(sortBy));
}
}
2024.2.15
parameter.getMethodAnnotation을 사용하고 있어서 해당 페이징에 제대로 나가고 있지 않았습니다.
현재와 같이 getParameterAnnotation으로 사용하시면 정상적으로 페이징이 동작합니다.
다음은 동일하게 argumentResolver를 생성을 해줍니다.
여기서 page에서 왜 -1을 했냐면 Spring data의 page는 0부터 시작입니다.
어노테이션에저 저희는 default 값을 1로 설정을 했기에 0으로 넣어주기 위해서 -1을 진행합니다.
이렇게 하고 PageRequest.of()로 값을 넘깁니다.
resolvers.add(new CustomPageableHandlerMethodArgumentResolver());
config파일에도 꼭 추가를 해주셔야 합니다.
그럼 이제 사용을 하실 때 @CustomPageable로 사용하시면 됩니다.