![spring](https://i-blog.csdnimg.cn/blog_migrate/7c5e4c3a45e6340be079693b75780dc6.png)
spring
Spring-hateoas为应用程序提供了一种遵循HATEOAS原理创建基于REST的服务的绝妙方法。
我的目的不是要展示如何创建服务本身,而是要展示如何将客户端写入服务。
我将使用的示例服务是Josh Long( @starbuxman )编写的“ the-spring-rest-stack ”。 我要使用的特定子项目是这里的Hateoas。 如果使用“ mvn jetty”命令运行此子项目,则可以在http:// localhost:8080 / users / 2上找到基于REST的端点以列出用户的详细信息,其中“ 2”是用户的ID,并给出一个以下结构的结果:
{
"links": [{
"rel": "self",
"href": "http://localhost:8080/users/2"
}, {
"rel": "customers",
"href": "http://localhost:8080/users/2/customers"
}, {
"rel": "photo",
"href": "http://localhost:8080/users/2/photo"
}],
"id": 2,
"firstName": "Lois",
"profilePhotoMediaType": null,
"lastName": "Lane",
"username": "loislane",
"password": null,
"profilePhotoImported": false,
"enabled": true,
"signupDate": 1370201631000
}
为了获得该用户的特定客户,端点位于http:// localhost:8080 / users / 2 / customers / 17,它提供以下结构的输出:
{
"links": [{
"rel": "self",
"href": "http://localhost:8080/users/2/customers/17"
}, {
"rel": "user",
"href": "http://localhost:8080/users/2"
}],
"id": 17,
"signupDate": 1372461079000,
"firstName": "Scott",
"lastName": "Andrews",
"databaseId": 17
}
现在,对于这两项服务的使用者而言,结果可以由Spring-hateoas项目中称为Resource的Java类型表示,并且是具有以下签名的泛型类:
public class Resource<T> extends ResourceSupport {
protected Resource() {
this.content = null;
}
public Resource(T content, Link... links) {
this(content, Arrays.asList(links));
}
...
因此,以上两种服务的使用者将获得以下两种类型:
Resource<User> user = .... //call to the service
Resource<Customer> customer = ... //call to the service
现在的问题是,由于上面的“用户”和“客户”是参数化类型,如果我要使用杰克逊作为json处理器来绑定这些类型,我将按照以下方式进行操作:
ObjectMapper objectMapper = new ObjectMapper();
Resource<Customer> customer = objectMapper.readValue(customerAsJson, Resource.class);
Resource<User> user = objectMapper.readValue(userAsJson, Resource.class);
上面的方法不起作用,原因是由于Java类型擦除导致参数化Resource的类型信息丢失,Jackson不知道创建Resource <User>或Resource <Customer>的实例
解决方法是使用超类型令牌,这实质上是一种提供像杰克逊库类型的信息和我以前的博客上讲述它在这里。 这样,将json映射到适当的参数化类型的工作代码将如下所示:
ObjectMapper objectMapper = new ObjectMapper();
Resource<Customer> customer = objectMapper.readValue(customerAsJson, new TypeReference<Resource<Customer>>() {});
Resource<User> customer = objectMapper.readValue(userAsJson, new TypeReference<Resource<User>>() {});
Spring处理基于Rest的服务的客户端抽象是RestTemplate ,它可以使用称为HttpMessageConverter的抽象处理各种消息格式(xml,json,atom等),以处理每种消息格式的绑定细节。
Spring RestTemplate提供了自己的Super Type令牌实现,以便能够按照Jackson的TypeReference的路线将不同的消息格式绑定到参数化类型,这被称为ParameterizedTypeReference 。
ParameterizedTypeReference可用于通过以下方式将用户和客户的Rest响应完全绑定到Java类型:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Resource<User>> responseEntity =
restTemplate.exchange("http://localhost:8080/users/2", HttpMethod.GET, null, new ParameterizedTypeReference<Resource<User>>() {}, Collections.emptyMap());
if (responseEntity.getStatusCode() == HttpStatus.OK) {
Resource<User> userResource = responseEntity.getBody();
User user = userResource.getContent();
}
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Resource<Customer>> responseEntity =
restTemplate.exchange("http://localhost:8080/users/2/customers/17", HttpMethod.GET, null, new ParameterizedTypeReference<Resource<Customer>>() {}, Collections.emptyMap());
if (responseEntity.getStatusCode() == HttpStatus.OK) {
Resource<Customer> customerResource = responseEntity.getBody();
Customer customer = customerResource.getContent();
}
总之,ParameterizedTypeReference提供了一种处理参数化类型的巧妙方法,在使用基于Spring Hateoas的REST服务时非常有用。
spring