You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Webflux非阻塞实现:多User实体转含部门列表的UserDTO

解决Spring Webflux下合并同一用户多数据的非阻塞实现

核心思路

利用响应式流的分组操作,先按用户ID聚合同一用户的所有数据,再将聚合后的部门信息整理为列表,最终组装成单个UserDTO,全程保持非阻塞特性。

步骤实现

1. 补全DepartmentDTO定义

首先需要定义对应部门信息的DTO类:

public class DepartmentDTO {
    private String department;
    private String departmentArea;

    // 构造器、Getter/Setter
    public DepartmentDTO(String department, String departmentArea) {
        this.department = department;
        this.departmentArea = departmentArea;
    }

    // 省略Getter/Setter方法
}

2. 修改服务层响应式流处理逻辑

将原有的直接映射逻辑替换为分组-聚合-转换的流程:

userRepo.findAllUsersByIds()
        // 按用户ID分组,同一ID的User进入同一响应式分组
        .groupBy(User::getId)
        // 处理每个分组,转换为单个UserDTO
        .flatMap(groupedUsers -> groupedUsers
                // 将分组内的Flux<User>收集为Mono<List<User>>(非阻塞操作)
                .collectList()
                .map(users -> {
                    // 提取用户基础信息(同一ID的name需保证一致)
                    User baseUser = users.get(0);
                    // 转换所有部门信息为DepartmentDTO列表,可按需去重
                    List<DepartmentDTO> deptList = users.stream()
                            .map(user -> new DepartmentDTO(user.getDepartment(), user.getDepartmentArea()))
                            .distinct() // 去除重复的部门记录
                            .collect(Collectors.toList());
                    // 组装最终的UserDTO
                    UserDTO userDTO = new UserDTO();
                    userDTO.setId(baseUser.getId());
                    userDTO.setName(baseUser.getName());
                    userDTO.setDepartmentDTO(deptList);
                    return userDTO;
                })
        );

3. (可选)抽离映射逻辑到Mapper类

如果需要复用映射逻辑,可以将聚合转换的代码抽离到Mapper类中:

// Mapper类中的方法
public UserDTO mapToUserDTO(List<User> users) {
    if (users == null || users.isEmpty()) {
        return null;
    }
    User baseUser = users.get(0);
    List<DepartmentDTO> deptList = users.stream()
            .map(this::mapToDepartmentDTO)
            .distinct()
            .collect(Collectors.toList());
    
    UserDTO dto = new UserDTO();
    dto.setId(baseUser.getId());
    dto.setName(baseUser.getName());
    dto.setDepartmentDTO(deptList);
    return dto;
}

private DepartmentDTO mapToDepartmentDTO(User user) {
    return new DepartmentDTO(user.getDepartment(), user.getDepartmentArea());
}

此时服务层代码可简化为:

userRepo.findAllUsersByIds()
        .groupBy(User::getId)
        .flatMap(group -> group.collectList().map(mapper::mapToUserDTO));

关键注意事项

  • 确保同一用户ID对应的name字段数据一致,非规范化表可能存在数据冗余或不一致,需提前校验或处理。
  • distinct()可根据业务需求选择是否保留:如果数据库中同一用户同一部门有多条重复记录,使用该方法去重;若需保留所有历史记录则移除。
  • 所有操作均为响应式非阻塞操作,符合Spring Webflux的异步编程模型,不会阻塞线程。

内容的提问来源于stack exchange,提问作者Upen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:35:47