Java 使用Spring实现restapi

Java 使用Spring实现restapi,java,spring,spring-mvc,Java,Spring,Spring Mvc,编写RESTFul api应用程序的最佳实践之一是添加版本控制。例如: http://my-server/api/v1/getData http://my-server/api/v2/getData @RequestMapping(method = RequestMethod.POST, value = "/api/v1/getData") public @ResponseBody ResponseDataDTO getData(@RequestBody OperationsDetailsTD

编写RESTFul api应用程序的最佳实践之一是添加版本控制。例如:

http://my-server/api/v1/getData
http://my-server/api/v2/getData
@RequestMapping(method = RequestMethod.POST, value = "/api/v1/getData")
public @ResponseBody ResponseDataDTO getData(@RequestBody OperationsDetailsTDO details) {...}
我们的应用程序使用Spring框架公开RESTAPI。我们将一个类标记为控制器,使用RequestMapping注释将URL映射到函数,并添加一些转换为json对象或从json对象转换而来的对象

例如:

http://my-server/api/v1/getData
http://my-server/api/v2/getData
@RequestMapping(method = RequestMethod.POST, value = "/api/v1/getData")
public @ResponseBody ResponseDataDTO getData(@RequestBody OperationsDetailsTDO details) {...}
现在,我们想提供API的第二个版本。大约有2/3的功能保持不变,1/3在变化。这些更改同时发生在逻辑和JSON对象中

我想知道如何设计代码。我认为这种代码很难管理:

@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData")
public @ResponseBody ResponseDataDTO createReleaseFromTemplate(@PathVariable("version-var") Integer version, @RequestBody OperationsDetailsTDO details) {
if (version == 1)
{
   doForVersion1();
}
else if (version == 2)
{
   doForVersion2();
}

}
这将很难管理,因为在每个函数中都会有不同的分支。为了说明这个问题,如果我有一个自动生成文档的工具,它将无法理解什么是API

其次,我想知道我应该如何处理绑定到JSON对象的类。我是否需要复制所有这些类以进行微小更改


Thx.

如果您为版本()使用path变量,则可以在RequestMapping中使用正则表达式。或者,您可以创建一个新方法,该方法只调用旧方法,但具有较新的v2请求映射。或者,创建一个通用方法来获取版本并调用实际处理该版本请求的适当方法。最后一种方法的好处是:如果用户发送的版本不受支持,您可以获取该版本并将用户发送到特定错误,例如,如果他们发送/app/v10/whatever。

我同意您将版本作为参数传递,就像

@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData")
但是我不认为增加很多分支是个好主意, 我们应该将资源类中的所有方法提取到业务接口,例如

private IDataRetrieve dataRetriever;
@RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData")
public @ResponseBody ResponseDataDTO createReleaseFromTemplate(@PathVariable("version-var") Integer version, @RequestBody OperationsDetailsTDO details) {
    dataRetiever = DataRetrieverFactory.getDataTrieverByVersion(version);  //TODO, create a factory to get DataRetriever
    return dataRetiever.getData();
}

然后需要两个类来实现IDataRetriver(一个用于V1,另一个用于v2);当然,为了避免重复的代码,您可以为V1和V2添加一个抽象类,并使用Template Patrn删除重复的代码。

毕竟这是一个不同的API。你必须改变使用它的任何东西。+1我只是不太喜欢接口的
I
前缀。客户端不应该知道它正在使用接口或实现。那么JSON对象呢?它们是根据相关类自动生成的。我需要复制这些类吗?我认为我们不需要复制这些类。(“这些类”是指进入/查看类,对吗?)。正如我所想,v1/v2将包含一些业务逻辑,返回应该是相同的。如果v1不支持某些方法,只需抛出异常即可。a)不需要正则表达式。那为什么要用它呢?b) 当api版本数量增加时,到处复制代码将不是很容易管理的。c) 您不能简单地将一个版本转储到另一个版本。客户端正在使用这些api。a)正则表达式可用于帮助匹配请求URL。这就是OP的要求b)没有人说要复制代码。他正在创建一个新的API,同时将旧的API保留在那里。那将是新的代码,对吗?我认为我提到的任何东西都不需要,而且“重复代码”c)没有人说要转储v1。我说“你可以使用regex,或者你可以在你的控制器中为v2使用另一种方法,或者你可以将你的版本更改为path var,有一种方法可以为所请求的版本切换到正确的底层方法”。顺便说一句,我相信我在上一篇文章中的建议与@StonyZhang的建议类似,使用版本作为路径变量来确定要调用的版本。我假设OP使用的是标准的OOP和MVC实践,而“服务层”就在某个地方。