如何从@RestController返回@RepositoryRestResource样式响应

时间:2018-07-05 16:39:51

标签: spring spring-boot spring-restcontroller spring-rest spring-hateoas

使用@RepositoryRestResource生成路径并为REST API注入所有必要的HATEOAS链接,但是当我使用控制器从存储库返回相同的结果时,JSON结构有所不同,并且没有HATEOAS链接。

如何从控制器返回与RepositoryRestResource生成的路径相同的JSON结构?

// /accounts (RepositoryRestResource JSON structure)
{
    _embedded: {
        accounts: []
    },
    _links: {
        first: {},
        self: {},
        next: {},
        last: {},
        profile: {},
        search: {}
    },
    page: {
    size: 20,
    totalElements: 35,
    totalPages: 2,
    number: 0
    }
}

// /my-accounts (RestController JSON structure)
{
    content: [ ... ], // accounts
    pageable: {},
    totalPages: 1,
    totalElements: 2,
    last: true,
    size: 20,
    number: 0,
    sort: {},
    numberOfElements: 2,
    first: true
}

REST存储库:

@RepositoryRestResource(collectionResourceRel = "accounts", path = "accounts", itemResourceRel = "account")
public interface AccountRepository extends PagingAndSortingRepository<Account, Long> {

    @RestResource(path = "owner", rel = "owner")
    Page<Account> findByOwner(@Param("username") String owner,Pageable p);
}

REST控制器:

@RestController
public class AccountController {

    private AccountRepository repo;

    @Autowired
    public AccountController(AccountRepository repo) {
        this.repo = repo;
    }

    @RequestMapping(
        path = "/my-accounts",
        method = RequestMethod.GET,
        produces = "application/hal+json")
    public ResponseEntity<Page<Account>> getStatus(
        @RequestParam(value = "page", defaultValue = "0", required = false) int page,
        @RequestParam(value = "size", defaultValue = "20", required = false) int size,
        Authentication authentication) {

        String username =  authentication.getName();

        Page<Account> accounts = repo.findByOwner(username, PageRequest.of(page, size));

        return ResponseEntity.ok(accounts);
    }
}

2 个答案:

答案 0 :(得分:1)

基本上,Spring Data REST只是样板代码(例如控制器)的默认实现,人们通常通过REST并使用Spring HATEOAS编写公开的Spring Data存储库,即尝试用您的手写控制器重现完全相同的效果意味着仅自己编写整个Spring Data REST,因此,这是一个坏主意。幸运的是,某些部分很容易复制。

如果您仅谈论将分页链接添加到控制器的输出中(并且实现其他功能,例如搜索控制器,则在示例Spring Data REST控制器输出中存在链接),则可以看一下how Spring Data REST does it。它使用Spring Data的PagedResourcesAssembler,后者接受Page并使用所需的导航链接创建HATEOAS资源。

因此,要添加分页链接,必须在控制器中注入PagedResourcesAssembler实例并使用它:

public ResponseEntity<PagedResources> getStatus(
    @RequestParam(value = "page", defaultValue = "0", required = false) int page,
    @RequestParam(value = "size", defaultValue = "20", required = false) int size,
    Authentication authentication,
    PagedResourcesAssembler assembler) {

    String username =  authentication.getName();

    Page<Account> accounts = repo.findByOwner(username, PageRequest.of(page, size));

    return ResponseEntity.ok(assembler.toResource(accounts));
}

答案 1 :(得分:0)

不确定,但这可以解决问题:

return ResponseEntity.ok(new org.springframework.hateoas.Resource<>(accounts));

如果没有,则可以将帐户包装在扩展ResourceSupport的类中。因此,只需创建一些类AccountSupport extends ResourceSupport并在其中添加所需的链接即可。它有很多实用方法,例如

add(linkTo(AccountController.class).withSelfRel());

或用于指向单个帐户的链接:

add(linkTo(AccountController.class).slash(idOfYourAccountInstance).withSelfRel())