如何将Flux中的EventCategoryEntity聚合映射为指定DTO结构?
问题描述
我定义了如下实体类EventCategoryEntity:
public class EventCategoryEntity { private UUID id; @Column("category_name") private String categoryName; @Column("group_name") private String groupName; }
通过Flux(一对多关系)查询获取数据:
public Flux<EventCategoryEntity> findAllCategories() { return eventRepository.findAll(); } @Query("select ec.id, ec.name as category_name,ecg.name as group_name" + "from event_category ec left join event_category_relation ecr on (ec.id = ecr.event_category_id) " + "left join event_category_group ecg on (ecr.event_category_group_id = ecg.id);") Flux<EventCategoryEntity> findAll();
当前Controller返回的JSON响应如下:
[ { "id": "87108493-4fc1-4b12-8ffc-e10aa039fc39", "categoryName": "soccer", "groupName": "team" }, { "id": "87108493-4fc1-4b12-8ffc-e10aa039fc39", "categoryName": "soccer", "groupName": "ball" } ]
但我希望按id聚合后的响应结构如下:
[ { "id": "87108493-4fc1-4b12-8ffc-e10aa039fc39", "categoryName": "soccer", "groupName": ["team", "ball"] } ]
我已准备好DTO类:
public class EventCategory { private UUID id; private String categoryName; private List<CategoryGroup> categoryGroup; private class CategoryGroup { private String groupName; } }
但不知如何将Flux中的数据映射转换为该DTO结构。
解决方案
可以利用Reactor的操作符对Flux<EventCategoryEntity>进行分组、聚合,再映射到目标DTO,具体步骤如下:
1. 按id分组
使用groupBy操作符,将相同id的EventCategoryEntity归为一组:
Flux<GroupedFlux<UUID, EventCategoryEntity>> groupedFlux = eventRepository.findAll() .groupBy(EventCategoryEntity::getId);
2. 对分组数据聚合转换
对每个分组,提取共同的id和categoryName,收集所有groupName并构建DTO:
Flux<EventCategory> resultFlux = groupedFlux.flatMap(group -> { // 取分组内第一个元素的基础信息(同组内id、categoryName一致) return group.take(1) .flatMap(firstEntity -> { // 收集当前分组所有的groupName return group.map(EventCategoryEntity::getGroupName) .collectList() .map(groupNames -> { // 转换为CategoryGroup列表 List<EventCategory.CategoryGroup> categoryGroups = groupNames.stream() .map(name -> { EventCategory.CategoryGroup group = new EventCategory().new CategoryGroup(); group.setGroupName(name); return group; }) .collect(Collectors.toList()); // 构建最终DTO对象 EventCategory dto = new EventCategory(); dto.setId(firstEntity.getId()); dto.setCategoryName(firstEntity.getCategoryName()); dto.setCategoryGroup(categoryGroups); return dto; }); }); });
3. 关键说明
- 因为同组数据的
id和categoryName完全一致,用take(1)获取基础信息能避免重复处理,提升效率; - 若允许调整DTO结构,把
categoryGroup改为List<String>,可省去CategoryGroup的转换步骤,直接赋值groupNames; - 非静态内部类
CategoryGroup需要通过外部类实例创建,即new EventCategory().new CategoryGroup()。
4. Controller返回处理结果
在Controller方法中直接返回上述resultFlux,Spring WebFlux会自动序列化为期望的JSON结构。
内容的提问来源于stack exchange,提问作者user1089362
相关产品推荐
相关产品推荐

