【问题标题】:Controller Inheritance and Ambiguous Mappings with URL Versioning in Spring MVCSpring MVC 中带有 URL 版本控制的控制器继承和模糊映射
【发布时间】:2013-07-30 11:48:43
【问题描述】:

我正在尝试使用 Spring MVC 设置版本化服务,使用继承来扩展旧控制器以避免重写未更改的控制器方法。我的解决方案基于关于版本控制服务的previous question,但是我遇到了不明确映射的问题。

@Controller
@RequestMapping({"/rest/v1/bookmark"})
public class BookmarkJsonController {

  @ResponseBody
  @RequestMapping(value = "/write", produces = "application/json", method = RequestMethod.POST)
  public Map<String, String> writeBookmark(@RequestParam String parameter) {
    // Perform some operations and return String
  }
}

@Controller
@RequestMapping({"/rest/v2/bookmark"})
public class BookmarkJsonControllerV2 extends BookmarkJsonController {

  @ResponseBody
  @RequestMapping(value = "/write", produces = "application/json", method = RequestMethod.POST)
  public BookmarkJsonModel writeBookmark(@RequestBody @Valid BookmarkJsonModel bookmark) {
    // Perform some operations and return BookmarkJsonModel
  }
}

通过此设置,我得到IllegalStateException: Ambiguous mapping found。我对此的想法是,因为我有两个具有不同返回/参数类型的方法,所以我在 BookmarkJsonControllerV2 中有两个具有相同映射的方法。作为一种解决方法,我尝试在没有任何请求映射的情况下覆盖 BookmarkJsonControllerV2 中的 writeBookmark:

@Override
public Map<String, String> writeBookmark(@RequestParam String parameter) {
  return null; // Shouldn't actually be used
}

但是,当我编译并运行这段代码时,我仍然遇到了不明确映射的异常。但是,当我点击 URL /rest/v2/bookmark/write 时,我得到了一个空/空响应。将return null 更改为:

return new HashMap<String, String>() {{
  put("This is called from /rest/v2/bookmark/write", "?!");
}};

我会收到带有该映射的 JSON,这表明尽管没有任何请求映射注释,但它显然是“继承”了超类的注释。在这一点上,我对控制器扩展的唯一“解决方案”是让每个控制器返回 Object 并且只有 HttpServletRequest 和 HttpServletResponse 对象作为参数。这似乎完全是 hack,我宁愿永远不要这样做。

那么有没有更好的方法来使用 Spring MVC 实现 URL 版本控制,它只允许我在后续版本中覆盖更新的方法,还是我唯一真正的选择是完全重写每个控制器?

【问题讨论】:

  • 你能发布你的 applicationContext.xml 吗?你是手动编写bean还是通过扫描包?这两种配置的混合可能会导致此问题。
  • @DeividiCavarzan 我确实在application-context.xml 中设置了一些与 Spring Security 相关的 bean,其余的都是通过扫描包来设置的。现在想起来有点没有实际意义,因为我已经通过为我的 REST 服务使用不同的处理程序映射来完成这项工作。

标签: spring-mvc versioning


【解决方案1】:

无论出于何种原因,使用 @RequestMapping 注释会导致不明确的映射异常。作为一种解决方法,我决定尝试将springmvc-router 用于我的 REST 服务,这将允许我在我的控制器类上利用继承,这样我就不必重新实现没有根据需要在版本之间更改的端点。我的解决方案还允许我继续为我的非 REST 控制器使用注释映射。

注意:我使用的是 Spring 3.1,它的处理程序映射类与以前的版本不同。

springmvc-router 项目将路由器系统从 Play 框架引入 Spring MVC。在我的application-context.xml 内部,相关设置如下:

<mvc:annotation-driven/>
<bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />

<bean class="org.resthub.web.springmvc.router.RouterHandlerMapping">
    <property name="routeFiles">
        <list>
            <value>routes/routes.conf</value>
        </list>
    </property>
    <property name="order" value="0" />
</bean>

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="order" value="1" />
</bean>

这使我可以继续在路由器旁边使用带注释的控制器。 Spring 使用责任链系统,因此我们可以分配多个映射处理程序。从这里,我有一个这样的路由器配置:

# Original Services

POST    /rest/bookmark/write     bookmarkJsonController.write
POST    /rest/bookmark/delete    bookmarkJsonController.delete

# Version 2 Services

POST    /rest/v2/bookmark/write  bookmarkJsonControllerV2.write
POST    /rest/v2/bookmark/delete bookmarkJsonControllerV2.delete

控制器看起来像:

@Controller
public class BookmarkJsonController {
  @ResponseBody
  public Map<String, Boolean> write(@RequestParam String param) { /* Actions go here */ }

  @ResponseBody
  public Map<String, Boolean> delete(@RequestParam String param) { /* Actions go here */ }
}

@Controller
public class BookmarkJsonControllerV2 extends BoomarkJsonController {
  @ResponseBody
  public Model write(@RequestBody Model model) { /* Actions go here */ }
}

通过这样的配置,URL /rest/v2/bookmark/write 将命中方法 BookmarkJsonControllerV2.write(Model model),而 URL /rest/v2/bookmark/delete 将命中继承方法 BookmarkJsonController.delete(String param)。

这样做的唯一缺点是必须为新版本重新定义整个路由,而不是将类上的 @RequestMapping(value = "/rest/bookmark") 更改为 @RequestMapping(value = "/rest/v2/bookmark")。

【讨论】:

    猜你喜欢
    • 2020-01-16
    • 1970-01-01
    • 2017-09-21
    • 2013-07-17
    • 2018-11-22
    • 2016-10-14
    • 2018-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多