【发布时间】:2013-06-20 07:14:39
【问题描述】:
几乎所有 API 都在处理不同的发布版本。您经常会看到这种版本控制:
但我还没有找到说明如何在 Spring 堆栈中组织它们的源代码。我猜想在每个控制器上都有一个 /v1 前缀,如 @RequestMapping("/v1/questions") 并不是最好的方法。
想象一下,只有当前版本(在我们的例子中是 V2)有一个 @Service 层。
我们的 Service 应该处理 V1 和 V2 的请求。唯一的变化是 V2 在问题实体上添加了一个新字段(这意味着 V1 问题可以轻松转换为 V2 问题)。
现在的问题是:
- 如何从java包的角度组织不同的
~.web.* @Controller? - 如何注释不同的
~.web.* @Controller,他们知道他们的版本?以RequestMapping的方式?或者是否可以在 V1 java 包中使用 context:component-scan 配置它们? - 如何组织转换器?放在哪里,如何命名?嗯。比如 QuestionsV1ToV2 控制器?
- 是否需要 DTO 层?因为我们的域必须同时处理多个版本?
一个例子可能是这样的(我到处都添加了包):
// on V1 Question look like this:
public class project.domain.Question
{
private String question;
}
// on v2 Question looks like this:
public class project.domain.Question
{
private String question;
private Date creationDate;
}
@Service
public class project.service.QuestionService
{
public long create(Question q) {...};
public Question read(long id) {...};
public void remove(long id) {...};
public void update(Question qd) {...};
}
@Controller
@RequestMapping("/v2/question")
public class project.web.v2.QuestionController
{
@Autowired
project.service.QuestionService questionService;
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public long create(Question q)
{
return questionService.create(q);
}
}
@Controller
@RequestMapping("/v1/question")
public class project.web.v1.QuestionController
{
@Autowired
project.service.QuestionService questionService;
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public long create(Question q)
{
// this will not work, because the v1 haven't had the 'creationDate' field.
return questionService.create(q);
}
}
【问题讨论】:
-
我会根据需要代理从 v1 到 v2 的请求。
-
@soulcheck 你的意思是你有每个版本的专用控制器。那些控制器使用旧实体(或 DTO),而不是直接访问服务(就像我正在做的那样)你调用 V2 控制器,对吗?
-
是的。您在失去一些性能的同时获得了很大的灵活性,但在这种情况下,我认为这是值得的。
-
你甚至可以有一个单独的 servlet 甚至是 web 应用程序为 v1 api 提供服务,并代理到 v2
标签: java spring rest spring-mvc spring-ws