2017-04-20 136 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

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