[Spring] Resolver 란? Resolver 구현하기(HandlerMethodArgumentResolver)
🙆♂️ import 🙇♂️
Custom HandlerMethodArgumentResolver 만들어보기[Advenoh - FRANK OH]
Spring Argument Resovler[jaehun2841.github.io]
HandlerMethodArgumentResolver
HandlerMethodArgumentResolver는 Interface로써,
Controller의 Argument(Parameter)에 지정된 변수들을,
Annotation이나 객체의 Type에 따라서 Resolver를 먼저 거쳐,
실제 Data를 Controller에 넘겨주는 역할을 수행한다.
Controller에 들어오는 Argument(Parameter)를 가공(암호화 > 복호화) 하거나, 
Argument(Parameter)를 추가하거나 수정해야 하는 경우에 사용한다.
실제 해당 Interface의 형태는 아래와 같다.
/**
 * Strategy interface for resolving method parameters into argument values in
 * the context of a given request.
 *
 * @author Arjen Poutsma
 * @since 3.1
 * @see HandlerMethodReturnValueHandler
 */
public interface HandlerMethodArgumentResolver {
	/**
	 * Whether the given {@linkplain MethodParameter method parameter} is
	 * supported by this resolver.
	 * @param parameter the method parameter to check
	 * @return {@code true} if this resolver supports the supplied parameter;
	 * {@code false} otherwise
	 */
	boolean supportsParameter(MethodParameter parameter);
	/**
	 * Resolves a method parameter into an argument value from a given request.
	 * A {@link ModelAndViewContainer} provides access to the model for the
	 * request. A {@link WebDataBinderFactory} provides a way to create
	 * a {@link WebDataBinder} instance when needed for data binding and
	 * type conversion purposes.
	 * @param parameter the method parameter to resolve. This parameter must
	 * have previously been passed to {@link #supportsParameter} which must
	 * have returned {@code true}.
	 * @param mavContainer the ModelAndViewContainer for the current request
	 * @param webRequest the current request
	 * @param binderFactory a factory for creating {@link WebDataBinder} instances
	 * @return the resolved argument value, or {@code null}
	 * @throws Exception in case of errors with the preparation of argument values
	 */
	Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
HandlerMethodArgumentResolver 사용 이유
HandlerMethodArgumentResolver를 사용하는 이유는,
매개변수로 사용되는 인자에 대해 공통적으로 처리해야할 로직 등이 있을 경우,
중복 코드를 줄이고 공통 기능으로 추출하여 사용할 수 있다.
동작 방식
Spring에서 Resolver의 동작은 아래와 같은 과정으로 이루어진다.

- 
Client Request요청 - 
Dispatcher Servlet에서 해당 요청 처리 - 
Client Request에 대한Handler Mapping
3.1RequestMapping에 대한 매칭 (RequestMappingHandlerAdapter가 수행)
3.2Interceptor처리
3.3Argument Resolver처리 <--Argument Resolver실행 지점
3.4Message Converter처리 - 
Controller Method invoke
 
정리하자면 특정 Request가 Handler로 Mapping되는 과정에서 invoke 되기 전,
Interceptor > Resolver > MessageConverter 순으로 처리된 후,
Controller의 Method가 invoke 된다.
Resolver 구현
먼저 HandlerMethodArgumentResolver를 implemnets하는 Class를 생성한다.
이때 구현해야 하는 method는 supportsParameter, resolveArgument 두 가지이다.
public boolean supportsParameter(MethodParameter parameter)
Parameter가 해당 Resolver에 의해 수행 되는 Type인지 체크하여 boolean을 return한다.
true로 return될 경우 resolveArgument method를 실행한다.
이때 Type 체크를 위해 Class를 .isAssignableFrom()을 이용해 비교 할 수도,
Annotation을 새로 생성하여 체크할 수도 있다.
.isAssignalbeFrom() 이용 Prameter 객체 Class 타입 체크
아래와 같이 Parameter에서 Binding 되길 원하는 객체의 Class Type을 .isAssignableFrom()을 이용해 구현하면,
isAssignableFrom이 궁금하다면 클릭
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return ResultJwt.class.isAssignableFrom(parameter.getParameterType());
	}
