为包中的所有控制器类的URL添加前缀

问题描述:

我正在使用在Tomcat Apache 6.0环境上运行的Spring 3.0开发RESTful服务。 Spring DispatcherServlet配置为“/ spring/*”。 Spring servlet处理多个客户端,并在应用程序中有许多控制器。我正在为REST服务添加一个新的控制器。我想我所有的控制器类的能有像“WS”(网络服务)标识前缀,以便完整的URL到资源看起来是这样的:
http://<server>:<port>/<context>/spring/ws/service1为包中的所有控制器类的URL添加前缀

我发现春天注释的唯一方法是使用@RequestMapping这样的:

@Controller 
@RequestMapping("/ws/service1") 
public class Service1 { 

@RequestMapping(method=RequestMethod.GET) 
@ResponseBody 
public String getHtml() { ... } 

.... 
} 

但因为我有几十个班,我不希望把“/ WS”前缀每个类。因此,如果另一个开发人员添加了一个新服务,他不必记住这个前缀,并且如果我们决定将前缀名称从“/ ws”更改为其他名称,则不必更改所有文件。我发现@RequestMapping注解仅适用于方法或类,而不适用于包级别。

有没有什么办法可以配置我的所有REST控制器都使用前缀进行访问?

请注意,我无法更改Spring servlet的web.xml URL映射,因为有其他控制器正在使用该URL运行。

+0

你的最后一句话是至关重要的 - 你可以扩展你的“其他控制器”的含义吗? – skaffman

+0

我的Spring servlet提供Flex客户端,我使用BlazeDS控制器。 Tomcat服务器本身也必须提供一些静态内容。除此之外,RESTful控制器也是如此。所以我无法将Spring servlet url映射到“/ *”或“/ ws/*”。 – Shreerang

您可能想看看Spring 3的convention over configuration支持,特别是ControllerClassNameHandlerMapping。实际上,您不需要在@RequestMapping中定义URL的位置,但它是由处理程序的程序包位置定义的。

如果您希望映射的URL反映控制器的软件包名称,那么您应该设置basePackage属性ControllerClassNameHandlerMapping。该documentation

Set the base package to be used for generating path mappings, including all subpackages underneath this packages as path elements. Default is null, using the short class name for the generated path, with the controller's package not represented in the path. Specify a base package like "com.mycompany.myapp" to include subpackages within that base package as path elements, e.g. generating the path "/mymodule/buyform" for the class name "com.mycompany.myapp.mymodule.BuyForm". Subpackage hierarchies are represented as individual path elements, e.g. "/mymodule/mysubmodule/buyform" for the class name "com.mycompany.myapp.mymodule.mysubmodule.BuyForm".

所以,一个例子豆类定义可能是

<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"> 
    <property name="basePackage" value="com.company.project"/> 
</bean> 
<context:component-scan base-package="com.company.project.ws"/> 

而且你的控制器看起来像

package com.company.project.ws; 
@Controller 
public class Service1 { 
    // your controller methods 
} 
+0

是的,我其实已经看过。您能否告诉我,是否可以使用URL映射来考虑软件包名称?例如,如果完全限定的类名是“com.ws.Service1”,那么它会映射到URL“/ ws/service1”等等? – Shreerang

+0

是的,这是可能的。没有在引用中解释,但JavaDoc有必要的指针。我已经更新了答案,以反映你将如何实现这一目标。如果您想为路径添加前缀,您可能还需要查看ControllerClassNameHandlerMapping的pathPrefix属性。 – ptomli

+0

这看起来不错,我试过,但我得到了以下错误: javax.servlet.ServletException:处理程序没有适配器[[email protected]]:您的处理程序是否实现受控接口,如Controller ? 即使我已经定义了bean 有什么建议吗? – Shreerang

另一种方法(很基本的,简单的),我实现的是定义多个Dispatcher servlet,然后为每个servlet映射不同的URL。 Servlet共享Spring根上下文,除此之外,还有自己的bean定义。阅读更多在这Java doc

所以我的web.xml的样子:

<servlet> 
    <servlet-name>flex</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<!-- Mappings for BlazeDS requests --> 
<servlet-mapping> 
    <servlet-name>flex</servlet-name> 
    <url-pattern>/spring/messagebroker/*</url-pattern> 
</servlet-mapping> 

<!-- Second dispatcher servlet for Web Services API --> 
<servlet> 
    <servlet-name>wsapi</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <load-on-startup>2</load-on-startup> 
</servlet> 
<servlet-mapping> 
    <servlet-name>wsapi</servlet-name> 
    <url-pattern>/spring/ws/*</url-pattern> 
</servlet-mapping> 

基本上,我离开现有的调度的servlet,因为它是和添加一个新的servlet仅适用于具有不同的URL映射REST控制器。所以我可以分别控制这些servlet的URL。在此之后,我不再需要在每个控制器上放置URL前缀。