如何从Spring数据正确使用PagedResourcesAssembler?

如何从Spring数据正确使用PagedResourcesAssembler?,spring,spring-mvc,pagination,spring-data,spring-hateoas,Spring,Spring Mvc,Pagination,Spring Data,Spring Hateoas,我使用的是Spring4.0.0.RELEASE,SpringDataCommons 1.7.0.M1,SpringHateoas0.8.0.RELEASE 我的资源是一个简单的POJO: public class UserResource extends ResourceSupport { ... } 我的资源汇编器将用户对象转换为用户资源对象: @Component public class UserResourceAssembler extends ResourceAssemblerSu

我使用的是Spring4.0.0.RELEASE,SpringDataCommons 1.7.0.M1,SpringHateoas0.8.0.RELEASE

我的资源是一个简单的POJO:

public class UserResource extends ResourceSupport { ... }
我的资源汇编器将用户对象转换为用户资源对象:

@Component
public class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> { 
    public UserResourceAssembler() {
        super(UserController.class, UserResource.class);
    }

    @Override
    public UserResource toResource(User entity) {
        // map User to UserResource
    }
}
这不会调用
UserResourceAssembler
,只返回
User
的内容,而不是我的自定义
UserResource

返回单个资源有效:

@Autowired
UserResourceAssembler assembler;

@RequestMapping(value="{id}", method=RequestMethod.GET)
UserResource getById(@PathVariable ObjectId id) throws NotFoundException {
    return assembler.toResource(service.getById(id));
}
PagedResourcesAssembler
需要一些通用参数,但是我不能使用
t来调用(t)
,因为我不想将我的
页面
转换为
PagedResources
,特别是因为
用户
是POJO,没有资源

所以问题是:它是如何工作的

编辑: My WebMVC配置支持:

@Configuration
@ComponentScan
@EnableHypermediaSupport
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(pageableResolver());
        argumentResolvers.add(sortResolver());
        argumentResolvers.add(pagedResourcesAssemblerArgumentResolver());
    }

    @Bean
    public HateoasPageableHandlerMethodArgumentResolver pageableResolver() {
        return new HateoasPageableHandlerMethodArgumentResolver(sortResolver());
    }

    @Bean
    public HateoasSortHandlerMethodArgumentResolver sortResolver() {
        return new HateoasSortHandlerMethodArgumentResolver();
    }

    @Bean
    public PagedResourcesAssembler<?> pagedResourcesAssembler() {
        return new PagedResourcesAssembler<Object>(pageableResolver(), null);
    }

    @Bean
    public PagedResourcesAssemblerArgumentResolver pagedResourcesAssemblerArgumentResolver() {
        return new PagedResourcesAssemblerArgumentResolver(pageableResolver(), null);
    }

    /* ... */
}
@配置
@组件扫描
@支持超媒体
公共类WebMvcConfig扩展了WebMvcConfigurationSupport{
@凌驾
受保护的void addArgumentResolvers(列出argumentResolvers){
add(pageableResolver());
ArgumentResolver.add(sortResolver());
ArgumentResolver.add(PagedResourcesSembleRargumentResolver());
}
@豆子
public HateoasPageableHandlerMethodArgumentResolver pageableResolver(){
返回新的HateoasPageableHandlerMethodArgumentResolver(sortResolver());
}
@豆子
public HateOsordHandlerMethodArgumentResolver sortResolver(){
返回新的HateoSockHandlerMethodArgumentResolver();
}
@豆子
公共页面DresourcesAssembler页面DresourcesAssembler(){
返回新的PagedResourcesAssembler(pageableResolver(),null);
}
@豆子
公共页面dResourcesSemblerAgentResolver页面dResourcesSemblerAgentResolver(){
返回新的PagedResourcesSembleRargumentResolver(pageableResolver(),null);
}
/* ... */
}
解决方案:
@Autowired
用户资源汇编程序;
@RequestMapping(value=”“,method=RequestMethod.GET)
PagedResources获取(@PageableDefault Pageable p,PagedResourcesAssembler pagedAssembler){
第u页=服务获取(p)
返回pagedAssembler.toResource(u,汇编程序);
}

您似乎已经找到了正确的使用方法,但我想在这里介绍一些细节,让其他人也能找到。我在中讨论了关于
PagedResourceAssembler
的类似细节

表示模型 Spring HATEOAS附带了各种表示模型的基类,使创建带有链接的表示变得容易。开箱即用提供了三种类型的类:

  • 资源
    -项目资源。有效地围绕捕获单个项目并通过链接丰富其内容的DTO或实体
  • Resources
    -一种集合资源,它可以是某些事物的集合,但通常是
    resource
    实例的集合
  • PagedResources
    -对
    资源的扩展,可捕获额外的分页信息,如总页数等
所有这些类都源自
ResourceSupport
,它是
链接
实例的基本容器

资源汇编程序
ResourceAssembler
现在是将域对象或DTO转换为此类资源实例的缓解组件。这里的重要部分是,它将一个源对象转换为一个目标对象

因此,
PagedResourcesAssembler
将获取一个Spring数据
Page
实例,通过评估
Page
并创建必要的
PageMetadata
以及导航页面的
prev
next
链接,将其转换为
PagedResources
实例。默认情况下,它将使用一个普通的
SimplePagedResourceAssembler
(一个
PRA
的内部类)将页面的各个元素转换为嵌套的
资源
实例,这可能是这里最有趣的部分

