天天看点

Java RESTful Web Service实战(第2版) 2.4 连通性

<b>2.4 连通性</b>

rest的一个重要的特性就是连通性。web

link和hateoas以不同方式实现了rest式服务的联通性。

web link定义在ietfrfc 5988(web linking),是通过在http头中定义链接信息,以描述当前页面与链接页面之间的关系。web link是一种过渡型链接(transitional links)。jax-rs 2.0引入了javax.ws.rs.core.link类,用来处理web link的表述。

hateoas(hypermedia as the

engine of application state,超媒体作为应用程序状态引擎)。hateoas的形式是包含链接信息的超媒体文档,hateoas的核心是“引擎”,该引擎的目的是通过请求的响应实体将超媒体信息返回给客户端,超媒体信息可以告诉用户,如果接下来选择去往某个链接(或者链接列表中的某个链接),应用的状态就会如超媒体描述的那样发生转变。hateoas是一种结构型链接(structural links)。jersey2中可以使用xml实现hateoas的结构要求。

下面讲述在jersey中如何实现web link和hateoa这两种rest连通性实践方式。

阅读指南

本节示例源代码地址:https://github.com/feuyeux/jax-rs2-guide-ii/tree/master/2.simple-service-3。

相关包:com.example.link。

<b>2.4.1 过渡型链接</b>

web link通过使用http的头信息来传递操作链接,在jersey中使用javax.ws.rs.core.link类可以非常简洁地实现支持web

link的资源类,示例代码如下。

@path("weblink-resource")

public class weblinkresource {

@context

  uriinfo

uriinfo;

@post

@produces(mediatype.application_xml)

@consumes({ mediatype.application_json,

mediatype.application_xml, mediatype.text_xml })

public response savebook(final book book) {

final long newid = system.nanotime();

book.setbookid(newid);

linkcache.map.put(newid, book);

//关注点1:通过uriinfo实例获取资源路径

final uribuilder ub = uriinfo.getabsolutepathbuilder();

final uri location = ub.path("" + newid).build();

//关注点2:通过模板获取资源路径

final string uritemplate =

"http://{host}:{port}/{path}/{param}";

final uri location2 = uribuilder.fromuri(uritemplate)

.resolvetemplate("host",

"localhost").resolvetemplate("port", "9998")

.resolvetemplate("path", "weblink-resource")

.resolvetemplate("param", newid).build();

//关注点3:通过模板方法获取资源路径

final uribuilder ub3 = uriinfo.getabsolutepathbuilder();

final uri location3 =

ub3.scheme("http").host("localhost").port(9998)

.path("weblink-resource").path("" + newid).build();

//关注点4:为响应实例添加路径信息

return response.created(location).link(location2, "view1")

.link(location3, "view2").entity(book).build();

    }

}

在这段代码中,使用了3种方式构建uri实例。第一种方式是通过调用uriinfo实例的getabsolutepathbuilder()方法可以获取当前请求的绝对路径,然后基于此路径添加资源id信息,见关注点1;第二种方式是为uribuilder提供路径模板,然后链式调用resolvetemplate()方法传递并解析模板参数,最后通过uribuilder的build方法生成uri实例,见关注点2;第三种方式和第二种类似,不同的是模板信息被具体方法替代。最后,这3个与link相关的uri实例由response构建,作为返回值响应给客户端,见关注点4。

<b>2.4.2 结构型链接</b>

hateoas用以代替聚集数据并避免描述膨胀,通常使用

atom格式在实体字段中提供链接信息。本例使用xml格式来支持hateoas,折中的设计是在pojo中额外定义一个链接字段。支持hateoas的资源类示例如下。

@path("hateoas-resource")

public class hateoasresource {

uriinfo uriinfo;

@produces({ mediatype.application_xml })

@consumes({ mediatype.application_xml })

public bookwrapper savebook(final book book) {

      final uri uri = ub.path("" +

newid).build();

bookwrapper b = new bookwrapper();

b.setbook(book);

//关注点2:将资源路径赋给资源实体

b.setlink(uri.tostring());

return b;

  }

在这段代码中,uri实例由上下文uriinfo中获取的绝对路径和资源id组成,见关注点1;该链接信息被赋值到pojo实例的link属性中,以实现hateoas,见关注点2。

rest连通性的实践手段非常多,推荐读者从成熟的产品中学习其设计。如果有可能,这里推荐jenkins和rallydev两个敏捷开发中常用的平台,它们提供了比较舒适的连通性设计。比如在rallydev中,为一个测试用例结果添加测试用例属性(该属性是必输项),其内容并不是对应测试用例的实例,而是该测试用例的引用地址字符串。这样的设计不但减少了网络传输的负载,还方便在调试和维护时排错。