使用HATEOAS来获取资源集合时,不会自动为资源提供链接。
当使用'/ forum / threads'获取ThreadResource的集合时,响应为:
{
"_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();
}
}