繁体   English   中英

Spring请求映射自定义注释 - 模糊映射

[英]Spring request mapping custom annotations - ambiguous mapping

我有以下Spring MVC控制器:

@RestController
@RequestMapping(value = "my-rest-endpoint")
public class MyController {

    @GetMapping
    public List<MyStuff> defaultGet() {
        ...
    }

    @GetMapping(params = {"param1=value1", "param2=value2"})
    public MySpecificStuff getSpecific() {
        ...
    }

    @GetMapping(params = {"param1=value1", "param2=value3"})
    public MySpecificStuff getSpecific2() {
        return uiSchemas.getRelatedPartyUi();
    }
}

我需要的是使用自定义注释使其更通用:

@RestController
@RequestMapping(value = "my-rest-endpoint")
public class MyController {

    @GetMapping
    public List<MyStuff> defaultGet() {
        ...
    }

    @MySpecificMapping(param2 = "value2")
    public MySpecificStuff getSpecific() {
        ...
    }

    @MySpecificMapping(param2 = "value3")
    public MySpecificStuff getSpecific2() {
        return uiSchemas.getRelatedPartyUi();
    }
}

我知道Spring meta注释可以帮助我。

所以我定义了注释:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(method = RequestMethod.GET, params = {"param1=value1"})
public @interface MySpecificMapping {

    String param2() default "";

}

仅凭这一点就无法解决问题。

所以我添加了一个拦截器来处理“param2”:

public class MyInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // get annotation of the method
            MySpecificMapping mySpecificMapping = handlerMethod.getMethodAnnotation(MySpecificMapping.class);
            if (mySpecificMapping != null) {
                // get the param2 value from the annotation
                String param2 = mySpecificMapping.param2();
                if (StringUtils.isNotEmpty(param2)) {
                    // match the query string with annotation
                    String actualParam2 = request.getParameter("param2");
                    return param2 .equals(actualParam2);
                }
            }
        }

        return true;
    }

}

当然,将它包含在Spring配置中。

这工作正常,但只有每个控制器有一个这样的自定义映射。

如果我添加两个用@MySpecificMapping注释的方法,即使具有不同的“param2”值,那么我得到应用程序启动的“模糊映射”错误:

java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'myController' method 
public com.nailgun.MySpecificStuff com.nailgun.MyController.getSpecific2()
to {[/my-rest-endpoint],methods=[GET],params=[param1=value1]}: There is already 'myController' bean method
public com.nailgun.MySpecificStuff com.nailgun.MyController.getSpecific() mapped.
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.assertUniqueMethodMapping(AbstractHandlerMethodMapping.java:576)
 - Application startup failed

我明白为什么会这样。

但是,你能帮助我给Spring一个提示,那就是两个不同的映射吗?

我在Spring Web 4.3.5中使用Spring Boot 1.4.3

@AliasFor是做这样的事情的注释。 以下是使用@RequestMapping的自定义注释示例

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public @interface JsonGetMapping {
    @AliasFor(annotation = RequestMapping.class, attribute = "value")
    String value() default "";
}

以及使用的例子

@JsonGetMapping("/category/{categoryName}/books")
public List<Book> getBooksByCategory(@PathVariable("categoryName") String categoryName){
    return bookRepository.getBooksByCategory(categoryName);
}

你不能用它们的参数绑定堆栈中的注释,Spring会将这两个方法视为具有相同@RequestMapping方法。

但你可以尝试制作一个技巧:在映射构建器之前以某种方式嵌入自定义注释增强器并执行注释替换:

  1. 使用注释@MySpecificMapping获取所有方法:

    MySpecificMapping myMapping = ...;

  2. 为每个这样的方法读取@RequestMapping注释,让我们说它会是

    RequestMapping oldMapping = ...;

  3. 创建@RequestMapping类的新实例:

    RequestMapping newMapping = new RequestMapping() { // ... rest methods @Override public String[] params() { // here merge params from old and MySpecificMapping: String[] params = new String[oldMapping.params().length + 1]; // todo: copy old one // ... params[params.length-1] = myMapping.param2(); return params; } }

  4. Forcly分配这个新newMapping每种方法相对应,而不是oldMapping

这是非常棘手和复杂的,但我相信这只是实现你想要的一种方式。

我认为解决这个问题的最佳方法是将@RequestMapping注释移动到方法级别而不是类级别。

Spring给出的错误是因为Spring在一条无效的路径上绑定了多个处理程序。 也许给我们一个您想要公开的URL的示例,以便我们更好地了解您要构建的内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM