Argument Resolver

이영규·2023년 7월 2일
0

ArgumentResolver 의 목적, 사용 방법을 간단히 정리한다.

목적

HttpRequest 요청에서 필요한 값을 꺼내고, 변환해서 사용해야 하는 경우가 있다.
이런 작업이 반복적으로 필요한 경우 ArgumentResolver 를 선언해 두면 이런 작업을 공통으로 적용할 수 있다.

우리가 Spring MVC 에서 흔히 사용하는 @RequestParam 같은 것들도 하나의 예시이다.
사실은 HttpServletRequest 에 담겨있는 parameter 정보를 읽어와야 하는데, 이를 Spring 의 ArgumentResolver 를 통해 편리하게 읽어오는 것이다.

구현

HandlerMethodArgumentResolver 를 구현한 뒤, WebMvcConfigurer 를 통해 등록하면 된다.

HandlerMethodArgumentResolver 구현

public class SampleArgumentResolver implements HandlerMethodArgumentResolver {

구현할 때는 2가지 메서드를 오버라이드 해야 하는데,

supportParameter

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

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 를 통해 등록

인터셉터를 등록할 때와 동일하게 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 에게 뿌려준다.

  • Mapping 되는 Handler 를 찾은 후
  • 해당 Handler 의 Intercepter 를 실행
  • Argument Resolver 처리
  • Message Converter 처리
  • Controller Method invoke(실행)

의 순서로 진행되며,
간단하게 ArgumentResolver 는 인터셉터 이후, 컨트롤러 메서드 invoke 이전에 호출된다고 생각하면 된다.

profile
더 빠르게 더 많이 성장하고 싶은 개발자입니다

0개의 댓글