Ссылки на ресурсы не предоставляются автоматически при использовании HATEOAS для извлечения коллекций ресурсов.
При получении коллекции ThreadResource с помощью '/forum/threads' ответ будет таким:
{
"_embedded": {
"threadList": [
{
"posts": [
{
"postText": "This text represents a major breakthrough in textual technology.",
"thread": null,
"comments": [],
"thisId": 1
},
{
"postText": "This text represents a major breakthrough in textual technology.",
"thread": null,
"comments": [],
"thisId": 2
}
],
"createdBy": "admin",
"updatedBy": null,
"thisId": 1
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/forum/threads?page=0&size=10"
}
},
"page": {
"size": 10,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}Я ожидал массив сообщений JSON (вместо ссылок на связанную коллекцию сообщений), как показано ниже:
{
"_embedded": {
"threadList": [
{
"createdBy": "admin",
"updatedBy": null,
"thisId": 1,
"_links": {
"posts": {
"href": "http://localhost:8080/forum/threads/1/posts"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/forum/threads?page=0&size=10"
}
},
"page": {
"size": 10,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}Я мог бы вручную создавать и добавлять ссылки в классах реализации ResourceProcessor и исключать отображение коллекции с помощью @JsonIgnore, но раньше мне никогда не приходилось этого делать. Что я делаю неправильно?
Соответствующие классы представлены ниже. Заранее спасибо!
@Entity
public class Thread {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany
private List<Post> posts;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_by")
private String updatedBy;
public Thread() { }
@PrePersist
public void prePersist() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
posts = new ArrayList<>();
createdBy = auth.getName();
}
@PreUpdate
public void preUpdate() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
updatedBy = auth.getName();
}
public void submitPost(Post newPost) {
posts.add(newPost);
}
public Long getThisId() {
return id;
}
public List<Post> getPosts() {
return posts;
}
public void setPosts(List<Post> posts) {
this.posts = posts;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public String getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(String updatedBy) {
this.updatedBy = updatedBy;
}@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String postText;
@ManyToOne(fetch = FetchType.LAZY)
private Thread thread;
@OneToMany
private List<Comment> comments;
public Post() { }
}public class ThreadResource extends ResourceSupport {
private List<PostResource> postResources;
private String createdBy;
private String updatedBy;
public ThreadResource() {
}
}public class PostResource extends ResourceSupport {
private String postText;
private ThreadResource threadResource;
private List<CommentResource> commentResources;
public PostResource() { }@Component
public class PostResourceAssembler extends ResourceAssemblerSupport<Post, PostResource> {
public PostResourceAssembler() {
super(PostController.class, PostResource.class);
}
@Override
public PostResource toResource(Post entity) {
PostResource resource = super.createResourceWithId(entity.getThisId(), entity);
resource.setPostText(entity.getPostText());
return resource;
}
}@Component
public class ThreadResourceAssembler extends ResourceAssemblerSupport<Thread, ThreadResource> {
private PostResourceAssembler postResourceAssembler;
public ThreadResourceAssembler(PostResourceAssembler postResourceAssembler) {
super(ThreadController.class, ThreadResource.class);
this.postResourceAssembler = postResourceAssembler;
}
@Override
public ThreadResource toResource(Thread entity) {
ThreadResource resource = super.createResourceWithId(entity.getThisId(), entity);
List<Post> posts = entity.getPosts();
List<PostResource> postResources = new ArrayList<>();
posts.forEach((post) -> postResources.add(postResourceAssembler.toResource(post)));
resource.setPostResources(postResources);
return resource;
}
}@RestController
public class PostController {
private PostService postService;
@Autowired
public PostController(PostService postService) {
this.postService = postService;
}
@GetMapping("/forum/threads/{threadId}/posts/{postId}")
public ResponseEntity<Resource<Post>> getPost(@PathVariable long threadId, @PathVariable long postId) {
Post post = postService.fetchPost(postId)
.orElseThrow(() -> new EntityNotFoundException("not found thread " + postId));
Link selfLink = linkTo(PostController.class).slash(postId).withSelfRel();
post.add(selfLink);
return ResponseEntity.ok(new Resource<>(post));
}
@GetMapping
public ResponseEntity<PagedResources<Resource<Post>>> getPosts(PagedResourcesAssembler<Post> pagedResourcesAssembler) {
Pageable pageable = new PageRequest(0, 10);
Page<Post> posts = postService.fetchAllPosts(pageable);
PagedResources<Resource<Post>> resources = pagedResourcesAssembler.toResource(posts);
return ResponseEntity.ok(resources);
}
@PostMapping("/forum/threads/{threadId}/posts")
public HttpEntity<?> submitPost(@PathVariable long threadId) throws URISyntaxException {
Post post = postService.submitPost(threadId, new Post());
if (post != null) {
Link selfLink = linkTo(methodOn(PostController.class).submitPost(threadId)).slash(post.getThisId()).withSelfRel();
post.add(selfLink);
return ResponseEntity.created(new URI(selfLink.getHref())).build();
}
return ResponseEntity.status(500).build();
}
}@RestController
public class ThreadController {
private ThreadService threadService;
private ThreadResourceAssembler threadResourceAssembler;
@Autowired
public ThreadController(ThreadService threadService,
ThreadResourceAssembler threadResourceAssembler) {
this.threadService = threadService;
this.threadResourceAssembler = threadResourceAssembler;
}
@GetMapping("/forum/threads/{threadId}")
public ResponseEntity<ThreadResource> getThread(@PathVariable long threadId) {
Thread thread = threadService.fetchThread(threadId)
.orElseThrow(() -> new EntityNotFoundException("not found thread " + threadId));
ThreadResource threadResource = threadResourceAssembler.toResource(thread);
return ResponseEntity.ok(threadResource);
}
@GetMapping("/forum/threads")
public ResponseEntity<PagedResources<Resource<ThreadResource>>> getThreads(PagedResourcesAssembler pagedResourcesAssembler) {
Pageable pageable = new PageRequest(0, 10);
Page<Thread> threads = threadService.fetchAllThreads(pageable);
PagedResources pagedResources = pagedResourcesAssembler.toResource(threads);
return ResponseEntity.ok(pagedResources);
}
@PostMapping("/forum/threads")
public HttpEntity<?> createThread() {
Thread thread = threadService.createThread();
return ResponseEntity.ok(thread);
}
@DeleteMapping("/forum/threads/{threadId}")
public HttpEntity<?> deleteThread(@PathVariable long threadId) {
Thread thread = threadService.fetchThread(threadId)
.orElseThrow(() -> new EntityNotFoundException("not found thread" + threadId));
threadService.closeThread(thread);
return ResponseEntity.ok().build();
}
}Это правда, да, потому что на данном этапе мне не нужны пользовательские ссылки. В прошлом я разрешал весенней загрузке создавать для меня ссылки на связанные ресурсы. По какой-то причине я не могу заставить его работать сейчас. У меня возникает соблазн просто добавить их вручную, но я не должен этого делать.
Поведение, которое вы получили, абсолютно нормальное, вы добавляете список PostResource внутри своего ThreadResource класса; что означает, что он будет вычисляться при создании вашего списка threadResources. Если вы хотите, чтобы внутри threadList размещались только ссылки, вы должны добавить их вручную.
взгляните на этот сообщение
Привет, спасибо, я уже погуглил и увидел этот пост. Я думаю, когда аннотация @RepositoryRestController была доступна (может быть, в весенней загрузке 1? В любом случае, сейчас она недоступна), многие ссылки можно было сгенерировать автоматически. В этом была магия. Спасибо, в любом случае.




Я не видел создания ссылок в вашем коде при возврате ресурсов!