簡體   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