Spring MVC @RequestMappinginheritance

来自Struts2我习惯于在超类(或者package-info.java )上声明@Namespace注释,inheritance类随后将获取其祖先的@Namespace注释中的值,并将其添加到请求路径中行动。 我现在尝试使用@RequestMapping注释在Spring MVC中执行类似的操作,如下所示(为简洁起见,代码已修剪):

 package au.test @RequestMapping(value = "/") public abstract class AbstractController { ... } au.test.user @RequestMapping(value = "/user") public abstract class AbstractUserController extends AbstractController { @RequestMapping(value = "/dashboard") public String dashboard() { .... } } au.test.user.twitter @RequestMapping(value = "/twitter") public abstract class AbstractTwitterController extends AbstractUserController { ... } public abstract class TwitterController extends AbstractTwitterController { @RequestMapping(value = "/updateStatus") public String updateStatus() { .... } } 
  • /按预期工作
  • /user/dashboard按预期工作
  • 但是,当我希望/user/twitter/updateStatus工作时它没有并检查日志我可以看到一个类似于的日志条目:

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping – 映射的URL路径[/ tweeter / updateStatus]到处理程序’twitterController’上

是否有一个我可以启用的设置,它将扫描超类的@RequestMapping注释并构造正确的路径?

另外我认为在package-info.java中定义@RequestMapping包是非法的吗?

以下基本上成为/tweeter/updateStatus而不是/user/tweeter/updateStatus

 public abstract class TwitterController extends AbstractTwitterController { @RequestMapping(value = "/updateStatus") public String updateStatus() { .... } } 

这是预期的行为,因为您已经覆盖了您在AbstractControllerAbstractUserController声明的原始@RequestMapping

实际上,当您声明AbstractUserController时,它还会覆盖AbstractController@RequestMapping 。 它只是给你一个幻觉,即来自AbstractController的/已被inheritance。

“我是否可以启用一个设置来扫描超类以获取@RequestMapping注释并构建正确的路径?” 从来没听说过。

根据在启动时修改@RequestMappings中解释的技术,是的,可以以您想要的方式从超类构造URL模式。

实质上,您必须inheritanceRequestMappingHandlerMapping (很可能,它将是您的HandlerMapping实现,但请先检查)并覆盖受保护的getMappingForMethod方法。 一旦这变得可行,您就可以完全控制URL模式生成。

从你给出的例子来看,它并不完全清楚确切的合并策略,例如,如果超类AbstractTwitterController也使用自己的@RequestMapping实现updateStatus()方法,你想要有什么路径,或者你想如何连接URL模式层次结构,自上而下或自下而上,(我假设前者在下面),但是,希望以下代码片段能给你一些想法:

  private static class PathTweakingRequestMappingHandlerMapping extends RequestMappingHandlerMapping { @Override protected RequestMappingInfo getMappingForMethod(Method method, Class handlerType) { RequestMappingInfo methodMapping = super.getMappingForMethod(method, handlerType); if (methodMapping == null) return null; List superclassUrlPatterns = new ArrayList(); boolean springPath = false; for (Class clazz = handlerType; clazz != Object.class; clazz = clazz.getSuperclass()) if (clazz.isAnnotationPresent(RequestMapping.class)) if (springPath) superclassUrlPatterns.add(clazz.getAnnotation(RequestMapping.class).value()[0]);// TODO handle other elements in the array if necessary else springPath = true; if (!superclassUrlPatterns.isEmpty()) { RequestMappingInfo superclassRequestMappingInfo = new RequestMappingInfo("", new PatternsRequestCondition(String.join("", superclassUrlPatterns)), null, null, null, null, null, null);// TODO implement specific method, consumes, produces, etc depending on your merging policies return superclassRequestMappingInfo.combine(methodMapping); } else return methodMapping; } } 

另一个好问题是如何拦截RequestMappingHandlerMapping的实例化。 在因特网中,有各种各样的配置策略的各种示例。 但是,使用JavaConfig时,请记住,如果在@Configuration集中提供WebMvcConfigurationSupport ,那么@EnableWebMvc (显式或隐式)将停止工作。 我最终得到以下内容:

 @Configuration public class WebConfig extends DelegatingWebMvcConfiguration{ @Configuration public static class UnconditionalWebMvcAutoConfiguration extends WebMvcAutoConfiguration {//forces @EnableWebMvc } @Override protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() { return new PathTweakingRequestMappingHandlerMapping(); } @Bean @Primary @Override public RequestMappingHandlerMapping requestMappingHandlerMapping() { return super.requestMappingHandlerMapping(); } } 

但想了解更好的方法。