HandlerMethodArgumentResolver
HandlerMethodArgumentResolver는 API가 호출될 때 매개 변수를 입력받기 위해 사용하는 Spring에서 제공하는 기능이다. 해당 인터페이스로 가보면 "지정된 요청의 컨텍스트에서 메서드 매개 변수를 인수 값으로 만들기 위한 전략 인터페이스" 라고 설명이 되있다.
즉 우리가 Controller에서 매개 변수를 받기 위해 사용하는 @PathVariable, @RequestParam, @RequestBody 등이 이 인터페이스를 이용해 원하는 값을 얻게 해주는 것이다.
HandlerMethodArgumentResolver는 두개의 추상 메소드를 가지고 있다.
- supportsParameter : 이 Resolver가 지원하는 매개 변수인 경우 true를 리턴하고 그 외에는 false를 리턴한다
- resulveArgument : 요청 데이터에서 찾아서 매개 변수의 값에 매핑해 리턴해준다
Custom HandlerMethodArgumentResolver 만들기
직접 HandlerMethodArgumentResolver를 만들어 사용하려면 받고자 하는 인자값에 명시해 줄 Annotation을 만들어줘야 한다. 먼저 API를 호출한 사람의 IP를 얻는 기능을 추가해보겠다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface GetIp {
}
public class GetIpArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(GetIp.class) != null;
}
@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory
) {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
String ip = request.getHeader("X-FORWARDED-FOR");
if (ip == null) ip = request.getRemoteAddr();
return ip;
}
}
supportsParameter 함수에는 우리가 선언한 Annotation이 적용된지 판별하는 판별식을 작성해준다.
resolveArgument에는 webRequest로부터 ip를 얻기 위해 HttpServletRequest로 변환해 준뒤 ip를 보관하는 헤더값을 가져와 리턴해준다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(ipArgsResolver());
resolvers.add(headerArgsResolver());
}
@Bean
public GetIpArgumentResolver ipArgsResolver() {
return new GetIpArgumentResolver();
}
}
마지막으로 직접 만든 Resolver를 Bean에 등록해주고 Controller에서 받고자하는 매개변수에 Annotation을 붙여준다.
@RestController
public class MyController {
@GetMapping("/getIp")
public Map<String, ?> getIp(@GetIp String ip) {
return Map.of(
"result", ip
);
}
}
HandlerMethodArgumentResolver는 한개가 아니라 여러개도 등록해 사용할 수 있다. 이번에는 Header에 저장된 모든 값을 가져오는 Resolver를 만들어 보겠다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface GetHeader {
}
public class GetHeaderArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(GetHeader.class) != null;
}
@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory
) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
Enumeration<String> headerNames = request.getHeaderNames();
Map<String, String> headers = new HashMap<>();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.put(headerName, request.getHeader(headerName));
}
return headers;
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(ipArgsResolver());
resolvers.add(headerArgsResolver());
}
@Bean
public GetIpArgumentResolver ipArgsResolver() {
return new GetIpArgumentResolver();
}
@Bean
public GetHeaderArgumentResolver headerArgsResolver() {
return new GetHeaderArgumentResolver();
}
}
@RestController
public class MyController {
@GetMapping("/getIp")
public Map<String, ?> getIp(@GetIp String ip) {
return Map.of(
"result", ip
);
}
@GetMapping("/getHeader")
public Map<String, ?> getHeader(@GetHeader Object headers) {
return Map.of(
"result", headers
);
}
}
같은 방법으로 매개 변수에 붙여줄 Annotation을 만들어 주고 Resolver를 만든다음 Bean에 등록하여 사용하였다.
결과값으로 모든 Header 정보들이 리턴되는 것을 확인할 수 있다.
'spring' 카테고리의 다른 글
Spring - Kafka 연동하기 (0) | 2021.12.04 |
---|---|
Spring에서 Http Request 보내기 - Feign (0) | 2021.09.19 |
Spring Data Event Handler (0) | 2021.06.19 |
JWT를 이용한 인증 처리 (0) | 2021.05.29 |
테스트 코드 커버리지 확인하기 (jacoco) tutorial (0) | 2021.05.01 |
댓글