spring - 使用与 Spring MVC 的内容协商进行 REST API 版本控制

标签 spring rest spring-mvc

我正在尝试使用内容协商来实现 API 版本控制,因为将版本放入 URI 不是 RESTful。 Spring MVC 似乎不可能,因为在解析 Controller 方法时不考虑 @RequestMapping 的消耗/生产属性,只考虑路径。为了便于讨论,假设我有这个 Controller

@RestController
@RequestMapping(path = "/foo")
public class FooController {
    @RequestMapping(path = "{id}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
    @ResponseBody
    public Foo getFoo(@PathVariable Long id) {
        return repository.findOne(id);
    }

    @RequestMapping(path = "{id}", method = RequestMethod.GET, produces = { "application/vnd.com.me.model.v1+json" })
    @ResponseBody
    public FooV1 getFooV1(@PathVariable Long id) {
        return repositoryV1.findOne(id);
    }
    ...
}

REST API 是“GET/foo/1”或“GET/foo/2”等,但我希望能够发送任何一个

Accept: application/json

Accept: application/vnd.com.me.model.v1+json

并让它转到正确的 Controller 方法。忽略如何最好地表示模型的问题。这只是让 Spring MVC 让我有一个单一的 REST URI 来处理不同的内容类型。这显然也适用于其他 HTTP 方法,PUT、POST 等。鉴于上面的 Controller 定义,当 Spring 尝试解析映射时,您会收到一个错误,“抱歉,已经有 '/foo/{id}' 的映射。”

我是否错过了可以让我实现这一目标的东西?

最佳答案

这绝对应该像您描述的那样工作。我这里有一个工作示例:

@RestController
@RequestMapping(path = "/persons")
public class PersonController {

    private final PersonV1Repository personV1Repository;
    private final PersonV2Repository personV2Repository;

    @Autowired
    public PersonController(PersonV1Repository personV1Repository, PersonV2Repository personV2Repository) {
        this.personV1Repository = personV1Repository;
        this.personV2Repository = personV2Repository;
    }

    @RequestMapping(produces = "application/vnd.com.me.model.v1+json")
    public ResponseEntity<List<PersonV1>> getPersonsV1() {
        return ResponseEntity.ok(personV1Repository.findAll());
    }

    @RequestMapping(path = "/{id}", produces = "application/vnd.com.me.model.v1+json")
    public ResponseEntity<PersonV1> getPersonV1(@PathVariable Long id) {
        return ResponseEntity.ok(personV1Repository.findOne(id));
    }

    @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<PersonV2>> getPersonsV2() {
        return ResponseEntity.ok(personV2Repository.findAll());
    }

    @RequestMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<PersonV2> getPersonV2(@PathVariable Long id) {
        return ResponseEntity.ok(personV2Repository.findOne(id));
    }
}

我使用 Accept header 获取我选择的版本 - 以下是示例请求和响应:

http :8080/persons/2 Accept:application/vnd.com.me.model.v1+json -v
GET /persons/2 HTTP/1.1
Accept: application/vnd.com.me.model.v1+json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8080
User-Agent: HTTPie/0.9.2



HTTP/1.1 200 OK
Content-Type: application/vnd.com.me.model.v1+json;charset=UTF-8
Date: Mon, 07 Dec 2015 20:14:26 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application

{
    "firstname": "some",
    "id": 2,
    "lastname": "other"
}

并获取默认版本:

http :8080/persons/2 Accept:application/json -v
GET /persons/2 HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8080
User-Agent: HTTPie/0.9.2



HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Date: Mon, 07 Dec 2015 20:16:20 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application

{
    "id": 2,
    "name": "some"
}

您的 Controller 中必须有一些其他重复映射 - 您可以添加完整的 Controller 代码以进行进一步调查。

关于spring - 使用与 Spring MVC 的内容协商进行 REST API 版本控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34140857/

相关文章:

java - 如何使 Java Web 应用程序完全无状态

java - 如何在运行时修改 Web 应用程序中的属性文件?

java - Spring 实用程序 :map injection

java - 结合JBehave和SpringJUnit4ClassRunner实现事务回滚

java - 如何使用 spring 框架检查启动和停止?

web-services - 发现 REST Web 服务的参数

rest - 在 REST API 中使 PUT 创建请求幂等

java - 为什么Spring MVC会以404响应并报告“在DispatcherServlet中未找到带有URI […]的HTTP请求的映射”?

jquery - 将文件从java服务器发送到客户端的最佳方式

spring - Primefaces fileUpload 不起作用,FileUploadFilter 调用两次