![](/img/trans.png)
[英]Spring HATEOAS ControllerLinkBuilder with methodOn
[英]Spring Hateoas ControllerLinkBuilder adds null fields
我正在關注Spring REST的教程,並試圖將HATEOAS鏈接添加到我的Controller結果中。
我有一個簡單的User類和一個CRUD控制器。
class User {
private int id;
private String name;
private LocalDate birthdate;
// and getters/setters
}
服務:
@Component
class UserService {
private static List<User> users = new ArrayList<>();
List<User> findAll() {
return Collections.unmodifiableList(users);
}
public Optional<User> findById(int id) {
return users.stream().filter(u -> u.getId() == id).findFirst();
}
// and add and delete methods of course, but not important here
}
一切正常,除了我的控制器,我想從所有用戶列表添加鏈接到單個用戶:
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public List<Resource<User>> getAllUsers() {
List<Resource<User>> userResources = userService.findAll().stream()
.map(u -> new Resource<>(u, linkToSingleUser(u)))
.collect(Collectors.toList());
return userResources;
}
Link linkToSingleUser(User user) {
return linkTo(methodOn(UserController.class)
.getById(user.getId()))
.withSelfRel();
}
這樣,對於結果列表中的每個用戶,都會添加一個指向用戶自身的鏈接。
鏈接本身創建正常,但生成的JSON中有多余的條目:
[
{
"id": 1,
"name": "Adam",
"birthdate": "2018-04-02",
"links": [
{
"rel": "self",
"href": "http://localhost:8080/users/1",
"hreflang": null,
"media": null,
"title": null,
"type": null,
"deprecation": null
}
]
}
]
具有空值( hreflang
, media
等)的字段來自哪里,為什么會添加它們? 有辦法擺脫它們嗎?
在構建指向所有用戶列表的鏈接時,它們不會出現:
@GetMapping("/users/{id}")
public Resource<User> getById(@PathVariable("id") int id) {
final User user = userService.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
Link linkToAll = linkTo(methodOn(UserController.class)
.getAllUsers())
.withRel("all-users");
return new Resource<User>(user, linkToAll);
}
為了進一步參考,以防其他人偶然發現這一點,我想出來了:我在application.properties
添加了一個條目,即
spring.jackson.default-property-inclusion=NON_NULL
為什么這對於Link
對象是必要的,但對於我不知道的User
卻是如此(並且沒有更深入地傾斜)。
根據Spring HATEOAS#493 “由於您的頂級結構不是有效的HAL結構,因此繞過了HAL序列化器。”
解決問題的用法:
return new Resources<>(assembler.toResources(sourceList));
這將在Spring HATEOAS的未來版本中得到解決,其中toResources(Iterable <>)返回Resources或使用SimpleResourceAssembler 。
正如semiintel所提到的,問題是List返回對象不是有效的HAL類型:
public List<Resource<User>> getAllUsers()
這可以通過將返回類型更改為Resources來輕松解決,如下所示:
public Resources<Resource<User>> getAllUsers()
然后,您可以通過更改return語句,將Resource <> List簡單地包裝在Resources <>對象中:
return userResources;
至:
return new Resources<>(userResources)
然后,您應該像對待單個對象一樣獲得正確的鏈接序列化。
這個方法是對這個非常有用的解決這個問題的文章的禮貌:
https://www.logicbig.com/tutorials/spring-framework/spring-hateoas/multiple-link-relations.html
要避免鏈接中的其他屬性為"hreflang": null, "media": null, "title": null, ...
,我構建了一個包裝類,如:
@JsonInclude(JsonInclude.Include.NON_NULL)
public class WsDtoLink extends Link {
public WsDtoLink(Link link) {
super(link.getHref(), link.getRel());
}
}
然后我擴展了org.springframework.hateoas.Resource
以覆蓋add(Link link)
:
public class WsDtoResource<T extends WsDto> extends Resource<T> {
@Override
public void add(Link link) {
super.add(new WsDtoLink(link));
}
}
然后我擴展了org.springframework.data.web.PagedResourcesAssembler
以修復分頁鏈接,如下所示:
public class WsDtoPagedResourceAssembler<T> extends PagedResourcesAssembler<T> {
public WsDtoPagedResourceAssembler(HateoasPageableHandlerMethodArgumentResolver resolver, UriComponents baseUri) {
super(resolver, baseUri);
}
@Override
public PagedResources<Resource<T>> toResource(Page<T> page, Link selfLink) {
PagedResources<Resource<T>> resources = super.toResource(page, new WsDtoLink(selfLink));
exchangeLinks(resources);
return resources;
}
@Override
public <R extends ResourceSupport> PagedResources<R> toResource(Page<T> page, ResourceAssembler<T, R> assembler, Link link) {
PagedResources<R> resources = super.toResource(page, assembler, new WsDtoLink(link));
exchangeLinks(resources);
return resources;
}
@Override
public PagedResources<?> toEmptyResource(Page<?> page, Class<?> type, Link link) {
PagedResources<?> resources = super.toEmptyResource(page, type, new WsDtoLink(link));
exchangeLinks(resources);
return resources;
}
private void exchangeLinks(PagedResources<?> resources) {
List<Link> temp = new ArrayList<>(resources.getLinks()).stream()
.map(WsDtoLink::new)
.collect(Collectors.toList());
resources.removeLinks();
resources.add(temp);
}
}
但更好的解決方案是生成正確的媒體類型org.springframework.hateoas.MediaTypes.HAL_JSON_VALUE
。 在我的情況下,我們生成了org.springframework.http.MediaType.APPLICATION_JSON_VALUE
,這是不正確的,但如果我們之后更改它會破壞客戶端。
在您的pom中添加此依賴項。 請訪問此鏈接: https : //www.baeldung.com/spring-rest-hal
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-hal-browser</artifactId>
</dependency>
它會像這樣改變你的反應。
"_links": {
"next": {
"href": "http://localhost:8082/mbill/user/listUser?extra=ok&page=11"
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.