Spring Boot HATEOAS不会自动将链接添加到相关资源

时间:2019-03-10 18:43:04

标签: java spring-boot spring-hateoas hateoas hal

使用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();
    }
}

0 个答案:

没有答案