[Spring] @RequestMapping의 wildcard 패턴 **의 값을 배열로 얻기
- IT/PROGRAMMING
- 2019. 2. 9. 01:10
스프링 프레임워크를 이용하여 컨트롤러에 패턴을 등록하면 다양한 URI로 매핑시킬 수 있다.
이때 와일드카드(wildcard)를 자주 사용하게 되는데 기본적으로 ?, *, ** 가 있다.
아래는 스프링 문서 설명이다.
※ 출처: Spring Web MVC - Web on Servlet Stack (https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html)
또한, {XXXXX}과 @PathVariable 어노테이션을 이용하여 URI의 특정부분을 변수에 할당할 수도 있다.
그리고 정규표현식(regular expression)도 지원한다.
가끔 매핑 패턴을 /path1/path2/** 처럼 여러개의 경로를 지원할 필요가 있는데, 단순하게 매핑뿐만 아니라 실제 ** 에 해당하는 경로를 얻어야할 때가 있다.
** 에 해당하는 값을 @PathVariable 처럼 문자열(String) 또는 문자열배열(String[])로 쉽게 바인딩하는 것을 스프링에서 지원하면 좋겠지만, 아무리 찾아봐도 없다.
그래서 이것을 구현하기 위한 방법을 설명하려고 한다.
혹시라도 스프링 기본기능으로 바인딩하는 방법을 아시는 분은 댓글로 남겨주세요.
아래와 같이 컨트롤러에 @WildcardPathVariable 어노테이션을 사용하여 **에 해당하는 값을 문자열배열로 바인딩하려고 한다.
TestController.java
@Controller
@RequestMapping(value = "/test")
public class TestController {
@GetMapping("/path1/path2/**")
public String[] getPaths(@WildcardPathVariable String[] paths) {
return paths;
}
}
아래는 @WildcardPathVariable 어노테이션 구현체이다.
WildcardPathVariable.java
/**
* 패턴이 "/path1/path2/**"이고 경로가 "/path1/path2/path3/path4"일 때, "path3/path4"를 얻기위한 어노테이션
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface WildcardPathVariable {
}
아래처럼 @WildcardPathVariable이 작동하도록 resolver를 작성한다.
핵심은 스프링에서 Request 객체에 attribute로 설정해주는 값 중, HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE 과 HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE 을 얻는것과, AntPathMatcher를 사용하는 것이다.
특히 AntPathMatcher의 extractPathWithinPattern() 메서드가 중요하다.
이 메서드를 간단하게 설명하면, 입력된 패턴(pattern) 중 wildcard 위치에 해당하는 경로(path)를 반환한다.
자세한 것은 스프링 소스코드 주석에 있는 샘플을 참고하기 바란다.
WildcardPathVariableHandlerMethodArgumentResolver.java
/**
* WildcardPathVariable 어노테이션을 처리하는 resolver
*/
public class WildcardPathVariableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
/**
* AntPathMatcher
*/
private AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.hasParameterAnnotation(WildcardPathVariable.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) nativeWebRequest.getNativeRequest();
// /path1/path2/**
String pattern = (String) httpServletRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
// /path1/path2/path3/path4
String path = (String) httpServletRequest.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
// 와일드카드 이후로 얻기
String wildcardPath = antPathMatcher.extractPathWithinPattern(pattern, path);
// "/"으로 분리
String[] splitPaths = StringUtils.split(wildcardPath, AntPathMatcher.DEFAULT_PATH_SEPARATOR);
return splitPaths;
}
}
Resolver를 사용하기 위하여 빈으로 정의하고, 스프링 argumentResolver에 등록한다.
WebConfig.java
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(wildcardPathVariableHandlerMethodArgumentResolver());
}
@Bean
public WildcardPathVariableHandlerMethodArgumentResolver wildcardPathVariableHandlerMethodArgumentResolver() {
return new WildcardPathVariableHandlerMethodArgumentResolver();
}
}
'IT > PROGRAMMING' 카테고리의 다른 글
[Spring] 웹어플리케이션의 Whitelabel 오류 페이지 비활성화 (0) | 2019.02.19 |
---|---|
[Java] 클래스에 정의된 제너릭(generic) 타입의 Class를 얻는 방법 (0) | 2019.02.12 |
[Java] IP주소가 loopback(127.0.0.1)인지 확인하는 방법 (0) | 2019.02.08 |
[Java] IP주소가 사설(private) 네트워크인지 확인하는 방법 (0) | 2019.02.08 |
[Spring] Spring bean 이름의 getter/setter 구현 (0) | 2019.02.06 |