Spring Boot Kotlin Reactive:如何合并多MongoDB查询结果返回单一响应?
实现Spring Boot 2 Kotlin Reactive手机号关联信息查询接口
看起来你正在搭建一个基于Spring Boot 2 Kotlin Reactive的手机号关联信息查询接口,我来分享一个完整的实现思路和代码示例,刚好匹配你的需求:
需求梳理
- 基于Spring Boot 2 + Kotlin Reactive技术栈构建接口
- 根据手机号从MongoDB查询关联的个人、公司、部门数据
- 通过请求参数灵活控制最终返回的显示名称格式:
asString:控制是否返回拼接后的字符串(示例中默认返回字符串)firstname/lastname/company/department:配置对应内容的显示规则(比如截取长度、显示优先级等)
核心实现步骤
1. 定义MongoDB实体类
首先定义关联的实体模型,用PhoneAssociation存储手机号与各实体的关联关系,保证灵活性:
import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document @Document("persons") data class Person( @Id val id: String? = null, val firstName: String, val lastName: String ) @Document("companies") data class Company( @Id val id: String? = null, val name: String ) @Document("departments") data class Department( @Id val id: String? = null, val name: String, val companyId: String ) @Document("phone_associations") data class PhoneAssociation( @Id val id: String? = null, val phoneNumber: String, val personId: String? = null, val companyId: String? = null, val departmentId: String? = null )
2. 编写Reactive Repository接口
使用Spring Data Reactive MongoDB提供的ReactiveMongoRepository实现异步数据操作:
import org.springframework.data.mongodb.repository.ReactiveMongoRepository import reactor.core.publisher.Mono interface PhoneAssociationRepository : ReactiveMongoRepository<PhoneAssociation, String> { fun findByPhoneNumber(phoneNumber: String): Mono<PhoneAssociation> } interface PersonRepository : ReactiveMongoRepository<Person, String> interface CompanyRepository : ReactiveMongoRepository<Company, String> interface DepartmentRepository : ReactiveMongoRepository<Department, String>
3. 实现业务逻辑服务类
核心是处理请求参数的规则(示例中假设参数值为内容截取长度,你可以根据需求改成显示优先级、是否显示等规则),并异步组装显示名称:
import org.springframework.stereotype.Service import reactor.core.publisher.Mono @Service class PhoneInfoService( private val phoneAssociationRepo: PhoneAssociationRepository, private val personRepo: PersonRepository, private val companyRepo: CompanyRepository, private val departmentRepo: DepartmentRepository ) { fun getDisplayName( phoneNumber: String, asString: Boolean, firstNameLen: Int?, lastNameLen: Int?, companyLen: Int?, departmentLen: Int? ): Mono<String> { return phoneAssociationRepo.findByPhoneNumber(phoneNumber) .flatMap { association -> // 并行获取所有关联数据,提升响应效率 val personMono = association.personId?.let(personRepo::findById) ?: Mono.empty() val companyMono = association.companyId?.let(companyRepo::findById) ?: Mono.empty() val departmentMono = association.departmentId?.let(departmentRepo::findById) ?: Mono.empty() Mono.zip(personMono, companyMono, departmentMono) .map { (person, company, department) -> val displayParts = mutableListOf<String>() // 处理个人名称 person?.let { val firstName = firstNameLen?.takeIf { it > 0 }?.let(it.firstName::take) ?: it.firstName val lastName = lastNameLen?.takeIf { it > 0 }?.let(it.lastName::take) ?: it.lastName displayParts.add("$firstName $lastName") } // 处理公司名称 company?.let { val companyName = companyLen?.takeIf { it > 0 }?.let(it.name::take) ?: it.name displayParts.add(companyName) } // 处理部门名称 department?.let { val deptName = departmentLen?.takeIf { it > 0 }?.let(it.name::take) ?: it.name displayParts.add(deptName) } // 按规则拼接成最终字符串 displayParts.joinToString(" | ") } } .defaultIfEmpty("No associated information found for phone number: $phoneNumber") } }
4. 编写Reactive Controller
定义接口端点,接收请求参数并调用业务逻辑:
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import reactor.core.publisher.Mono @RestController @RequestMapping("/api/v1/numbers") class PhoneInfoController(private val phoneInfoService: PhoneInfoService) { @GetMapping("/find/{phoneNumber}") fun getDisplayName( @PathVariable phoneNumber: String, @RequestParam(value = "asString", defaultValue = "true") asString: Boolean, @RequestParam(value = "firstname", required = false) firstNameLen: Int?, @RequestParam(value = "lastname", required = false) lastNameLen: Int?, @RequestParam(value = "company", required = false) companyLen: Int?, @RequestParam(value = "department", required = false) departmentLen: Int? ): Mono<String> { return phoneInfoService.getDisplayName(phoneNumber, asString, firstNameLen, lastNameLen, companyLen, departmentLen) } }
测试示例
使用你提供的请求地址:
http://localhost:8080/api/v1/numbers/find/xxxxxxxxxxx?asString=true&firstname=2&lastname=1&company=3&department=4
假设关联数据为:
- 个人:
firstName="张三", lastName="李四" - 公司:
name="XX科技有限公司" - 部门:
name="软件研发部"
则返回的显示字符串为:"张三 李 | XX科 | 软件研发"(对应参数截取长度规则)
如果需要调整参数规则(比如按优先级排序拼接),只需要修改PhoneInfoService中组装displayParts的逻辑即可,比如根据参数值的大小排序后再拼接。
内容的提问来源于stack exchange,提问作者SteVio
相关产品推荐
相关产品推荐