为了允许对此进行自定义,
PRA
具有额外的
toResource(…)
方法,这些方法使用委托
resourcesassembler
来处理单个项。所以你会得到这样的结果:

 class UserResource extends ResourceSupport { … }

 class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> { … }
 PagedResourcesAssembler<User> parAssembler = … // obtain via DI
 UserResourceAssembler userResourceAssembler = … // obtain via DI

 Page<User> users = userRepository.findAll(new PageRequest(0, 10));

 // Tell PAR to use the user assembler for individual items.
 PagedResources<UserResource> pagedUserResource = parAssembler.toResource(
   users, userResourceAssembler);
class UserResource扩展了ResourceSupport{…}
类UserResourceAssembler扩展ResourceAssemblerSupport{…}
客户端代码现在看起来像这样:

 class UserResource extends ResourceSupport { … }

 class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> { … }
 PagedResourcesAssembler<User> parAssembler = … // obtain via DI
 UserResourceAssembler userResourceAssembler = … // obtain via DI

 Page<User> users = userRepository.findAll(new PageRequest(0, 10));

 // Tell PAR to use the user assembler for individual items.
 PagedResources<UserResource> pagedUserResource = parAssembler.toResource(
   users, userResourceAssembler);
PagedResourcesAssembler-ParasAssembler=…//通过DI获取
UserResourceAssembler UserResourceAssembler=…//通过DI获取
Page users=userRepository.findAll(新的页面请求(0,10));
//告诉PAR使用单个组件的用户汇编程序。
PagedResources pagedUserResource=parAssembler.toResource(
用户,userResourceAssembler);
见解 从即将发布的Spring Data Commons 1.7 RC1(以及Spring HATEOAS 0.9过渡版)开始,
prev
next
链接将作为兼容的URI模板生成,以公开
HandlerMethodArgumentResolver
中为
Pageable
Sort
配置的分页请求参数


通过使用
@EnableSpringDataWebSupport
注释config类,可以简化上面显示的配置,这将使您摆脱所有显式bean声明。

替代方法

另一种方法是使用范围HTTP标头(请参阅中的详细信息)。您可以通过以下方式定义HTTP标头:

Range: resources=20-41
这意味着,您希望获得从20到41(包括)的资源。这种方式允许API的使用者接收精确定义的资源

这只是另一种方式。范围通常与其他单位(如字节等)一起使用

推荐方式

如果您想使用分页并拥有真正适用的API(包括超媒体/HATEOAS),那么我建议您
http://host.loc/articles?Page=1&PageSize=20
{
    var requestHelper = new RequestHelper(Request);

    int page = requestHelper.GetValueFromQueryString<int>("page");
    int pageSize = requestHelper.GetValueFromQueryString<int>("pagesize");

    var filter = new QueryFilter
    {
        Page = page != 0 ? page : DefaultPageNumber,
        PageSize = pageSize != 0 ? pageSize : DefaultPageSize
    };

    return filter;
}
public class ApiCollection<T>
{
    public ApiCollection()
    {
        Data = new List<T>();
    }

    public ApiCollection(int? totalItems, int? totalPages)
    {
        Data = new List<T>();
        TotalItems = totalItems;
        TotalPages = totalPages;
    }

    public IEnumerable<T> Data { get; set; }

    public int? TotalItems { get; set; }
    public int? TotalPages { get; set; }
}
public abstract class ApiEntity
{
    public List<ApiLink> Links { get; set; }
}

public class ApiLink
{
    public ApiLink(string rel, string href)
    {
        Rel = rel;
        Href = href;
    }

    public string Href { get; set; }

    public string Rel { get; set; }
}
 public class JobExecutionInfoResource extends ResourceSupport {
    private final JobExecutionInfo jobExecution;

    public JobExecutionInfoResource(final JobExecutionInfo jobExecution) {
        this.jobExecution = jobExecution;        
        add(ControllerLinkBuilder.linkTo(methodOn(JobsMonitorController.class).get(jobExecution.getId())).withSelfRel()); // add your own links.          
    }

    public JobExecutionInfo getJobExecution() {
        return jobExecution;
    }
}
    private final PagedResourcesAssembler<JobExecutionInfoResource> jobExecutionInfoResourcePagedResourcesAssembler;
    public static final PageRequest DEFAULT_PAGE_REQUEST = new PageRequest(0, 20);
    public static final ResourceAssembler<JobExecutionInfoResource, JobExecutionInfoResource> SIMPLE_ASSEMBLER = entity -> entity;

@GetMapping("/{clientCode}/{propertyCode}/summary")
    public PagedResources<JobExecutionInfoResource> getJobsSummary(@PathVariable String clientCode, @PathVariable String propertyCode,
                                                                   @RequestParam(required = false) String exitStatus,
                                                                   @RequestParam(required = false) String jobName,
                                                                   Pageable pageRequest) {
        List<JobExecutionInfoResource> listOfResources = // your code to generate the list of resource;
        int totalCount = 10// some code to get total count;
        Link selfLink = linkTo(methodOn(JobsMonitorController.class).getJobsSummary(clientCode, propertyCode, exitStatus, jobName, DEFAULT_PAGE_REQUEST)).withSelfRel();
        Page<JobExecutionInfoResource> page = new PageImpl<>(jobExecutions, pageRequest, totalCount);
        return jobExecutionInfoResourcePagedResourcesAssembler.toResource(page, SIMPLE_ASSEMBLER, selfLink);
    }