1.pom.xml?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion groupIdcom.example/groupId artifactIdmongodb-demo/artifactId version1.0.0-SNAPSHOT/version namemongodb-demo/name descriptionJava SE Kotlin Maven Spring Data MongoDB demo/description properties kotlin.version1.9.24/kotlin.version kotlinx.coroutines.version1.8.1/kotlinx.coroutines.version reactor.version3.6.6/reactor.version junit.version5.10.2/junit.version spring.data.mongodb.version4.2.5/spring.data.mongodb.version mongodb.driver.version4.11.2/mongodb.driver.version project.build.sourceEncodingUTF-8/project.build.sourceEncoding maven.compiler.source21/maven.compiler.source maven.compiler.target21/maven.compiler.target /properties dependencies dependency groupIdorg.jetbrains.kotlin/groupId artifactIdkotlin-stdlib/artifactId version${kotlin.version}/version /dependency dependency groupIdorg.jetbrains.kotlin/groupId artifactIdkotlin-reflect/artifactId version${kotlin.version}/version /dependency dependency groupIdorg.jetbrains.kotlinx/groupId artifactIdkotlinx-coroutines-core/artifactId version${kotlinx.coroutines.version}/version /dependency dependency groupIdorg.jetbrains.kotlinx/groupId artifactIdkotlinx-coroutines-reactor/artifactId version${kotlinx.coroutines.version}/version /dependency dependency groupIdio.projectreactor/groupId artifactIdreactor-core/artifactId version${reactor.version}/version /dependency dependency groupIdorg.springframework.data/groupId artifactIdspring-data-mongodb/artifactId version${spring.data.mongodb.version}/version /dependency dependency groupIdorg.mongodb/groupId artifactIdmongodb-driver-reactivestreams/artifactId version${mongodb.driver.version}/version /dependency dependency groupIdorg.slf4j/groupId artifactIdslf4j-simple/artifactId version2.0.13/version scoperuntime/scope /dependency dependency groupIdorg.junit.jupiter/groupId artifactIdjunit-jupiter/artifactId version${junit.version}/version scopetest/scope /dependency /dependencies build sourceDirectory${project.basedir}/src/main/kotlin/sourceDirectory plugins plugin groupIdorg.jetbrains.kotlin/groupId artifactIdkotlin-maven-plugin/artifactId version${kotlin.version}/version executions execution idcompile/id phasecompile/phase goals goalcompile/goal /goals /execution execution idtest-compile/id phasetest-compile/phase goals goaltest-compile/goal /goals /execution /executions configuration jvmTarget${maven.compiler.target}/jvmTarget /configuration /plugin plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-surefire-plugin/artifactId version3.2.5/version configuration useModulePathfalse/useModulePath /configuration /plugin plugin groupIdorg.codehaus.mojo/groupId artifactIdexec-maven-plugin/artifactId version3.2.0/version /plugin /plugins /build /project2.MongoTemplateFactory.ktpackage com.example.mongodbdemo.config import com.mongodb.reactivestreams.client.MongoClient import com.mongodb.reactivestreams.client.MongoClients import kotlinx.coroutines.reactor.awaitSingle import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider import org.springframework.data.mongodb.core.ReactiveMongoTemplate import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper import org.springframework.data.mongodb.core.convert.MappingMongoConverter import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver import org.springframework.data.mongodb.core.mapping.Document import org.springframework.core.type.filter.AnnotationTypeFilter object MongoTemplateFactory { // 根据地址创建 fun createMongoClient(uri: String): MongoClient MongoClients.create(uri) // 后续关闭使用 suspend fun createTemplate( mongoClient: MongoClient, database: String, entityBasePackages: ListString listOf(defaultEntityBasePackage()) ): ReactiveMongoTemplate { val factory SimpleReactiveMongoDatabaseFactory(mongoClient, database) val template ReactiveMongoTemplate(factory) configureTypeMapper(template) val entityClasses scanDocumentEntities(entityBasePackages) ensureIndexesFromAnnotations(template, entityClasses) return template } // 索引检查 private suspend fun ensureIndexesFromAnnotations( template: ReactiveMongoTemplate, entityClasses: ListClass* ) { if (entityClasses.isEmpty()) { return } val resolver MongoPersistentEntityIndexResolver(template.converter.mappingContext) entityClasses.forEach { entityClass - val indexOps template.indexOps(entityClass) resolver.resolveIndexFor(entityClass).forEach { indexDefinition - indexOps.ensureIndex(indexDefinition).awaitSingle() } } } // 扫描包 private fun scanDocumentEntities(basePackages: ListString): ListClass* { val scanner ClassPathScanningCandidateComponentProvider(false) scanner.addIncludeFilter(AnnotationTypeFilter(Document::class.java)) return basePackages.asSequence() .flatMap { basePackage - scanner.findCandidateComponents(basePackage).asSequence() } .mapNotNull { beanDefinition - beanDefinition.beanClassName } .map { className - Class.forName(className) } .toList() } // 默认包名 private fun defaultEntityBasePackage(): String { val packageName MongoTemplateFactory::class.java.packageName return if (packageName.endsWith(.config)) { packageName.removeSuffix(.config) } else { packageName } } // 去掉_class private fun configureTypeMapper(template: ReactiveMongoTemplate) { val converter template.converter if (converter is MappingMongoConverter) { converter.setTypeMapper(DefaultMongoTypeMapper(null)) } } }3.Person.kt 文档例子package com.example.mongodbdemo.model import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.index.Indexed import org.springframework.data.mongodb.core.mapping.Document Document(person) data class Person( // 主键 Id val id: String? null, // 唯一索引 Indexed(unique true, name uk_person_name) val name: String, val email: String )4.PersonService.ktpackage com.example.mongodbdemo.service import com.example.mongodbdemo.model.Person import kotlinx.coroutines.reactor.awaitSingle import kotlinx.coroutines.reactor.awaitSingleOrNull import org.springframework.data.mongodb.core.ReactiveMongoTemplate import org.springframework.data.mongodb.core.query.Criteria import org.springframework.data.mongodb.core.query.Query import org.springframework.data.mongodb.core.query.Update class PersonService( private val mongoTemplate: ReactiveMongoTemplate ) { private val collectionName person // 增 suspend fun create(name: String, email: String): Person mongoTemplate.save(Person(name name, email email), collectionName).awaitSingle() // 查 suspend fun findById(id: String): Person? mongoTemplate.findById(id, Person::class.java, collectionName).awaitSingleOrNull() // 查 suspend fun findByEmail(email: String): Person? { val query Query.query(Criteria.where(email).is(email)) return mongoTemplate.findOne(query, Person::class.java, collectionName).awaitSingleOrNull() } // 更 suspend fun updateEmail(id: String, newEmail: String): Boolean { val query Query.query(Criteria.where(_id).is(id)) val update Update().set(email, newEmail) val result mongoTemplate.updateFirst(query, update, Person::class.java, collectionName).awaitSingle() return result.modifiedCount 0 } // 查询所有 suspend fun listAll(): ListPerson mongoTemplate.findAll(Person::class.java, collectionName).collectList().awaitSingle() // 删 suspend fun deleteById(id: String) { val query Query.query(Criteria.where(_id).is(id)) mongoTemplate.remove(query, Person::class.java, collectionName).awaitSingle() } }5.App.ktpackage com.example.mongodbdemo import com.example.mongodbdemo.config.MongoTemplateFactory import com.example.mongodbdemo.service.PersonService import kotlinx.coroutines.runBlocking import org.springframework.dao.DuplicateKeyException fun main() { val mongoUri mongodb://localhost:37017 val primaryDb demo_db val mongoClient MongoTemplateFactory.createMongoClient(mongoUri) try { runBlocking { println(Java SE Mongo demo started.) try { // 连接上db val primaryTemplate MongoTemplateFactory.createTemplate( mongoClient mongoClient, database primaryDb ) val primaryService PersonService(primaryTemplate) println(Primary service: ${primaryService.javaClass.simpleName}, db$primaryDb) println(Indexes ensured from annotations (including unique person.name)) // 增 val created primaryService.create(DemoUser_${System.currentTimeMillis()}, demo.userexample.com) println(CREATE: $created) // 查询(不为null时执行let语句) val found created.id?.let { id - primaryService.findById(id) } println(READ BY ID: $found) if (created.id ! null) { // 改 val updated primaryService.updateEmail(created.id, demo.userupdatedexample.com) println(UPDATE EMAIL: $updated) println(READ BY EMAIL: ${primaryService.findByEmail(demo.userupdatedexample.com)}) println(LIST SIZE: ${primaryService.listAll().size}) // 删 primaryService.deleteById(created.id) println(DELETE DONE, READ AGAIN: ${primaryService.findById(created.id)}) } } catch (ex: DuplicateKeyException) { println(Cannot create unique index on person.name because duplicate names already exist.) println(Please remove duplicate name records in collection person first, then run again.) throw ex } catch (ex: RuntimeException) { println(Failed to initialize Mongo or execute CRUD: ${ex.message}) throw ex } } } finally { mongoClient.close() } }