Link API
Link 模組提供 HATEOAS 連結建構功能。
套件: io.leandev.appfuse.web.link
核心類別
LinkBuilder
HATEOAS 連結建構器。
public class LinkBuilder {
static LinkBuilder linkTo(Class<?> controller)
LinkBuilder(Class<?> controller)
LinkBuilder(URIBuilder uriBuilder)
}
主要方法
| 方法 | 說明 |
|---|---|
withContext(String) | 設定 Context 前綴(如 API 版本) |
slash(Object) | 附加路徑片段 |
toUri() | 輸出 URI |
toHref() | 輸出 href 字串 |
withRel(String) | 建立帶 rel 的 Link |
withSelfRel() | 建立 self rel Link |
使用範例
基本用法
String href = LinkBuilder.linkTo(UserController.class)
.slash("users")
.slash(123)
.toHref();
// 結果: "users/123"
使用 Context 前綴
String href = LinkBuilder.linkTo(UserController.class)
.withContext("api/v1")
.slash("users")
.slash(123)
.toHref();
// 結果: "api/v1/users/123"
建立 HATEOAS Link
Link selfLink = LinkBuilder.linkTo(UserController.class)
.withContext("api/v1")
.slash("users")
.slash(user.getId())
.withSelfRel();
// 結果: Link with href="api/v1/users/123" rel="self"
Link ordersLink = LinkBuilder.linkTo(OrderController.class)
.withContext("api/v1")
.slash("users")
.slash(user.getId())
.slash("orders")
.withRel("orders");
// 結果: Link with href="api/v1/users/123/orders" rel="orders"
在 Controller 中使用
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
@GetMapping("/{id}")
public EntityModel<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
EntityModel<User> model = EntityModel.of(user);
model.add(LinkBuilder.linkTo(UserController.class)
.withContext("api/v1")
.slash("users")
.slash(id)
.withSelfRel());
model.add(LinkBuilder.linkTo(OrderController.class)
.withContext("api/v1")
.slash("users")
.slash(id)
.slash("orders")
.withRel("orders"));
return model;
}
}
集合資源連結
@GetMapping
public CollectionModel<EntityModel<User>> getUsers() {
List<EntityModel<User>> users = userService.findAll().stream()
.map(user -> {
EntityModel<User> model = EntityModel.of(user);
model.add(LinkBuilder.linkTo(UserController.class)
.withContext("api/v1")
.slash("users")
.slash(user.getId())
.withSelfRel());
return model;
})
.collect(Collectors.toList());
CollectionModel<EntityModel<User>> collection = CollectionModel.of(users);
collection.add(LinkBuilder.linkTo(UserController.class)
.withContext("api/v1")
.slash("users")
.withSelfRel());
return collection;
}
設計考量
相對路徑
LinkBuilder 產生相對路徑(移除前導斜線),適合 Reverse Proxy 架構:
// 產生相對路徑
LinkBuilder.linkTo(Controller.class)
.withContext("api/v1")
.slash("users")
.toHref();
// 結果: "api/v1/users"(無前導斜線)
與 Spring HATEOAS 整合
LinkBuilder 產生的 Link 物件與 Spring HATEOAS 完全相容:
// 可直接用於 EntityModel、CollectionModel
EntityModel<User> model = EntityModel.of(user);
model.add(LinkBuilder.linkTo(...)
.withSelfRel());
輸出格式
JSON 輸出範例
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"_links": {
"self": {
"href": "api/v1/users/123"
},
"orders": {
"href": "api/v1/users/123/orders"
}
}
}
最佳實踐
- 統一 Context - 使用統一的 API 版本前綴
- 語意化 Rel - 使用有意義的 rel 名稱
- Self Link - 每個資源都應包含 self link
- 相關資源 - 提供相關資源的連結