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. bzoj3551 3545

    我直接来讲在线好了 这是一个很巧妙的方法,把边作为一个点 做一遍最小生成树,当加如一条边时,我们把这条边两点x,y的并查集的根i,j的父亲都设为这条边代表的点k,由k向i,j连边 这样我们就构建出一棵 ...

  2. Spring MVC 的请求参数获取的几种方法

    通过@PathVariabl注解获取路径中传递参数 @RequestMapping(value = "/{id}/{str}") public ModelAndView hello ...

  3. Firefox和Chrome浏览器导出书签

    Chrome浏览器: 或者直接在地址栏中输入:“chrome://bookmarks/#1”也可以 Firefox浏览器:

  4. CodeForces Round #296 Div.2

    A. Playing with Paper 如果a是b的整数倍,那么将得到a/b个正方形,否则的话还会另外得到一个(b, a%b)的长方形. 时间复杂度和欧几里得算法一样. #include < ...

  5. ffmpeg开发指南

    FFmpeg是一个集录制.转换.音/视频编码解码功能为一体的完整的开源解决方案.FFmpeg的开发是基于Linux操作系统,但是可以在大多数操作系统中编译和使用.FFmpeg支持MPEG.DivX.M ...

  6. Oracle中如何判断一个字符串是否含有汉字

    看到网友问,怎么查询表中某个字段数据是不是包含了全角字符啊? 这个问题涉及到几个函数:to_single_byte.length和lengthb,我之前做开发的时候研究的是如何判断一个字符串中是否包含 ...

  7. web项目Log4j日志输出路径配置问题

    问题描述:一个web项目想在一个tomcat下运行多个实例(通过修改war包名称的实现),然后每个实例都将日志输出到tomcat的logs目录下实例名命名的文件夹下进行区分查看每个实例日志,要求通过尽 ...

  8. TCP/IP详解学习笔记(1)-基本概念

    为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣经中上帝打乱了各地人的口音,让他们无法合作一样 ...

  9. K2 blackpearl 流程开发(一)

    转:http://blog.csdn.net/gxiangzi/article/details/8444060 郁闷,今天K2的license过期了,很多东西都没法用了,还得去找PM大大帮忙申请一个. ...

  10. SQL2012远程连接到SQL2008时的问题:已成功与服务器建立连接,但在登陆过程中发生错误。

    服务器装的是2008,我机上装的是2012,结果一远程连接马上报错而且2012直接crash了.后来找到这位兄弟的帖子,http://www.cnblogs.com/liuguozhu2015/p/3 ...