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