HATEOAS

HATEOAS(The Hypermedia As The Engine Of Application Statue)是REST架构的主要约束。“hepermedia”表示任何包含指向图片、电影、文字等资源的链接,Web是超媒体的经典例子。HATEOAS背后的思想其实非常简单,就是响应中包含指向其它资源的链接。客户端可以利用这些链接和服务器交互。

client不用事先知道服务或者工作流中不同步骤,还有client不用再为不同的资源硬编码URI了。而且服务器还可以在不破坏和客户端交互的情况下,更改URI。

非HATEOAS的响应例子是:

GET /posts/1 HTTP/1.1
Connection: keep-alive
Host: blog.example.com
{
"id" : 1,
"body" : "My first blog post",
"postdate" : "2015-05-30T21:41:12.650Z"
}

而HATEOAS的响应例子则是:

{
"id" : 1,
"body" : "My first blog post",
"postdate" : "2015-05-30T21:41:12.650Z",
"links" : [
{
"rel" : "self",
"href" : http://blog.example.com/posts/1,
"method" : "GET"
}
]
}

上面的例子中,每一个在links中的link都包含了三部分:

href:用户可以用来检索资源或者改变应用状态的URI
rel:描述href指向的资源和现有资源的关系
method:和此URI需要的http方法

在rel中“self”表示了自描述的关系。如果一个资源包含其它资源,那么可以按照下面例子组织:

{
"id" : 1,
"body" : "My first blog post",
"postdate" : "2015-05-30T21:41:12.650Z",
"self" : "http://blog.example.com/posts/1",
"author" : "http://blog.example.com/profile/12345",
"comments" : "http://blog.example.com/posts/1/comments",
"tags" : "http://blog.example.com/posts/1/tags"
}

上面的例子和前一个例子有些不同,没有使用links数组。

JSON Hypermedia Types

JSON媒体类型没有提供原生的超链接语法,所以为了解决这个问题,有几种JSON超媒体类型被创建出来:

• HAL—http://stateless.co/hal_specification.html
• JSON-LD—http://json-ld.org
• Collection+JSON—http://amundsen.com/media-types/collection/
• JSON API—http://jsonapi.org/
• Siren—https://github.com/kevinswiber/siren

HAL是其中最流行的一种,而且被Spring Framework支持。

HAL

HAL(The Hypertext Application Language)是简单的超媒体类型,由Mike Kelly于2011创建。它同时支持XML和JSON格式。HAL媒体类型定义了一种资源,它是状态的容器、links的集合、嵌套资源的集合。如下图所示:

资源状态是用JSON的key/valude形式表达的。如下面所示:

{
"id" : 1,
"body" : "My first blog post",
"postdate" : "2015-05-30T21:41:12.650Z"
}

HAL规范中定义,使用_links包含所有的link。如下面例子所示:

{
"id" : 1,
"body" : "My first blog post",
"postdate" : "2015-05-30T21:41:12.650Z",
"_links" : {
"self": { "href": "http://blog.example.com/posts/1" },
"comments": { "href": "http://blog.example.com/posts/1/comments",
"totalcount" : 20 },
"tags": { "href": "http://blog.example.com/posts/1/tags" }
}
}

在HAL嵌套资源的情况,如下面例子所示:

{
"id" : 1,
"body" : "My first blog post",
"postdate" : "2015-05-30T21:41:12.650Z",
"_links" : {
"self": { "href": "http://blog.example.com/posts/1" },
"comments": { "href": "http://blog.example.com/posts/1/comments",
"totalcount" : 20 },
"tags": { "href": "http://blog.example.com/posts/1/tags" }
},
"_embedded" : {
"author" : {
"_links" : {
"self": { "href": "http://blog.example.com/profile/12345" }
},
"id" : 12345,
"name" : "John Doe",
"displayName" : "JDoe"
}
}
}

HATEOAS in Spring

<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>0.17.0.RELEASE</version>
</dependency>

为了简化超链接的嵌入,Spring HATEOAS提供了org. springframework.hateoas.ResourceSupport,一般应由资源类进行扩展。ResourceSupport类为增加/删除链接提供了重载方法,它也包含了getId方法,此方法返回和资源相关的URI。getId的实现依据了REST的一个准则:一个资源的ID就是它的URI。

下面的例子是在Spring中使用HATEOAS的代码:

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
@RestController
public class PollController {
@RequestMapping(value="/polls", method=RequestMethod.GET)
public ResponseEntity<Iterable<Poll>> getAllPolls() {
Iterable<Poll> allPolls = pollRepository.findAll();
for(Poll p : allPolls) {
updatePollResourceWithLinks(p);
return new ResponseEntity<>(allPolls, HttpStatus.OK);
}
} @RequestMapping(value="/polls/{pollId}", method=RequestMethod.GET)
public ResponseEntity<?> getPoll(@PathVariable Long pollId) {
Poll p = pollRepository.findOne(pollId);
updatePollResourceWithLinks(p);
return new ResponseEntity<> (p, HttpStatus.OK);
} private void updatePollResourceWithLinks(Poll poll) {
poll.add(linkTo(methodOn(PollController.class).getAllPolls()).slash(poll.getPollId()).withSelfRel());
poll.add(linkTo(methodOn(VoteController.class).getAllVotes(poll.getPollId())).withRel("votes"));
poll.add(linkTo(methodOn(ComputeResultController.class).computeResult(poll.getPollId())).withRel("compute-result"));
}
}

