Spring HATEOAS

一.简介

        Spring HATEOAS的目标是解决两个问题:link creation(创建链接)及representation assembly(集合表述)。

二.创建链接

        HATEOAS的核心是链接。链接的存在使得客户端可以动态发现其所能执行的动作。

HATEOAS生成链接的几种方式:

① 静态生成链接

        Spring HATEOAS使用 org.springframework.hateoas.Link 类来表示链接。可以继承自 Spring HATEOAS 提供的 org.springframework.hateoas.Resource 类,Resource 类提供了简单的方式来创建链接。

Eg:

Link link1 = new Link("http://localhost:8080/something");

② 动态生成链接

        在创建资源的链接时,指向单个资源的链接的href属性值是类似“http://localhost:8080/lists/1”这样的格式。而其中的“/lists”不应该是硬编码的,否则当修改了 ListRestController 类的“@RequestMapping”时,所有相关的生成链接的代码都需要进行修改。Spring HATEOAS 提供了 org.springframework.hateoas.mvc.ControllerLinkBuilder 来解决这个问题,用来根据 Spring MVC 控制器动态生成链接。

Eg:

//通过slash方法找到下一级,生成自身链接

Link link = linkTo(PersonController.class).slash(person.getId()).withSelfRel();

//如果实体类实现Identifiable接口

Link link = linkTo(PersonController.class).slash(person).withSelfRel();

//通过指定类的方法,生成rel为"items"的链接

Link link = linkTo(methodOn(ItemRestController.class).readItems(listId)).withRel("items");

③ 通过实体类创建单个链接

        首先需要添加Maven依赖,此外还需要在控制器类中通过“@ExposesResourceFor”注解声明其所暴露的模型类,另外在 Spring 应用的配置类中需要通过“@EnableEntityLinks”注解来启用 EntityLinks 功能。

Eg:

<dependency>

 <groupId>org.springframework.plugin</groupId>

 <artifactId>spring-plugin-core</artifactId>

 <version>1.1.0.RELEASE</version>

</dependency>


@RestController

@ExposesResourceFor(List.class)

@RequestMapping("/lists")

public class ListRestController {

@Autowired

private EntityLinks entityLinks;

entityLinks.linkForSingleResource(List.class, 1)  

}

        需要注意的是,为了linkForSingleResource方法可以正常工作,控制器类中需要包含访问单个资源的方法,而且其“@RequestMapping”是类似“/{id}”这样的形式。

④Model—>ModelResource

        继承ResourceAssemblerSupport类,并根据ModelRestController与ModelResource进行相应配置。

//组装单个资源对象

new ModelResourceAssembler().toResource(model);

//组装资源对象的集合

Resources<ModelResource> resources = new Resources<ModelResource>(new ModelResourceAssembler().toResources(models));

二.集合表述

①Resource资源

        继承Resource类,在ModelResource类中可以根据实体参数进行自定义封装,并向ModelResource中添加自定义链接。

Eg:

public class ChartResource extends Resource {    public ChartResource(Chart chart) throws Exception {        super(chart);        Long chartId = chart.getId();         add(linkTo(methodOn(ChartRestController.class).getDimensions(chartId)).withRel("dimensions"));//维度         add(linkTo(methodOn(ChartRestController.class).getConditions(1)).withRel("conditions"));//条件    }}

结果如下:

"id": 1,

"title": "房价监管",

"_links": {

"dimensions": {"href": "http://localhost:8088/charts/1/dimensions"}, "conditions": {"href": "http://localhost:8088/charts/1/conditions"}, "self": {"href": "http://localhost:8088/charts/1"}

}

②_embedded子集合

        首先是内嵌资源在_embedded对应的哈希对象中的属性值,该属性值是由 org.springframework.hateoas.RelProvider 接口的实现来提供的。对于应用来说,只需要在内嵌资源对应的模型类中添加 org.springframework.hateoas.core.Relation 注解即可.

@Relation(value = "list", collectionRelation = "lists")

public class List extends AbstractEntity {

}

CurieProvider API

        使用URL作为链接的关系带来的问题是 URL 作为属性名称来说显得过长,而且不同关系的 URL 的大部分内容是重复的。为了解决这个问题,可以使用 Curie。简单来说,Curie 可以作为链接关系 URL 的模板。链接的关系声明时使用 Curie 的名称作为前缀,不用提供完整的 URL。应用中声明的 Curie 出现在_links 属性中。

@Bean

public CurieProvider curieProvider() {

return new DefaultCurieProvider("todo",

new UriTemplate("http://www.midgetontoes.com/todolist/rels/{rel}"));

}

注意:CurieProvider每个应用程序范围只能定义一个bean

获取链接属性:

String content = "{'_links' :  { 'foo' : { 'href' : '/foo/bar' }}}";

LinkDiscoverer discoverer = new HalLinkDiscoverer();

Link link = discoverer.findLinkWithRel("foo", content);

assertThat(link.getRel(), is("foo"));

assertThat(link.getHref(), is("/foo/bar"));

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容