Kotlin 版 MyBatis-Plus 查询优雅解决方案

Kotlin 版 MyBatis-Plus 查询优雅解决方案

从 Java 切换到 Kotlin 之后,总觉得 MyBatis-Plus 的查询写法还是啰嗦:要么用 KtQueryWrapper 写一长串 User::getName,要么在动态搜索表单里写一堆 if-else 判空,视觉噪音还是大

于是我写了一个扩展库 ------ mybatis-plus-kt ,利用 KProperty1 属性引用,让你用类型安全、接近自然语言的风格写查询,彻底告别字符串和重复判空。

kotlin 复制代码
// 就这样,读起来像说话一样自然
User::name eq "btown"
User::age ge 18
User::role `in` listOf("admin", "dev")

✨ 核心亮点

  • 类型安全User::name 是编译期检查的,再也不会把字段名写错
  • 类自然语言User::age between (18 to 60) 读作"年龄在 18 到 60 之间"
  • 零配置:Spring Boot 自动配置,引入依赖即用
  • 安全模式ktWhereSafe { } 里 null / 空集合自动跳过,零 if-else
  • 无侵入 :复用 QueryWrapper,直接 .selectList() 就能执行

🚀 5 分钟快速上手

1. 引入依赖

Gradle

kotlin 复制代码
implementation("io.github.btown021:mybatis-plus-kt-spring-boot-starter:1.0.1")

Maven

xml 复制代码
<dependency>
    <groupId>io.github.btown021</groupId>
    <artifactId>mybatis-plus-kt-spring-boot-starter</artifactId>
    <version>1.0.1</version>
</dependency>

2. 定义实体与 Service

kotlin 复制代码
@TableName("sys_user")
data class User(
    var name: String = "",
    var age: Int = 0,
    var status: Int = 0,
    var role: String = ""
) : BaseAttr()

interface IUserService : IService<User>
class UserServiceImpl : ServiceImpl<UserMapper, User>(), IUserService

3. 查询就是这么简单

kotlin 复制代码
@Service
class UserBizService(private val userService: IUserService) {

    fun search(name: String?, status: Int?, roleList: List<String>?): List<User> {
        return userService.createQueryWrapper<User>()
        	// 安全模式:自动跳过 null,空集合生成永假条件,between 单端 null 自动降级
            .ktWhereSafe {
                User::name like name             // null 自动跳过
                User::status eq status           // null 自动跳过
                User::role in null				// null 自动跳过
                User::role in enmptyList()       // 转换为生成永假条件 (无匹配)
                User::age between (null to 60)   // 降级为 age <= 60
                User::age between (18 to null)   // 降级为 age >= 18
                User::age between (null to null) // 自动跳过
            }
        	// 普通模式 原生MP行为 不进行null的跳过 降级等
        	.ktWhere {
                User::name like name
                User::status eq status 
            }
            .ktOrder { User::id.orderByDesc }
            .selectList()
    }
}

空集合的智能处理:in 操作遇到空集合时,不能简单跳过(否则会查出全部数据),安全模式会自动生成 1<>1,保证结果为空,更符合业务直觉。notIn 空集合则直接跳过。

不用写一行 if (name != null) { ... },安全模式帮你把所有空判断都处理好了。

🤯 减少 if-else 样板代码 (安全模式)

原生写法:

kotlin 复制代码
val wrapper = QueryWrapper<User>()
if (name != null) wrapper.lambda().like(User::getName, name)
if (status != null) wrapper.lambda().eq(User::getStatus, status)
if (ageMin != null) wrapper.lambda().ge(User::getAge, ageMin)
if (ageMax != null) wrapper.lambda().le(User::getAge, ageMax)
if (!roleList.isNullOrEmpty()) wrapper.lambda().`in`(User::getRole, roleList)

mybatis-plus-kt 写法:

kotlin 复制代码
userService.createQueryWrapper()
    .ktWhereSafe {
        User::name like name
        User::status eq status
        User::age between (ageMin to ageMax)
        User::role in roleList
    }
    .selectList()

代码量直接减半,可读性肉眼可见地提升。

🧩 强大的逻辑组合

支持 and / or / anyOf 等逻辑,复杂条件也写得优雅:

kotlin 复制代码
ktWhere {
    User::status eq 1
    and {
        User::role eq "admin"
        or {
            User::level ge 5
            User::vip eq true
        }
    }
}
// 生成 SQL: WHERE status = 1 AND (role = 'admin' OR level >= 5 OR vip = TRUE)

// anyOf:对同一字段的多候选值 OR 匹配
anyOf(listOf("a", "b", "c")) {
    User::name like it
}
// SQL: WHERE (name LIKE '%a%' OR name LIKE '%b%' OR name LIKE '%c%')

排序、指定返回列也都支持,且保持同样的自然语法:

kotlin 复制代码
.ktOrder { User::status.orderByAsc; User::id.orderByDesc }
.ktSelect(User::id, User::name)

⚙️ 自定义列名映射

默认从 @TableField 读取映射,你也可以实现 ColumnNameProvider 来覆盖:

kotlin 复制代码
override fun resolveFieldColumnMap(): Map<String, String> = mapOf(
    "name" to "user_name"
)

甚至支持运行时动态列名(分表、多租户场景),只需将 isDynamic() 设为 true 即可。

📦 环境

  • Kotlin 2.2+ / JDK 17+
  • MyBatis-Plus 3.5.3+
  • Spring Boot 3.0+

🎯 总结

mybatis-plus-kt 在不改变 MyBatis-Plus 原有使用习惯的前提下,用 Kotlin 特性让查询代码更安全、更简洁,写起来就像说话一样自然。特别适合动态查询多、表单搜索频繁的后台系统。如果你也在用 Kotlin 写 Spring Boot,强烈推荐试一下。

👉 GitHub: github.com/btown021/my... 👉 Gitee: gitee.com/btown/mybat...

(顺手点个 Star 支持一下呗 ⭐)

相关推荐
我命由我123456 小时前
Android 开发问题:java.lang.NoSuchMethodError:No virtual method readAllBytes()
android·java·java-ee·kotlin·android studio·android-studio·android runtime
Kapaseker8 小时前
你是不是还没用过 select?实战 Kotlin select
android·kotlin
plainGeekDev1 天前
synchronized → Coroutines
android·java·kotlin
唐青枫1 天前
Java Gradle 实战指南:从 Wrapper、Kotlin DSL 到 Spring Boot 多模块构建
java·kotlin·gradle
帅次2 天前
Kotlin Flow 与 StateFlow:UI 单向数据流基础
开发语言·ui·kotlin·stateflow·onlifecycle
Kapaseker2 天前
Sequence 一定比 List 快?等等,我们先从基础讲起
android·kotlin
zhangjin11203 天前
Android Studio创建HelloWorld(kotlin版本)
android·kotlin·android studio
怣疯knight3 天前
kotlin安卓应用打包编译卡死的可能原因
android·kotlin
plainGeekDev3 天前
NullPointerException → Kotlin 空安全
android·java·kotlin