这里的问题不是关于版本信息所在的位置(URI 与标头),而是更多关于如何组织不同版本的代码。
我怀疑是否存在单一标准方法。这仅取决于版本的差异程度。
简单的格式更改。例如,假设唯一的区别是您从 V1 中的 XML 迁移到 V2 中的 JSON。在这种情况下,您可以使用完全相同的代码,但只需将应用程序配置为全局输出 JSON 即可。不需要不同的包或控制器。 (例如,您可以使用 JAXB 注释来驱动 XML 和 Jackson 生成的 JSON 输出。)
适度的架构更改。假设 V2 引入了少量破坏性架构更改。在这种情况下,在其上创建新包可能没有意义。您的控制器中可能只有简单的条件逻辑来处理/提供版本的正确表示。
主要架构更改。如果您的架构更改很深且范围很广,您可能需要的不仅仅是单独的控制器。您甚至可能需要不同的域模型(实体/服务)。在这种情况下,为控制器提供一组并行的包,一直到实体、存储库甚至数据库表可能是有意义的。
应用这些想法
方法一。将这些想法应用到你的@RequestMapping
例如,您可以按照您所说的进行操作,但如果版本之间的响应完全相同,那么它们应该委托给单个共享方法:
@RequestMapping(
value = "/orders/{id}",
method = RequestMethod.GET,
produces = "application/vnd.example-v1")
@ResponseBody
public Order getOrderV1(@PathVariable("id") Long id) {
return getOrder(id);
}
@RequestMapping(
value = "/orders/{id}",
method = RequestMethod.GET,
produces = "application/vnd.example-v2")
@ResponseBody
public Order getOrderV2(@PathVariable("id") Long id) {
return getOrder(id);
}
private Order getOrder(Long id) {
return orderRepo.findOne(id);
}
类似的东西会起作用。如果版本之间的顺序不同,那么您可以直接在方法中实现差异。
方法2。您可能会尝试的另一件事(我自己没有尝试过)是每种资源类型(例如订单、产品、客户等)都有自己的基本控制器,其中带有 HTTP 方法的方法级注释(仅value
and method
已定义,但未定义produces
)。然后使用特定于版本的扩展来扩展基础,其中扩展控制器具有@RequestMapping(value = "/orders", produces = "application/vnd.example-v1")
在班级层面。然后仅覆盖版本和基线之间的增量。我不确定这是否有效但如果是这样的话,这将是一种非常干净的组织控制器的方式。这就是我的意思:
// The baseline
public abstract class BaseOrderController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public Order getOrder(@PathVariable("id") Long id) { ... }
}
// V1 controller
@RequestMapping(value = "/orders", produces = "application/vnd.example-v1")
public class OrderControllerV1 extends BaseOrderController {
... no difference from baseline, so nothing to implement ...
}
// V2 controller
@RequestMapping(value = "/orders", produces = "application/vnd.example-v2")
public class OrderControllerV2 extends BaseOrderController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
@Override
public Order getOrder(@PathVariable("id") Long id) {
return orderRepoV2.findOne(id);
}
}