当我使用
PagingAndSortingRepository.findAll(Pageable)
访问数据库时,我得到 Page<ObjectEntity>
。但是,我想向客户端而不是实体公开 DTO。我可以通过将实体注入到 DTO 的构造函数中来创建 DTO,但是如何将 Page 对象中的实体映射到 DTO 呢?根据spring文档,Page提供只读操作。
此外,Page.map 也是不可能的,因为我们不支持 java 8。如何手动创建带有映射对象的新页面?
您仍然可以使用
Page.map
而不使用 lambda 表达式:
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;
}
});
在 Spring Data 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;
}
});
在java8中:
Page<ObjectDto> entities =
objectEntityRepository.findAll(pageable)
.map(ObjectDto::fromEntity);
其中 fromEntity 是 ObjectDto 上的静态方法,包含转换逻辑。
您可以通过简单地执行以下操作来使用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);
@Tip:您可以在 util 类中使用此方法,并且根据您的架构,它可以重用于服务和控制器上的页面转换中的所有实体/dto。
示例:
Page<ObjectDto> dtoPage = mapperUtil.mapEntityPageIntoDtoPage(entities, ObjectDto.class);
这是我的解决方案,感谢@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);
}
});
}
使用lambda表达式更方便
Page<ObjectDto> dto=objectRepository.findAll(pageable).map((object -> DozerBeanMapperBuilder.buildDefault().map(object, ObjectDto.class)));
Page<Order> persistedOrderPage = orderQueryRepository.search();
Page<OrderDTO> orderPage = persistedOrderPage.map(persistedOrder -> {
OrderDTO order = mapper.toOrderDTO(persistedOrder);
// do another action
return order;
});
这在 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;
}
我将 Lambda 与 ModelMapper
结合使用 Page<ObjectEntity> pageEntity = objectRepository.findAll(pageable);
Page<ObjectDto> pageDto = pageEntity.map(objectEntity -> modelMapper.map(objectEntity, ObjectDto.class));
最后,您不会将页面返回给用户,而是返回一个 ObjectDTO 列表,页面详细信息位于标题处,所以这将是我的解决方案。
public Page<ObjectEntity> findAll (Pageable pageable){
//logic goes here.
Page<ObjectEntity> page = objectRepository.findAll(pageable);
return page;
}
@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是返回的对象列表,并且是唯一需要映射到DTO的东西。
试试这个代码
服务
Pageable pageable = PageRequest.of(page - 1, size);
Page<ContentResDTO> resDTOPage = contentRepository.findAllBy(contentID, userId, pageable);
存储库
@Query("SELECT new com.example.demo.dto.content.ContentResDTO(t, COUNT(DISTINCT c.cmtID), COUNT(DISTINCT r.rctId)) " +
"FROM TMnTrContent t LEFT JOIN TMnTrComment c ON t.cntID = c.content.cntID LEFT JOIN TMnTrReact r ON t.cntID = r.content.cntID " +
" WHERE (:cntId IS NULL OR (:cntId IS NOT NULL AND t.cntID = :cntId)) AND " +
" (:userId IS NULL OR (:userId IS NOT NULL AND t.user.userId = :userId)) " +
" GROUP BY t.cntID")
Page<ContentResDTO> findAllBy(@Param("cntId") Long cntId,
@Param("userId") Long userId,
Pageable pageable);
DTO
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
public class ContentResDTO {
private long id;
private long userId;
private String type;
private String description;
private int version;
private Date createdDate;
private Date modifyDate;
private int commentCount;
private int reactCount;
public ContentResDTO(TMnTrContent content, long commentCount, long reactCount) {
this.id = content.getCntID();
this.userId = content.getUser().getUserId();
this.type = content.getCntType();
this.description = content.getCntDescription();
this.version = content.getVersion();
this.createdDate = content.getCreateDate();
this.modifyDate = content.getModifyDate();
this.commentCount = (int) commentCount;
this.reactCount = (int) reactCount;
}
}
这里是选项,如果你还需要从origin获取totalElements、totalPages
@Component
@RequiredArgsConstructor
public class CreditIssuedMapper {
public static CreditIssuedDto toCreditIssuedDto(CreditIssued creditIssued){
CreditIssuedDto c = new CreditIssuedDto();
c.setId(creditIssued.getId());
c.setClientId(creditIssued.getClientData().getId());
c.setClientName(creditIssued.getClientData().getClientName());
c.setClientSurname(creditIssued.getClientData().getClientSurname());
c.setClientMiddlename(creditIssued.getClientData().getClientMiddlename());
c.setManagerId(creditIssued.getManagerData().getId());
c.setManagerName(creditIssued.getManagerData().getManagerName());
c.setManagerSurname(creditIssued.getManagerData().getManagerSurname());
c.setManagerMiddlename(creditIssued.getManagerData().getManagerMiddlename());
c.setCreditIssuedBody(creditIssued.getCreditBody());
c.setCreditIssuedLeft(creditIssued.getCreditLeft());
c.setCreditIssuedFine(creditIssued.getCreditFine());
c.setCreditIssuedMonthlyPayment(creditIssued.getCreditMonthlyPayment());
c.setCreditIssuedDate(creditIssued.getCreditIssuedDate());
c.setCreditIssuedNextPayment(creditIssued.getCreditNextPayment());
c.setCreditIssuedExpDate(creditIssued.getCreditExpDate());
c.setCreditOfferId(creditIssued.getCreditOfferId().getId());
c.setCreditOfferName(creditIssued.getCreditOfferId().getCreditName());
c.setCreditOfferInterest(creditIssued.getCreditOfferId().getCreditInterest());
c.setCreditOfferFine(creditIssued.getCreditOfferId().getCreditFine());
c.setCreditOfferCurrency(creditIssued.getCreditOfferId().getCurrencyData().getCurrencyName());
return c;
}
public Page<CreditIssuedDto> creditIssuedDto (Page<CreditIssued> creditIssued){
List<CreditIssuedDto> creditIssuedDto = creditIssued
.stream()
.map(CreditIssuedMapper::toCreditIssuedDto)
.collect(Collectors.toList());
long totalElements = creditIssued.getTotalElements();
int totalPages = creditIssued.getTotalPages();
return new PageImpl<>(creditIssuedDto, PageRequest.of(creditIssued.getNumber(), creditIssued.getSize()), totalElements);
}
}