如何从含List型DTO的BookingEntity映射数据至ViewAllDTO?
解决MongoDB BookingEntity到ViewAllDTO的List类型字段映射问题
问题分析
你的代码编译错误核心原因是直接把List类型字段当成单个对象访问:
BookingEntity的booking是List<BookingDTO>,没有getBooking_number()方法,需从List元素中提取booking_numbershipper_details是List<ShipperDetailsDTO>,没有getFirst_name()/getLast_name()方法,需从List元素中获取字段拼接item是List<ItemDTO>,无法直接将多个字段参数传给setItem_details(),需先把ItemDTO字段整合为字符串
基础解决方案(手动映射)
假设每个BookingEntity对应单个BookingDTO、ShipperDetailsDTO(若需处理多元素场景,可根据业务逻辑调整,比如拼接所有元素或取指定元素),修正后的映射方法如下:
import org.apache.commons.lang3.StringUtils; import java.util.Optional; public ViewAllDTO toDTO(BookingEntity entity) { ViewAllDTO dto = new ViewAllDTO(); // 提取booking_number:空值安全处理List,取第一个元素的booking_number Optional.ofNullable(entity.getBooking()) .filter(list -> !list.isEmpty()) .map(list -> list.get(0).getBooking_number()) .ifPresent(dto::setBooking_number); // 拼接sender_name:空值安全处理List,拼接first_name+last_name Optional.ofNullable(entity.getShipper_details()) .filter(list -> !list.isEmpty()) .map(list -> list.get(0)) .map(shipper -> StringUtils.normalizeSpace(String.format("%s %s", shipper.getFirst_name(), shipper.getLast_name()))) .ifPresent(dto::setSender_name); // 整合item_details:循环拼接所有ItemDTO的字段为字符串 StringBuilder itemDetailsBuilder = new StringBuilder(); Optional.ofNullable(entity.getItem()) .ifPresent(items -> { for (ItemDTO item : items) { itemDetailsBuilder.append(String.format( "商品描述:%s,重量:%s,尺寸:%sx%sx%s,申报价值:%s,包装类型:%s\n", item.getItem_description(), item.getWeight(), item.getHeight(), item.getLength(), item.getWidth(), item.getDeclared_value(), item.getPackage_handling_type() )); } }); dto.setItem_details(itemDetailsBuilder.toString().trim()); return dto; }
关键处理点说明
- 空值安全:用
Optional处理List为null或空的情况,避免空指针异常 - List元素提取:通过
filter(list -> !list.isEmpty())确保List有元素后再操作,若需支持多元素,可改为拼接所有值(比如String.join(",", list.stream().map(BookingDTO::getBooking_number).toList())) - 字段拼接:
item_details用StringBuilder循环拼接,格式可根据业务需求调整(比如改为JSON格式字符串)
进阶方案:用MapStruct简化映射
若项目有大量映射需求,推荐用MapStruct框架自动生成映射代码,减少手动编写重复逻辑。
1. 添加MapStruct依赖(Maven)
<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.5.5.Final</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.5.Final</version> <scope>provided</scope> </dependency>
2. 定义Mapper接口
import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Named; import java.util.List; import java.util.Optional; @Mapper(componentModel = "spring") public interface BookingMapper { @Mapping(source = "booking", target = "booking_number", qualifiedByName = "extractBookingNumber") @Mapping(source = "shipper_details", target = "sender_name", qualifiedByName = "buildSenderName") @Mapping(source = "item", target = "item_details", qualifiedByName = "buildItemDetails") ViewAllDTO toViewAllDTO(BookingEntity entity); @Named("extractBookingNumber") default String extractBookingNumber(List<BookingDTO> bookingList) { return Optional.ofNullable(bookingList) .filter(list -> !list.isEmpty()) .map(list -> list.get(0).getBooking_number()) .orElse(null); } @Named("buildSenderName") default String buildSenderName(List<ShipperDetailsDTO> shipperList) { return Optional.ofNullable(shipperList) .filter(list -> !list.isEmpty()) .map(list -> list.get(0)) .map(shipper -> StringUtils.normalizeSpace(String.format("%s %s", shipper.getFirst_name(), shipper.getLast_name()))) .orElse(null); } @Named("buildItemDetails") default String buildItemDetails(List<ItemDTO> itemList) { if (itemList == null || itemList.isEmpty()) { return ""; } StringBuilder builder = new StringBuilder(); for (ItemDTO item : itemList) { builder.append(String.format( "商品描述:%s,重量:%s,尺寸:%sx%sx%s,申报价值:%s,包装类型:%s\n", item.getItem_description(), item.getWeight(), item.getHeight(), item.getLength(), item.getWidth(), item.getDeclared_value(), item.getPackage_handling_type() )); } return builder.toString().trim(); } }
3. 使用Mapper
在业务类中注入BookingMapper即可直接调用:
@Autowired private BookingMapper bookingMapper; public ViewAllDTO convertToViewAllDTO(BookingEntity entity) { return bookingMapper.toViewAllDTO(entity); }
注意事项
- 若List字段包含多个元素,需根据业务需求调整逻辑:比如拼接所有值、取最新元素或指定元素
- 空值处理是生产环境必备,避免出现空指针异常
item_details的拼接格式可根据前端需求调整,比如改为JSON格式字符串
内容的提问来源于stack exchange,提问作者Practice Tech
相关产品推荐
相关产品推荐