下图是上面例子的响应:

Spring REST实践之HATEOAS的更多相关文章

  1. Spring+MyBatis实践—MyBatis数据库访问

    关于spring整合mybatis的工程配置,已经在Spring+MyBatis实践—工程配置中全部详细列出.在此,记录一下几种通过MyBatis访问数据库的方式. 通过sqlSessionTempl ...

  2. Spring MVC 实践 - Component

    Spring MVC 实践 标签 : Java与Web Converter Spring MVC的数据绑定并非没有任何限制, 有案例表明: Spring在如何正确绑定数据方面是杂乱无章的. 比如: S ...

  3. Spring MVC 实践 - Base

    Spring MVC 实践 标签 : Java与Web Spring Web MVC Spring-Web-MVC是一种基于请求驱动的轻量级Web-MVC设计模式框架, Spring MVC使用MVC ...

  4. Spring Boot实践——Spring AOP实现之动态代理

    Spring AOP 介绍 AOP的介绍可以查看 Spring Boot实践——AOP实现 与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改 ...

  5. Spring Boot实践——AOP实现

    借鉴:http://www.cnblogs.com/xrq730/p/4919025.html     https://blog.csdn.net/zhaokejin521/article/detai ...

  6. Spring Boot 实践 :Spring Boot + MyBatis

    Spring Boot 实践系列,Spring Boot + MyBatis . 目的 将 MyBatis 与 Spring Boot 应用程序一起使用来访问数据库. 本次使用的Library spr ...

  7. Spring REST实践之Spring Boot

    Spring Boot基本描述 可以利用http://start.spring.io网站的进行Spring Boot的初始化构建.这个初始化构建器允许你输入工程基本信息.挑选工程支持的功能,最后会生成 ...

  8. Spring Batch实践

    Spring Batch在大型企业中的最佳实践 在大型企业中,由于业务复杂.数据量大.数据格式不同.数据交互格式繁杂,并非所有的操作都能通过交互界面进行处理.而有一些操作需要定期读取大批量的数据,然后 ...

  9. Spring REST实践之REST基本介绍

    REST是什么 REST(REpresentational State Transfer)是一个设计分布式web应用的框架风格,有六个基本原则: Client-Server:应用的参独立与者可分为Cl ...

随机推荐

  1. 启动PL/SQL Developer 报字符编码不一致错误 Database character set (AL32UTF8) and Client character set (ZHS16GBK) are different. Character set conversion may cause unexpected results. Note: you can set the client

    今天写hibernate时候遇到一些异常 代码: 出现异常情况: 出现以上原因是Session关闭 如果不是使用的SessionFactory.getSession()来获得Session. 而是使用 ...

  2. ios tweak之binary not signed (use ldid -S)问题解决

    参考tweak教程写了个简单的tweak,无奈完全无效果,摸索了好长时间才找到方法: 打开terminal ssh root@192.168.1.100 vim /var/log/syslog 找到如 ...

  3. wdcp系统升级mysql5.7.11

    1.下载解压 下载地址为:http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.12-linux-glibc2.5-x86_64.tar.gz ...

  4. WTL汉化版2013.10.15

    汉化内容: 2013.10.15 版本:当前可下载Trunk最新版,wtl-code-467-trunk.zip 汉化内容: 1.应用向导的部分汉化,考虑到部分词汇的表述问题,只汉化无影响部分 2.资 ...

  5. Java [Leetcode 160]Intersection of Two Linked Lists

    题目描述: Write a program to find the node at which the intersection of two singly linked lists begins. ...

  6. Egret应用开发实践(01) Egret与WebPack

    Egret Egret引擎是一款使用TypeScript语言构建的开源免费的移动游戏引擎.Egret仅是纯粹的使用TypeScript语言来开发游戏,开发后可以使用Egret来打包为HTML5网页游戏 ...

  7. system函数的总结

    最近在看APUE第10章中关于system函数的POSIX.1的实现.关于POSIX.1要求system函数忽略SIGINT和SIGQUIT,并且阻塞信号SIGCHLD的论述,理解得不是很透彻,本文就 ...

  8. java web 学习二(Tomcat服务器学习和使用1)

    一.Tomcat服务器端口的配置 Tomcat的所有配置都放在conf文件夹之中,里面的server.xml文件是配置的核心文件. 如果想修改Tomcat服务器的启动端口,则可以在server.xml ...

  9. iOS已发布应用中对异常信息捕获和处理

    iOS已发布应用中对异常信息捕获和处理 iOS开发中我们会遇到程序抛出异常退出的情况,如果是在调试的过程中,异常的信息是一目了然,但是如果是在已经发布的程序中,获取异常的信息有时候是比较困难的. iO ...

  10. Authentication with SignalR and OAuth Bearer Token

    Authentication with SignalR and OAuth Bearer Token Authenticating connections to SignalR is not as e ...