环境:springboot2.2.10.RELEASE
自定义请求匹配
希望根据请求中header['x-token']的不同值调用不同的接口。接口请求地址相同,根据不同的header信息调用不同的执行方法。
在SpringMVC中可以通过自定义
RequestMappingHandlerMapping#getCustomMethodCondition来实现此功能。
自定义请求匹配通过实现RequestCondition接口自定义规则
系统默认提供了以下RequestCondition实现
自定义匹配条件
- public class CustomRequestCondition implements RequestCondition<CustomRequestCondition> {
- private static final String X_TOKEN_NAME = "x-token" ;
- private Method method ;
- public CustomRequestCondition(Method method) {
- this.method = method ;
- }
- // 当接口上有多个匹配规则时,进行合并操作
- @Override
- public CustomRequestCondition combine(CustomRequestCondition other) {
- return new CustomRequestCondition(other.method) ;
- }
- // 核心方法:根据匹配的条件进行判断是否匹配,如果匹配则返回当前的对象,不匹配则返回null
- @Override
- public CustomRequestCondition getMatchingCondition(HttpServletRequest request) {
- AKF akf = method.getAnnotation(AKF.class) ;
- return akf != null ? buildToken(request, akf) : null ;
- }
- // 当有多个都满足条件的时候,进行比较具体使用哪个
- @Override
- public int compareTo(CustomRequestCondition other, HttpServletRequest request) {
- return 0 ;
- }
- // 判断请求header中的信息与注解中配置的信息是否一致
- private CustomRequestCondition buildToken(HttpServletRequest request, AKF akf) {
- String xToken = request.getHeader(X_TOKEN_NAME) ;
- if (xToken == null || xToken.length() == 0) {
- return null ;
- }
- return xToken.equals(akf.value()) ? this : null ;
- }
- }
自定义HandlerMapping
- public class CustomMethodConditionRequestHandlerMapping extends RequestMappingHandlerMapping {
- @Override
- protected RequestCondition<?> getCustomMethodCondition(Method method) {
- return new CustomRequestCondition(method) ;
- }
- }
配置自定义的HandlerMapping
- @Configuration
- public class CustomEndpointConfig extends WebMvcConfigurationSupport {
- @Override
- protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
- return new CustomMethodConditionRequestHandlerMapping() ;
- }
- }
注册HandlerMapping我们也可以通过@Bean的方式,但是这种方式会使得你在定义多个相同接口地址的时候容器启动就会报错
而且@Bean的方式是向容器中注册一个HandlerMapping对象;而通过上面的方式就是替换系统默认的
RequestMappingHandlerMapping对象。两种方式是不一样的,一个是增加一个HandlerMapping,一个是替换系统默认的。
测试接口
- @RestController
- @RequestMapping("/conditions")
- public class CustomMethodConditionController {
- @GetMapping("/index")
- public Object index() {
- return "custom method condition success" ;
- }
- @GetMapping("/index")
- @AKF
- public Object x() {
- return "x method invoke" ;
- }
- @GetMapping("/index")
- @AKF("x1")
- public Object x1() {
- return "x1 method invoke" ;
- }
- @GetMapping("/index")
- @AKF("x2")
- public Object x2() {
- return "x2 method invoke" ;
- }
- }
上面的接口地址完全相关,只是有些有@AKF注解,有些没有。
如果通过@Bean注册一个HandlerMapping后,多个请求路径相同会报如下错误:
- Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'customMethodConditionController' method
- com.pack.controller.CustomMethodConditionController#x()
- to {GET /conditions/index}: There is already 'customMethodConditionController' bean method
- com.pack.controller.CustomMethodConditionController#index() mapped.
- at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.validateMethodMapping(AbstractHandlerMethodMapping.java:636) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
- at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:603) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
在以上的请求中如果请求中没有携带x-token信息或者是value值不被匹配那么请求会是404。