【问题标题】:Add prefix to URLs of all the controller classes in the package为包中所有控制器类的 URL 添加前缀
【发布时间】:2011-07-13 19:14:41
【问题描述】:

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

我发现 Spring 注释的唯一方法是像这样使用 @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 运行。

【问题讨论】:

  • 你的最后一句话很关键——你能详细解释一下“其他控制器”的含义吗?
  • 我的 Spring servlet 服务于 Flex 客户端,为此我使用 BlazeDS 控制器。 Tomcat 服务器本身也必须提供一些静态内容。 RESTful 控制器是除此之外的。所以我无法将 Spring servlet url 映射到“/*”或“/ws/*”。

标签: spring url rest controller


【解决方案1】:

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

如果您想让映射的 URL 反映控制器的包名称,那么您应该设置 ControllerClassNameHandlerMappingbasePackage 属性。 documentation

设置用于生成路径映射的基础包,包括此包下的所有子包作为路径元素。 默认为空,使用生成路径的短类名,控制器的包不在路径中表示。指定一个基本包,如“com.mycompany.myapp”,以在该基本包中包含子包作为路径元素,例如为类名“com.mycompany.myapp.mymodule.BuyForm”生成路径“/mymodule/buyform”。子包层次结构表示为单独的路径元素,例如类名“com.mycompany.myapp.mymodule.mysubmodule.BuyForm”的“/mymodule/mysubmodule/buyform”。

所以,一个示例 bean 定义可能是

<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
}

【讨论】:

  • 是的,事实上我已经调查过了。您能否告诉我是否可以进行考虑包名称的 URL 映射?例如,如果完全限定的类名是“com.ws.Service1”,那么它会映射到 URL“/ws/service1”等等吗?
  • 是的,这是可能的。参考资料中没有解释,但 JavaDoc 有必要的指针。我已经更新了答案以反映您将如何实现这一目标。如果您想为路径添加前缀,您可能还想查看 ControllerClassNameHandlerMapping 的 pathPrefix 属性。
  • 这看起来不错,我试过了,但出现以下错误:javax.servlet.ServletException: No adapter for handler [com.coresecurity.wsapi.ws.Service@407d11]: 你的处理程序实现了吗支持的接口,如控制器?即使我已经定义了 bean 有什么建议吗?
  • 您可能想看看 AnnotationMethodHandlerAdapter,以及基于注释的控制器的参考。 static.springsource.org/spring/docs/3.0.x/reference/….
  • 是的,我尝试了 AnnotationMethodHandlerAdapter 并且成功了。我接受这个作为答案,因为它确实解决了我提出的问题。但是,我采用了不同的方法在我的项目中实施解决方案。为了他人的利益,我将其作为不同的答案。
【解决方案2】:

我实现的另一种方法(非常基本和简单)是定义多个 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,并为具有不同 URL 映射的 REST 控制器添加了一个新的 servlet。所以我可以分别控制这些 servlet 的 URL。在此之后,我不再需要在每个 Controller 上放置 URL 前缀。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多