首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring请求映射自定义注释.模糊映射

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

Stack Overflow用户
提问于 2017-04-20 12:55:12
回答 3查看 3.8K关注 0票数 1

我有以下Spring控制器:

代码语言:javascript
复制
@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();
    }
}

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

代码语言:javascript
复制
@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 元注释可以帮助我做到这一点。

因此,我定义了注释:

代码语言:javascript
复制
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(method = RequestMethod.GET, params = {"param1=value1"})
public @interface MySpecificMapping {

    String param2() default "";

}

光靠这个是不行的。

因此,我添加了一个拦截器来处理"param2":

代码语言:javascript
复制
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“值,那么我就会得到应用程序启动的”模糊映射“错误:

代码语言:javascript
复制
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

我明白为什么会发生这种事。

,但你能帮我暗示一下这是两个不同的映射吗?

我在SpringWeb4.3.5中使用SpringBoot1.4.3

EN

回答 3

Stack Overflow用户

发布于 2018-06-02 10:14:14

@AliasFor是用于这样做的注释。下面是一个使用@RequestMapping进行自定义注释的示例

代码语言:javascript
复制
@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 "";
}

也是使用的例子

代码语言:javascript
复制
@JsonGetMapping("/category/{categoryName}/books")
public List<Book> getBooksByCategory(@PathVariable("categoryName") String categoryName){
    return bookRepository.getBooksByCategory(categoryName);
}
票数 4
EN

Stack Overflow用户

发布于 2017-04-20 13:35:28

不能将堆栈中的注释绑定到它们的params中,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

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

票数 1
EN

Stack Overflow用户

发布于 2017-04-20 13:25:56

我认为最好的方法是将@RequestMapping注释移到方法级别,而不是类级别。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43520174

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档