首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring中带有URL版本的控制器继承和模糊映射

Spring中带有URL版本的控制器继承和模糊映射
EN

Stack Overflow用户
提问于 2013-07-30 11:48:43
回答 1查看 3.2K关注 0票数 2

我试图使用Spring设置版本化的服务,使用继承来扩展旧的控制器,以避免重写不变的控制器方法。我的解决方案基于一个关于版本控制服务的前一个问题,但是我遇到了一个映射不明确的问题。

代码语言:javascript
复制
@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中的BookmarkJsonControllerV2

代码语言:javascript
复制
@Override
public Map<String, String> writeBookmark(@RequestParam String parameter) {
  return null; // Shouldn't actually be used
}

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

代码语言:javascript
复制
return new HashMap<String, String>() {{
  put("This is called from /rest/v2/bookmark/write", "?!");
}};

我将收到带有该映射的JSON,这表明尽管没有任何请求映射注释,但它显然是在“继承”来自超类的注释。在这一点上,我对将来验证控制器扩展的唯一“解决方案”是让每个控制器返回Object,并且只有HttpServletRequestHttpServletResponse对象作为参数。这似乎是一次彻头彻尾的黑客攻击,我宁愿永远不这么做。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-08-01 11:46:24

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

注意事项:我使用Spring3.1,它为处理程序映射提供了与以前版本不同的类。

springmvc-路由器项目将路由器系统从播放框架带到springmvc。在我的application-context.xml中,相关设置如下:

代码语言:javascript
复制
<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使用了一个责任链系统,因此我们可以分配多个映射处理程序。在这里,我有一个类似于这样的路由器配置:

代码语言:javascript
复制
# 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

与控制员一起看上去如下:

代码语言:javascript
复制
@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")

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17946231

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档