@NoRepositoryBeaninterface BaseMongoRepository<T, ID> : MongoRepository<T, ID> {?fun listAll(condition: Criteria, pageable: Pageable): Page<T>?fun updateById(id: ID, update: Update): Long}复制代码
我创建了一个新的接口:BaseMongoRepository,用它来继承 MongoRepository,接着定义我们需要的扩展的一些方法,这里我扩展类了两个方法:新的多条件分页方法和新的更新接口 。
其中 listAll 方法的第一个参数 Criteria 是 Spring Data 已经给我们提供好的类,它广泛运用于 MongoTemplate 里面,毕竟这层 CRUD 的封装底层其实还是 MongoTemplate 来操作 。
除了继承接口外,我们还需要对这两个方法进行实现,再创建一个 BaseMongoRepository 的实现类去继承 MongoRepository 的实现类——SimpleMongoRepository:
class BaseMongoRepositoryClass<T, ID>(private val metadata: MongoEntityInformation<T, ID>,private val mongoOperations: MongoOperations) :SimpleMongoRepository<T, ID>(metadata, mongoOperations), BaseMongoRepository<T, ID> {?private val clazz: Class<T> = metadata.javaType?override fun listAll(condition: Criteria, pageable: Pageable): Page<T> {val list = mongoOperations.find(Query(condition).with(pageable), this.clazz, metadata.collectionName)?return PageableExecutionUtils.getPage(list, pageable) {mongoOperations.count(Query(condition).limit(-1).skip(-1),clazz,metadata.collectionName)}}?override fun updateById(id: ID, update: Update): Long {if (update.updateObject.isEmpty()) return 0return mongoOperations.updateFirst(Query().addCriteria(Criteria.where("_id").`is`(id)),update,metadata.collectionName).modifiedCount}??}复制代码
其中 BaseMongoRepositoryClass 需要两个参数,这两个参数直接从 SimpleMongoRepository 里面拷贝过来然后通过构造再传递给 SimpleMongoRepository 即可,反正都是从自动注入里面来 。
两个变量简单讲解一下都是什么意思:
- MongoEntityInformation:这个是 MongoEntity 的元信息,就是最上面用 @Document 注解标记的 PO 类的元信息,我们可以通过它拿到 PO 类的类型和数据表的名字 。
- MongoOperations:MongoTemplate 的实现类,这个我想不用多谈 。
接下来就是最重要的一步,没有这一步一切都是白费,还会造成项目启动失败,那就是把这个新的基类告诉 Spring,这是新的基类,你可以在项目的入口中加上这一句注解:
@EnableMongoRepositories(basePackages = ["com.xxx.*"], repositoryBaseClass = BaseMongoRepositoryClass::class)class AdminApplication?fun main(args: Array<String>) {runApplication<AdminApplication>(*args)}复制代码
指定一下 repositoryBaseClass,这样生成动态代理的时候会以这个类为基类,我们动态代理类也就具有了我们定义的两个方法的能力了,使用中和原来的一样,只不过继承的接口不同罢了:interface UserRepository : BaseMongoRepository<User, String> {?}复制代码
到这一步,我们可以完成这个效果:fun test() {?userRepository.listAll(Criteria.where("account").`is`("admin").and("name").`is`("你的名字"))?}复制代码
3. 实体类变量进行 lambda 封装接下来是对实体变量进行 lambda 封装,这个东西我觉得可以分为 Kotlin 和 Java 两个版本来说,两者各有千秋 。先来说说Kotlin,因为 Kotlin 自身的语言特性的关系,实现起来比较简单,但也会拖一个尾巴,Kotlin 具有一个扩展函数的能力,简单点说就是直接给某个类加上一些自定义方法,比如 String 我们可以在不继承的情况下直接给 String 类加上一个新的方法,然后它就会出现在 String 对象可调用的函数列表中 。
所以我们如果想要 User::account.mongoFiled() 这种效果,就得先知道 User::account 返回值是什么,在 Kotlin 中,它的返回值是一个 KProperty 类对象,那么我们直接给这个类加上扩展如下:
fun KProperty<*>.mongoFiled(): String {if (this.hasAnnotation<Id>()) return "_id"return this.findAnnotation<Field>()?.run {this.name.ifEmpty { this@mongoFiled.name }} ?: this.name}复制代码
这样在 lambda 调用下就可以再调用这个方法了,接着来看看方法内容 。- 首先判断了是否存在 ID 注解,这个 ID 注解是用来标识 Mongo 的主键属性的注解,这种注解标识的变量在数据库中统一叫做 "_id",所以这里我也返回这个名字 。
推荐阅读
- 如何解一元二次方程应用题
- 油价本周四或再迎上调 今晚油价迎来今年第二次下调
- 人在空中为什么不能再跳第二次?
- 第二次世界大战是人类浩劫 第2次世界大战给人类带来的灾难
- 妄想山海云端岳云鲲在哪?
- SpringBoot项目基础设施搭建
- OkHttp完美封装,用一行代码搞定外部请求,使用起来很方便
- 标书封条制作和封装注意事项
- 文艺复兴是什么梗?
- 第二次世界大战两极对峙 第三次世界大战正在酝酿