2017-04-20 142 views
2

我有以下的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(); 
    } 
} 

我知道,春天meta annotations可以幫助我。

所以我定義了註解:

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

    String param2() default ""; 

} 

這本身就不會做的伎倆。

所以我添加一個攔截器來處理與「參數2」:

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甚至具有「參數2」不同的值註釋兩種方法然後我得到了應用程序啓動的「曖昧映射」錯誤:

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引導具有Spring Web 4.3.5

回答

0

1.4.3,我認爲解決這個問題的最好的辦法是你的@RequestMapping註解移動到方法的水平,而不是一流水平。

Spring給你的錯誤是因爲Spring綁定了一個無效的路徑上的多個處理程序。也許給我們一個你想要公開的URL的例子,這樣我們就可以更好地瞭解你想要構建的內容。

1

您不能在堆棧中使用它們的參數綁定註釋,並且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

這是相當棘手和複雜的,但這只是實現你想要的一種方式,我相信。