컨트롤러의 메소드 찾기 → Argument Resolver 처리 → 컨트롤러 메소드 실행
@Inherited
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface AccessRole {
// 사용 시 @AccessRole(firValue = "", secValue = "")
String firValue();
String secValue();
}
이름 | 설명 |
---|---|
RUNTIME | 컴파일 이후에도 참조 가능 |
CLASS | 클래스를 참조할 때까지 유효 |
SOURCE | 컴파일 이후 어노테이션 정보 소멸 (컴파일러에 의해 폐기) |
이름 | 설명 |
---|---|
PACKAGE | 패키지 선언 시 |
TYPE | 타입(클래스, 인터페이스, enum) 선언 시 |
CONSTUCTOR | 생성자 선언 시 |
FIELD | enum 상수를 포함한 멤버변수 선언 시 |
METHOD | 메소드 선언시 |
ANNOTATION_TYPE | 어노테이션 타입 선언 시 |
LOCAL_VARIABLE | 지역변수 선언 시 |
PARAMETER | 파라미터 선언 시 |
TYPE_PARAMETER | 파라미터 타입 선언 시 |
@Component
@RequiredArgsConstructor
public class AccessResolver implements HandlerMethodArgumentResolver {
private final ApplicationSetting setting;
private String key;
@PostConstruct
protected void init() {
key = setting.getJwt_key();
}
// 컨트롤러의 메서드에 존재하는 파라미터들에 대해서 검사하여, 적용 여부를 판단
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 파라미터 타입이 String 인지 확인
return parameter.getParameterType().equals(HashMap.class);
}
// supportsParameter() 가 true값을 return하면 실행되는 메소드
@Override
public HashMap<String, String> resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) webRequest.getNativeRequest();
String token =
httpServletRequest.getHeader("Authorization")
.split("Bearer ")[1];
String role = Jwts.parser()
.setSigningKey(key.getBytes("UTF-8")) // Set Key
.parseClaimsJws(token).getBody().getSubject();
return new HashMap<String, String>(){{
put("role", role);
put("token", token);
}};
}
}
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final AccessResolver accessResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(accessResolver);
}
}
@PostMapping("/read")
@ResponseBody
public ApiDTO read(
@AccessRole HashMap<String, String> jwt,
@RequestBody ReadRequest request
){
...
나의 경우 컨트롤러에서 모든 Exception을 처리하게 되어있는데,
Resolver에서 발생한 Exception을 Response 데이터로 활용하기 위해선
컨트롤러로 Exception을 넘겨주어야 했다.
그냥 throw new exception종류(); 또는 catch 문에 throw e; 를 해도
컨트롤러에는 넘어가지 않고 Resolver에서 Exception 처리가 완료되었다.
여러 방법을 시도 해보다가 Exception 값을 return으로 넘겨주는 것으로 성공했다!
@Override
public HashMap<String, Object> resolveArgument(
...
} catch (MalformedJwtException e){
// 토큰을 확인할 수 없을 때
return new HashMap<String, Object>() {{
put("exception", e);
}};
} catch (ExpiredJwtException e) { // 토큰이 만료되었을 경우
return new HashMap<String, Object>() {{
put("exception", e);
}};
}
}
@PostMapping("/read")
@ResponseBody
public ApiDTO read(
@AccessRole HashMap<String, Object> jwt,
@RequestBody ReadRequest request
) throws Throwable {
try{
if(jwt.get("exception") != null)
throw (Throwable) jwt.get("exception");
...
// 캐치문 처리
[JWT] 세션 의존성 제거하기 - 커스텀 어노테이션 활용 - LJH
스프링에서 Argument Resolver 사용하기 - hudi.blog