Spring Boot WebFlux如何正确编写Mono.map()返回值实现用户信息查询
响应式方法组装用户角色权限关联问题
原有代码与异常
基础实体与DTO定义
// 实体类 class User{ // 注意原有代码拼写错误:rivate 改为 private,Sting 改为 String private Long id; private String name; } class Role{ private Integer id; private String name; } class Permission{ private Integer id; private String name; private String uri; } // DTO类 class RoleDto extends Role{ private List<Permission> permissions; // 需补全构造方法、setter、角色新增方法 } class UserDto extends User{ private List<RoleDto> roles; // 需补全构造方法、setter、角色新增方法 }
错误业务实现
// 基础用户查询方法 public Mono<User> getUserById(Long userId){ return userRepository.findSysUserById(userId); } // 待修正的组装方法 public Mono<UserDto> getUserInfoByUserId(Long userId){ return getUserById(userId).map(user -> { UserDto userDto = new UserDto(user); roleService.getRolesByUserId(userId).map(roles -> { roles.forEach(role -> { RoleDto roleDto = new RoleDto(role); permissionService.getPermissionsByRoleId(role.getId()).map(plist ->{ roleDto.setPermissions(plist); userDto.addRoles(roleDto); return Mono.just(roleDto);//1 原代码标注疑问点 }).subscribe(); }); return Mono.just(roles);//2 原代码标注疑问点 }).subscribe(); return Mono.just(userDto); //3 原代码标注疑问点 }); }
编译异常信息
Required type: Mono
Provided:Mono
no instance(s) of type variable(s) T exist so that Mono conforms to UserDto inference variable R has incompatible bounds: equality constraints: UserDto lower bounds: Mono
错误原因
- 违反响应式流组装规则:手动在流处理逻辑中调用
subscribe()会打破完整订阅链,不仅会导致异步查询时序错乱(返回结果时角色、权限可能还未查询完成),还会引发泛型类型推断不匹配的编译错误 - 操作符使用错误:
map仅用于同步值转换,如果转换逻辑返回Mono/Flux等异步类型,必须使用flatMap/flatMapMany等操作符做流扁平化处理 - 嵌套异步逻辑未做组合:多层IO查询(查用户→查角色→查每个角色的权限)没有通过响应式操作符串联,无法保证结果组装的时序正确性
正确实现方案
public Mono<UserDto> getUserInfoByUserId(Long userId){ return getUserById(userId) // 第一步:查询到用户后,用flatMap衔接后续异步操作 .flatMap(user -> { UserDto userDto = new UserDto(user); // 第二步:查询用户关联的角色列表 return roleService.getRolesByUserId(userId) // 将角色列表转为Flux流逐个处理 .flatMapMany(Flux::fromIterable) // 第三步:逐个查询角色关联的权限,组装RoleDto .flatMap(role -> permissionService.getPermissionsByRoleId(role.getId()) .map(permissionList -> { RoleDto roleDto = new RoleDto(role); roleDto.setPermissions(permissionList); return roleDto; }) ) // 收集所有组装完成的RoleDto为列表 .collectList() // 第四步:将角色列表设置到UserDto,返回最终结果 .map(roleDtoList -> { userDto.setRoles(roleDtoList); return userDto; }); }); }
实现说明
- 整个流组装过程全程不手动调用
subscribe(),最终由WebFlux框架在请求处理末端统一触发订阅,保证异步时序正确 - 如果需要保证角色、权限的返回顺序,可以把
flatMap替换为concatMap;如果需要控制并发数,可以给flatMap传入指定并发度参数 - 请提前补全DTO类的构造方法、setter方法,修正实体类的拼写错误,避免基础编译问题
内容的提问来源于stack exchange,提问作者Ari
相关产品推荐
相关产品推荐

