2011-03-11 117 views
27

来自Struts2我习惯于在超类(或package-info.java)上声明@Namespace注解,并且继承类将随后选取其祖先的@Namespace注释中的值并将其预先加载到请求路径为行动。我现在要做的使用@RequestMapping注释在Spring MVC类似如下(修剪简码):Spring MVC @RequestMapping继承

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路径[/高音/ updateStatus]在处理 'twitterController'

是否有设置我可以启用将扫描超类为@RequestMapping注释并构建正确的路径?

另外我还认为在package-info.java的封装上定义@RequestMapping是非法的?

回答

24

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

public abstract class TwitterController extends AbstractTwitterController { 

    @RequestMapping(value = "/updateStatus")  
    public String updateStatus() { 
     .... 
    } 
} 

这是预期的行为,因为你已经重写你声明的原始@RequestMappingAbstractControllerAbstractUserController

实际上,当您声明AbstractUserController时,它也覆盖@RequestMappingAbstractController。它只是给你一个错觉,认为AbstractController已被继承。

“是否有可以启用的设置,将扫描@RequestMapping批注的超类并构建正确的路径?”从来没听说过。

+6

你有没有任何机会得到任何其他建议,如何实现这一点。在我看来,像一个废物不得不把/ x/y/z放在一个子类环境中。然后,如果我决定更改/ x/to/k /,我必须到代码中定义的所有位置并手动更改它! – garyj

+0

@chris:这不适合我。是否涉及配置步骤,还是仅仅是注释问题?基本控制器确实与扩展基本控制器的控制器在同一个包中。但是,基本控制器的URI/RequestMapping被忽略和/或未找到。 “org.springframework.web.servlet.DispatcherServlet:947 - 没有找到具有URI的HTTP请求的映射”。所以,如果我只是使用扩展控制器的“基础”RequestMapping,那很好。如果我尝试使用由基本控制器继承的RequestMapping,则无法找到URI。 – Rick

+0

它的值得明确指出,超类路径仍然可路由。也就是说,覆盖一个类并提供新的@ RequestMapping不会覆盖或替换超类的@ RequestMapping,它只是增加了一些。例如,在OP的问题中,这意味着所有这些路径都是有效的:'/ user/dashboard','/ twitter/updateStatus'。 – kuporific

0

根据Modifying @RequestMappings on startup, 中解释的技术,可以根据需要从超类构建URL模式。

从本质上说,你必须继承RequestMappingHandlerMapping(最有可能的,这将是你HandlerMapping实现,但请先检查) 和覆盖保护getMappingForMethod方法。 一旦这个可行,你完全可以控制URL模式的生成。

从你给它不是完全清楚确切的合并方针,例如例如,你想拥有什么样的路径,如果 一个超AbstractTwitterController还实现了updateStatus()方法都有自己的@RequestMapping,或者您希望如何来连接的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<String> superclassUrlPatterns = new ArrayList<String>(); 
        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。在互联网上有各种配置策略的各种示例。 但是,请记住,如果您在@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(); 
    } 

} 

但希望了解更好的方法。