ArgumentResolver 의 목적, 사용 방법을 간단히 정리한다.
HttpRequest 요청에서 필요한 값을 꺼내고, 변환해서 사용해야 하는 경우가 있다.
이런 작업이 반복적으로 필요한 경우 ArgumentResolver
를 선언해 두면 이런 작업을 공통으로 적용할 수 있다.
우리가 Spring MVC 에서 흔히 사용하는 @RequestParam
같은 것들도 하나의 예시이다.
사실은 HttpServletRequest
에 담겨있는 parameter 정보를 읽어와야 하는데, 이를 Spring 의 ArgumentResolver
를 통해 편리하게 읽어오는 것이다.
HandlerMethodArgumentResolver
를 구현한 뒤, WebMvcConfigurer
를 통해 등록하면 된다.
public class SampleArgumentResolver implements HandlerMethodArgumentResolver {
구현할 때는 2가지 메서드를 오버라이드 해야 하는데,
supportParameter
는 resolver 를 적용할 대상을 판별한다.
@Override
public boolean supportsParameter(MethodParameter parameter) {
// (1) 이름
String parameterName = parameter.getParameterName();
boolean nameValid = parameterName.equals("something");
// (2) 타입
Class<?> parameterType = parameter.getParameterType();
boolean typeValid = parameterType.equals(SomeType.class);
// (3) 어노테이션
boolean annotationValid = parameter.hasParameterAnnotation(RequestParam.class);
return nameValid && typeValid && annotationValid;
}
일반적으로 파라미터의 이름이나 타입, 어노테이션의 존재 여부 등을 통해 판단한다.
resolveArgument
는 실제 resolve 하는 내용을 구현한다.
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// (1) token
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
Token token = TokenUtil.extract(servletRequest);
String userName = token.getUserName();
// (2) decrypt something
String header = webRequest.getHeader("header");
String decryptedHeader = DecryptUtil.decrypt(header);
return "resolvedResult";
}
반복적으로 일어날만한 resolve 작업을 구현하면 된다.
토큰을 추출해 그 정보를 가져오거나, 암/복호화를 처리하거나, SecurityContext
에서 현재 사용자의 정보를 가져오는 등 필요에 따라 다양하게 활용할 수 있다.
인터셉터를 등록할 때와 동일하게 WebMvcConfigurer
를 구현하고, 리졸버를 추가해주면 된다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new SampleArgumentResolver());
}
}
@RestController
@RequestMapping("/api/v1/sample")
public class SampleApi {
@GetMapping("/resolver-test")
public void resolverTest(String resolvedParameter){
System.out.println("use resolvedParameter by ArgumentResolver!");
System.out.println("resolvedParameter = " + resolvedParameter);
}
}
resolve 된 값을 별다른 작업 없이 바로 사용할 수 있다.
Spring MVC 의 요청은 우선 DispatcherServlet 으로 들어가고,
DispatcherServlet 이 요청을 적절한 Handler 에게 뿌려준다.
의 순서로 진행되며,
간단하게 ArgumentResolver 는 인터셉터 이후, 컨트롤러 메서드 invoke 이전에 호출된다고 생각하면 된다.