我试图使用Spring设置版本化的服务,使用继承来扩展旧的控制器,以避免重写不变的控制器方法。我的解决方案基于一个关于版本控制服务的前一个问题,但是我遇到了一个映射不明确的问题。
@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:
@Override
public Map<String, String> writeBookmark(@RequestParam String parameter) {
return null; // Shouldn't actually be used
}然而,当我编译和运行这段代码时,我仍然得到了一个模糊映射的异常。但是,当我点击/rest/v2/bookmark/write时,我得到了一个空/空响应。将return null更改为:
return new HashMap<String, String>() {{
put("This is called from /rest/v2/bookmark/write", "?!");
}};我将收到带有该映射的JSON,这表明尽管没有任何请求映射注释,但它显然是在“继承”来自超类的注释。在这一点上,我对将来验证控制器扩展的唯一“解决方案”是让每个控制器返回Object,并且只有HttpServletRequest和HttpServletResponse对象作为参数。这似乎是一次彻头彻尾的黑客攻击,我宁愿永远不这么做。
那么,是否有更好的方法来使用Spring来实现URL版本控制,这种方法只允许我在后续版本中覆盖更新的方法,还是我唯一真正的选择是完全重写每个控制器?
发布于 2013-08-01 11:46:24
无论出于什么原因,使用@RequestMapping注释都会导致不明确的映射异常。作为解决办法,我决定尝试在REST服务中使用springmvc路由器,这将允许我利用控制器类上的继承,这样我就不必重新实现不按需要在不同版本之间更改的端点。我的解决方案还允许我继续为非REST控制器使用注释映射。
注意事项:我使用Spring3.1,它为处理程序映射提供了与以前版本不同的类。
springmvc-路由器项目将路由器系统从播放框架带到springmvc。在我的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")。
https://stackoverflow.com/questions/17946231
复制相似问题