아래에서 처럼 Handler에서 해당 Parameter 객체 Class 타입을 사용하는 Parameter가 Handelr의 처리 지점이 된다.
	@GetMapping("")
	public ResponseEntity<Contents<Board>> getNotices(ResultJwt resultJwt,
			@RequestParam(required = false) String category, CommonParameter<NoticeType> parameter) {
		String platformId = (String) resultJwt.getClaims().get(JwtClaims.PLATFORMID.getClaim());
Annotation 생성
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ResultJWT {
}
사용된 Annotation들의 속성은 아래와 같다.
- @interface : 해당 파일을 
AnnotationClass로 지정,@ResultJWT라는Annotation이 생성됨 
- 
@Target(ElementType.PARAMETER) : 해당
Annotation이 생성될 위치 지정,
PARAMETER로 지정 시 Method의 Parameter에서만 사용 가능 - 
@Retention(RetentionPolicy.RUNTIME) :
Annotation유지 정책을 설정,
RUNTIME은 Byte Code File까지Annotation정보를 유지,
reflection을 이용 Runtime시에 해당Annotation정보를 획득.
reflection : 구체적인 Class Type을 알지 못해도, 그 Class의 method, type, field들에 접근할 수 있도록 해주는 Java API 
	@GetMapping("")
	public ResponseEntity<Contents<Board>> getNotices(@ResultJWT ResultJwt resultJwt,
			@RequestParam(required = false) String category, CommonParameter<NoticeType> parameter) {
		String platformId = (String) resultJwt.getClaims().get(JwtClaims.PLATFORMID.getClaim());
위와 같이 @ResultJWT Annotation 적용 후  supportsParameter()를 아래와 같이 구현 시,
해당 Parameter가 Resolver의 처리 지점이 된다.
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        boolean isResultJwtAnnotation =  parameter.getParameterAnnotation(ResultJWT.class) != null;
        boolean isResultJwtClass = ResultJwt.class.equals(parameter.getParameterType());
        return isResultJwtAnnotation && isResultJwtClass;
    }
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception
실제 Parameter와 Binding하여 return할 Object를 생성하는 method이다.
NativeWebRequest Object에 접근하여 Client Request의 Parameter를 Controller 보다 우선적으로 받아 작업할 수 있다.
해당 Handler method안 Parameter에서 Binding을 원하는 객체 Type에 맞게 return해주면 된다.
public class ResultJwtArgumentResolver implements HandlerMethodArgumentResolver {
	@Autowired
	private AuthService authService;
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return ResultJwt.class.isAssignableFrom(parameter.getParameterType());
	}
	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
			WebDataBinderFactory binderFactory) throws Exception {
                // return type은 본인이 Binding을 원하는 객체 Class
                // supportsParameter에서 검증한 ResultJwt.class
		return authService.getResultJwt(webRequest.getHeader("Authorization"));
	}
}
위 두 가지 method를 구현하는 Class를 생성해준 후,
servlet-context.xml에 등록하거나, Configuration을 이용해 Resolver를 등록해주면 된다.
servlet-context.xml 등록
	<mvc:annotation-driven>
		<mvc:argument-resolvers>
			<bean class="project.config.resolver.ResultJwtArgumentResolver"></bean>
		</mvc:argument-resolvers>
	</mvc:annotation-driven>
Configuration 이용
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
    private final ResultJwtArgumentResolver resultJwtArgumentResolver;
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(resultJwtArgumentResolver);
    }
}
실제 적용
실제 본인의 경우는 아래와 같이 @RequestHeader로 Header에서 JWT 토큰을 가져와 Claims를 추출하는 공통 로직 부분을
	@GetMapping("")
	public ResponseEntity<Contents<Board>> getNotices(@RequestHeader(value = "Authorization") String jwt,
			@RequestParam(required = false) String category, CommonParameter<NoticeType> parameter) {
		ResultJwt resultJwt = authService.getResultJwt(jwt);
		String platformId = (String) resultJwt.getClaims().get(JwtClaims.PLATFORMID.getClaim());
간단한 Resolver를 구현하여 공통 로직을 추출하였고,
public class ResultJwtArgumentResolver implements HandlerMethodArgumentResolver {
	@Autowired
	private AuthService authService;
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return ResultJwt.class.isAssignableFrom(parameter.getParameterType());
	}
	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
			WebDataBinderFactory binderFactory) throws Exception {
		return authService.getResultJwt(webRequest.getHeader("Authorization"));
	}
}
아래와 같이 효과적으로 바로 Handler에서 매개변수로 사용할 수 있게 적용해 사용 중이다.
	@GetMapping("")
	public ResponseEntity<Contents<Board>> getNotices(ResultJwt resultJwt,
			@RequestParam(required = false) String category, CommonParameter<NoticeType> parameter) {
		String platformId = (String) resultJwt.getClaims().get(JwtClaims.PLATFORMID.getClaim());
                Author And Source
이 문제에 관하여([Spring] Resolver 란? Resolver 구현하기(HandlerMethodArgumentResolver)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gillog/Spring-HandlerMethodArgumentResolver-PathVariable-RequestHeader-RequestParam저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)