如何在 spring-data-rest 中将 Page<ObjectEntity> 映射到 Page<ObjectDTO>

How to map Page<ObjectEntity> to Page<ObjectDTO> in spring-data-rest

当我使用 PagingAndSortingRepository.findAll(Pageable) 访问数据库时,我得到 Page<ObjectEntity>。但是,我想将 DTO 公开给客户端而不是实体。我可以通过将实体注入它的构造函数来创建 DTO,但是如何将 Page 对象中的实体映射到 DTO?根据 spring 文档,Page 提供只读操作。

此外,Page.map 是不可能的,因为我们不支持 java 8. 如何手动创建带有映射对象的新页面?

您仍然可以使用不带 lambda 表达式的 Page.map

Page<ObjectEntity> entities = objectEntityRepository.findAll(pageable);
Page<ObjectDto> dtoPage = entities.map(new Converter<ObjectEntity, ObjectDto>() {
    @Override
    public ObjectDto convert(ObjectEntity entity) {
        ObjectDto dto = new ObjectDto();
        // Conversion logic

        return dto;
    }
});

这是我的解决方案,感谢@Ali Dehghani

private Page<ObjectDTO> mapEntityPageIntoDTOPage(Page<ObjectEntity> objectEntityPage) {
        return objectEntityPage.map(new Converter<ObjectEntity, ObjectDTO>() {
            public ObjectDTO convert(ObjectEntity objectEntity) {
                return new ObjectDTO(objectEntity, httpSession);
            }

        });
    }

在java8中:

Page<ObjectDto> entities = 
 objectEntityRepository.findAll(pageable)
 .map(ObjectDto::fromEntity);

其中 fromEntity 是 ObjectDto 上包含转换逻辑的静态方法。

在Spring数据2中,Page map方法采用了一个Function而不是一个Converter,但它仍然与@Ali Dehghani描述的基本相同。

使用函数:

Page<ObjectEntity> entities = objectEntityRepository.findAll(pageable);
Page<ObjectDto> dtoPage = entities.map(new Function<ObjectEntity, ObjectDto>() {
    @Override
    public ObjectDto apply(ObjectEntity entity) {
        ObjectDto dto = new ObjectDto();
        // Conversion logic

        return dto;
    }
});

最后,您不会 return 给用户的页面,而是一个 ObjectDTO 列表,页面详细信息在 header,所以这将是我的解决方案。

对象服务

public Page<ObjectEntity> findAll (Pageable pageable){
  //logic goes here.
  Page<ObjectEntity> page = objectRepository.findAll(pageable);
  return page;
} 

ObjectResource / rest(公开的端点)

@GetMapping
public ResponseEntity<List<ObjectDTO>> findAll (Pageable pageable){
  Page<ObjectEntity> page = objectServiceService.findAll(pageable);

  HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "your-endpoint-here");

  return new ResponseEntity<>(objectMapper.toDto(page.getContent()), headers, HttpStatus.OK);
}

使用它的原因是您不需要为 ObjectEntity 和 DTO 复制页面详细信息。需要注意的是,页面包含以下内容:

  • 页码
  • 页面大小
  • 数量元素
  • 内容

content 是 objects returned 的列表,是唯一需要映射到 DTO 的内容。

您只需执行以下操作即可使用 Page.map:

public Page<ObjectDto> toPageObjectDto(Page<Object> objects) {
    Page<ObjectDto> dtos  = objects.map(this::convertToObjectDto);
    return dtos;
}

private ObjectDto convertToObjectDto(Object o) {
    ObjectDto dto = new ObjectDto();
    //conversion here
    return dto;
}

我创建了解决方案并将其与模型映射器、泛型和 lambda 一起用于常见用途。

/**
 * Maps the Page {@code entities} of <code>T</code> type which have to be mapped as input to {@code dtoClass} Page
 * of mapped object with <code>D</code> type.
 *
 * @param <D> - type of objects in result page
 * @param <T> - type of entity in <code>entityPage</code>
 * @param entities - page of entities that needs to be mapped
 * @param dtoClass - class of result page element
 * @return page - mapped page with objects of type <code>D</code>.
 * @NB <code>dtoClass</code> must has NoArgsConstructor!
 */
public <D, T> Page<D> mapEntityPageIntoDtoPage(Page<T> entities, Class<D> dtoClass) {
    return entities.map(objectEntity -> modelMapper.map(objectEntity, dtoClass));
} 

这正是您需要的情况(我认为其他情况的常见情况)。

您已经通过这种方式从存储库(与服务相同)获取数据:

Page<ObjectEntity> entities = objectEntityRepository.findAll(pageable);

转换所需的一切就是按这种方式调用此方法:

Page<ObjectDto> dtoPage = mapEntityPageIntoDtoPage(entities, ObjectDto.class);

@提示:您可以从 util class 中使用此方法,并且可以根据您的体系结构对服务和控制器上的页面转换中的所有 entity/dto 重复使用。

示例:

Page<ObjectDto> dtoPage = mapperUtil.mapEntityPageIntoDtoPage(entities, ObjectDto.class);

使用lambda表达式更方便

Page<ObjectDto> dto=objectRepository.findAll(pageable).map((object -> DozerBeanMapperBuilder.buildDefault().map(object, ObjectDto.class)));

这在 Spring 2.0 中正常工作 -

@Override
public Page<BookDto> getBooksByAuthor(String authorId, Pageable pageable) {
        Page<BookEntity> bookEntity = iBookRepository.findByAuthorId(authorId, pageable);
        return bookEntity.map(new Function<BookEntity, BookDto>() {

            @Override
            public BookDto apply(BookEntity t) {
                return new ModelMapper().map(t, BookDto.class);
            }

        });
    }

Spring 2.0 的页面类型不再支持该转换器。此外,该函数应从 java.util.function.Function.

使用

使用 Java 8 Lambda,它对我有用。上面已经给出了答案,我只是简化一下。

Page<EmployeeEntity> employeeEntityPage = employeeService.findEmployeeEntities();


Page<EmployeeDto> employeeDtoPage = employeeEntityPage.map(entity -> {
        EmployeeDto dto = employeeService.employeEntityToDto(entity);
        return dto;
    });

这里employeeEntityToDto()是Entities转Dtos的方法

public EmployeeDto employeeEntityToDto(EmployeeEntity entity){
    EmployeeDto employeeDto =  new EmployeeDto();
    employeeDto.setId(entity.getId());
    employeeDto.setName(entity.getName());
    return employeeDto;
}
Page<Order> persistedOrderPage = orderQueryRepository.search();

Page<OrderDTO> orderPage = persistedOrderPage.map(persistedOrder -> {
    OrderDTO order = mapper.toOrderDTO(persistedOrder);
    // do another action
    return order;
});