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. Struts2注解配置之@Namespace(四)

    今天开始学习@Namespace注解. 还是先看一段代码: package com.example.actions; import org.apache.struts2.convention.anno ...

  2. java--关键字和保留字

    关键字:Java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等. 保留字:为java预留的关键字.现在还没用到,但是在升级版本中可能作为关键字. 访问控制:pr ...

  3. bzoj1063

    仔细观察可以发现,这个规划路径很像树链剖分 树链剖分的经典定理:任意一个点到根的所经过轻边不超过logn 而这个规划路径所走公路相当于轻边,也就是说,不便利度不会很大 那么直接dp即可,设f[x,i, ...

  4. LeetCode Letter Combinations of a Phone Number 电话号码组合

    题意:给一个电话号码,要求返回所有在手机上按键的组合,组合必须由键盘上号码的下方的字母组成. 思路:尼玛,一直RE,题意都不说0和1怎么办.DP解决. class Solution { public: ...

  5. 物联网操作系统HelloX应用编程指南

    HelloX操作系统应用编程指南 HelloX应用开发概述 可以通过三种方式,在HelloX操作系统基础上开发应用: 1.        以内部命令方式实现应用,直接编译链接到HelloX的内核she ...

  6. django --------------------- [必要操作]

    基本models 命令: python manage.py validate (验证模型有效性, 记得配置 settings.py - INSTALLED_APPS) python manage.py ...

  7. ffmpeg开发指南

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

  8. zoj 1967 Fiber Network/poj 2570

    题意就是 给你 n个点 m条边 每条边有些公司支持 问 a点到b点的路径有哪些公司可以支持 这里是一条路径中要每段路上都要有该公司支持 才算合格的一个公司// floyd 加 位运算// 将每个字符当 ...

  9. 【转】C++ 智能指针详解

    一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 ...

  10. NumberSeekBar 可任意拖动和自动

    package com.example.numberseekbar; import android.content.Context; import android.content.res.Resour ...