天天看點

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中,為一個測試用例結果添加測試用例屬性(該屬性是必輸項),其内容并不是對應測試用例的執行個體,而是該測試用例的引用位址字元串。這樣的設計不但減少了網絡傳輸的負載,還友善在調試和維護時排錯。