[ Spring ] Spring Boot Mybatis++ 2025

文章目录

          • Structure
          • MyBatis++ Controller Abilities
          • Configure Plugins and Repositories
          • Apply Plugins and Add Dependencies
          • MyBatis++ Spring Properties
          • MyBatis++ Application
          • MyBatis++ Beans
          • MyBatis++ Mapper
          • MyBatis++ Query Builder

Structure

this blog introduce 3 ways using mybatis

  • based on annotationed SQL and Query interfaces : suppored by MyBatis framework

  • based on Query Wrapper : supported by MyBatis Plus framework

    MyBatis Plus provides a easier way to dynamically set condition and updated fields

  • base on Query Condition : combined MyBatis Plus and Kotlin, so called MyBatis++

    MyBatis++ provides a more easier way to build complicated conditions

    and supports update values through an Example bean

MyBatis++ Controller Abilities

this controller present multiple ways to do CURD with MyBatis++

you can choose your favorite ones or those match your current project most comfortably

package x.spring.hello.controllerimport org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import x.kotlin.commons.serialize.JSON.toJson
import x.kotlin.commons.serialize.JSON.toJsonOrNull
import x.kotlin.commons.string.UUID
import x.spring.hello.model.User
import x.spring.hello.model.UserExample
import x.spring.hello.repository.UserMapper
import x.spring.hello.mybatis.*@RestController
class UserController {@Autowiredprivate lateinit var userMapper: UserMapper@GetMapping("/01")fun selectAll(): String {val userList = userMapper.selectAll()return userList.toJson()}@GetMapping("/02")fun selectByName(): String {val user = userMapper.selectUserByName("Jimmy")return user.toJsonOrNull().orEmpty()}@GetMapping("/03")fun selectByCondition(): String {val condition = condition { it.eq(User::name, "Jimmy") }val users = userMapper.selectList(condition.build())return users.toJson()}@GetMapping("/04")fun insert(): String {val user = User()user.name = UUID.short()userMapper.insert(user)return user.toJson()}@GetMapping("/05")fun insertOrUpdate(): String {val user = User()user.id = "1"user.name = UUID.short()userMapper.insertOrUpdate(user)return user.toJson()}@GetMapping("/06")fun updateByCondition(): String {val cond1 = condition { it.isNotNull(User::id) }val cond2 = condition { it.eq(User::name, "Jimmy") }val cond3 = condition { it.gt(User::age, 15) }val cond4 = condition {it.set(User::name, "Jimmy")it.set(User::age, 18)}val condition = cond1 and cond2 and cond3 attributes cond4val count = userMapper.update(condition.build())return count.toJson()}@GetMapping("/07")fun updateByEntityAndCondition(): String {val entity = User()entity.name = "Updated"entity.age = 36val cond1 = condition { it.isNotNull(User::id) }val cond2 = condition { it.like(User::name, "Jimmy") }val cond3 = condition { it.gt(User::age, 35) }val condition = cond1 and (cond2 or cond3)val count = userMapper.update(entity, condition.build())return count.toJson()}@GetMapping("/08")fun updateByExampleAndCondition(): String {val example = UserExample()example.age = 18val cond1 = condition { it.isNotNull(User::id) }val cond2 = condition { it.like(User::name, "Jimmy") }val cond3 = condition { it.gt(User::age, 35) }val condition = cond1 and (cond2 or cond3) values exampleval count = userMapper.update(condition.build())return count.toJson()}@GetMapping("/09")fun selectCrossTables(): String {val userRoles = userMapper.selectUserRole()return userRoles.toJson()}
}
Configure Plugins and Repositories
pluginManagement {repositories {gradlePluginPortal()google()mavenCentral()}
}dependencyResolutionManagement {repositoriesMode = RepositoriesMode.PREFER_SETTINGSrepositories {gradlePluginPortal()google()mavenCentral()}
}buildscript {repositories {gradlePluginPortal()google()mavenCentral()}
}plugins {id("org.jetbrains.kotlin.jvm") version "2.0.21" apply falseid("org.jetbrains.kotlin.kapt") version "2.0.21" apply falseid("org.jetbrains.kotlin.plugin.spring") version "2.0.21" apply falseid("org.springframework.boot") version "3.4.1" apply false
}include("spring-mybatis")
Apply Plugins and Add Dependencies
plugins {id("org.jetbrains.kotlin.jvm")id("org.jetbrains.kotlin.kapt")id("org.jetbrains.kotlin.plugin.spring")id("org.springframework.boot")
}java {toolchain {languageVersion = JavaLanguageVersion.of(17)}
}dependencies {val springBootVersion = "3.4.1"val springCloudVersion = "4.2.0"val springCloudAlibabaVersion = "2023.0.3.2"// commonsapi("io.github.hellogoogle2000:kotlin-commons:1.0.19")// kotlinapi("org.jetbrains.kotlin:kotlin-reflect:2.0.21")// springapi("org.springframework.boot:spring-boot-starter:$springBootVersion")api("org.springframework.boot:spring-boot-starter-web:$springBootVersion")api("org.springframework.cloud:spring-cloud-starter-bootstrap:$springCloudVersion")// mybatisapi("link.thingscloud:quick-spring-boot-starter-mybatis-plus:2025.01.22")
}
MyBatis++ Spring Properties
# service
server.port=10003
spring.application.name=mybatis
spring.profiles.active=dev
spring.devtools.add-properties=false
# mybatis
spring.datasource.username=root
spring.datasource.password=123456789
spring.datasource.url=jdbc:mysql://localhost:3306/dev?characterEncoding=utf-8&serverTimezone=UTC
MyBatis++ Application
package x.spring.helloimport org.mybatis.spring.annotation.MapperScan
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication@SpringBootApplication
@MapperScan(basePackages = ["x.spring.hello.repository"])
class MybatisApplicationfun main(args: Array<String>) {runApplication<MybatisApplication>(*args)
}
MyBatis++ Beans
package x.spring.hello.modelimport com.baomidou.mybatisplus.annotation.IdType
import com.baomidou.mybatisplus.annotation.TableIdclass User {@TableId(type = IdType.ASSIGN_UUID)var id = ""var name = ""var age = 0
}
package x.spring.hello.modelclass UserExample {var id: String? = nullvar name: String? = nullvar age: Int? = null
}
package x.spring.hello.modelclass UserRoleQueryResult {var name = ""var role = ""
}
MyBatis++ Mapper

mapper sometimes called interface, service or repository in other projects

package x.spring.hello.repositoryimport link.thingscloud.quick.mybatisplus.base.BaseMapper
import org.apache.ibatis.annotations.Select
import x.spring.hello.model.User
import x.spring.hello.model.UserRoleQueryResultinterface UserMapper : BaseMapper<User> {@Select("select * from user")fun selectAll(): MutableList<User>@Select("select * from user where name = #{name}")fun selectUserByName(name: String): User?@Select("""select user.name as name,role.name as role from user left join roleon user.roleId = role.id""")fun selectUserRole(): List<UserRoleQueryResult>
}
MyBatis++ Query Builder

this is the core component to build query condition and examples

difference between entity and example is :

entity will update all field, while example only update non-null fields

package x.spring.hello.mybatisimport com.baomidou.mybatisplus.extension.kotlin.KtUpdateWrapper
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberPropertiesfun interface ConditionConfigurator<T : Any> {fun configure(wrapper: KtUpdateWrapper<T>)
}data class QueryCondition<T : Any>(val configurator: ConditionConfigurator<T>
)inline fun <reified T : Any> QueryCondition<T>.build(): KtUpdateWrapper<T> {val wrapper = KtUpdateWrapper(T::class.java)configurator.configure(wrapper)return wrapper
}inline fun <reified T : Any> condition(configurator: ConditionConfigurator<T>): QueryCondition<T> {return QueryCondition(configurator)
}infix fun <T : Any> QueryCondition<T>.and(other: QueryCondition<T>): QueryCondition<T> {val configurator = ConditionConfigurator {configurator.configure(it)it.and { other.configurator.configure(it) }}return QueryCondition(configurator)
}infix fun <T : Any> QueryCondition<T>.or(other: QueryCondition<T>): QueryCondition<T> {val configurator = ConditionConfigurator {configurator.configure(it)it.or { other.configurator.configure(it) }}return QueryCondition(configurator)
}infix fun <T : Any> QueryCondition<T>.not(other: QueryCondition<T>): QueryCondition<T> {val configurator = ConditionConfigurator {configurator.configure(it)it.not { other.configurator.configure(it) }}return QueryCondition(configurator)
}infix fun <T : Any> QueryCondition<T>.attributes(other: QueryCondition<T>): QueryCondition<T> {val configurator = ConditionConfigurator {configurator.configure(it)other.configurator.configure(it)}return QueryCondition(configurator)
}inline infix fun <reified T : Any, reified S : Any> QueryCondition<T>.values(example: S): QueryCondition<T> {val configurator = ConditionConfigurator { wrapper ->configurator.configure(wrapper)val properties = S::class.memberPropertiesproperties.forEach { propertyS ->val value = propertyS.get(example)value.takeIf { it != null } ?: return@forEachval property = T::class.findPropertyByName(propertyS.name)property.takeIf { it != null } ?: return@forEachwrapper.set(property, value)}}return QueryCondition(configurator)
}inline fun <reified T : Any> KClass<T>.findPropertyByName(name: String): KProperty1<T, *>? {return memberProperties.firstOrNull { it.name == name }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/69024.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

请解释 Java 中的 IO 和 NIO 的区别,以及 NIO 如何实现多路复用?

Java中的IO和NIO是两种不同的输入输出处理方式&#xff0c;它们在设计理念、实现方式、性能特点和应用场景上有着显著的差异。 下面我将详细解释Java中的IO和NIO的区别&#xff0c;以及NIO如何实现多路复用&#xff0c;并提供一些日常开发中的使用建议和注意事项。 Java中的I…

防火墙安全策略配置实验

一.实验拓扑&#xff1a; 二.实验需求&#xff1a; 1.vlan 2 属于办公区&#xff1b; vlan 3 属于生产区 2.办公区PC在工作日时间&#xff08;早8晚6&#xff09;可以正常访问OA server&#xff0c;其他时间不允许 3.办公区PC可以在任意时间访问Web server 4.生产区PC可以…

Redis入门概述

1.1、Redis是什么 Redis&#xff1a;官网 高性能带有数据结构的Key-Value内存数据库 Remote Dictionary Server&#xff08;远程字典服务器&#xff09;是完全开源的&#xff0c;使用ANSIC语言编写遵守BSD协议&#xff0c;例如String、Hash、List、Set、SortedSet等等。数据…

【C++篇】哈希表

目录 一&#xff0c;哈希概念 1.1&#xff0c;直接定址法 1.2&#xff0c;哈希冲突 1.3&#xff0c;负载因子 二&#xff0c;哈希函数 2.1&#xff0c;除法散列法 /除留余数法 2.2&#xff0c;乘法散列法 2.3&#xff0c;全域散列法 三&#xff0c;处理哈希冲突 3.1&…

ubuntu22.04(GUN)安装蓝牙驱动

Ubuntu上安装和配置蓝牙驱动 1. 检查蓝牙硬件是否被识别 首先&#xff0c;打开终端&#xff08;Ctrl Alt T&#xff09;并运行&#xff1a; lsusb或 lspci看看是否有蓝牙设备被识别。如果找不到蓝牙设备&#xff0c;可能是硬件问题或者蓝牙被禁用。 2. 检查蓝牙服务是否…

基于RTOS的STM32游戏机

1.游戏机的主要功能 所有游戏都来着B站JL单片机博主开源 这款游戏机具备存档与继续游戏功能&#xff0c;允许玩家在任何时候退出当前游戏并保存进度&#xff0c;以便日后随时并继续之前的冒险。不仅如此&#xff0c;游戏机还支持多任务处理&#xff0c;玩家可以在退出当前游戏…

优选算法的灵动之章:双指针专题(一)

个人主页&#xff1a;手握风云 专栏&#xff1a;算法 目录 一、双指针算法思想 二、算法题精讲 2.1. 查找总价格为目标值的两个商品 2.2. 盛最多水的容器 ​编辑 2.3. 移动零 2.4. 有效的三角形个数 一、双指针算法思想 双指针算法主要用于处理数组、链表等线性数据结构…

ROS应用之SwarmSim在ROS 中的协同路径规划

SwarmSim 在 ROS 中的协同路径规划 前言 在多机器人系统&#xff08;Multi-Robot Systems, MRS&#xff09;中&#xff0c;SwarmSim 是一个常用的模拟工具&#xff0c;可以对多机器人进行仿真以实现复杂任务的协同。除了任务分配逻辑以外&#xff0c;SwarmSim 在协同路径规划方…

MVC、MVP和MVVM模式

MVC模式中&#xff0c;视图和模型之间直接交互&#xff0c;而MVP模式下&#xff0c;视图与模型通过Presenter进行通信&#xff0c;MVVM则采用双向绑定&#xff0c;减少手动同步视图和模型的工作。每种模式都有其优缺点&#xff0c;适合不同规模和类型的项目。 ### MVVM 与 MVP…

【BUUCTF杂项题】后门查杀、webshell后门

前言&#xff1a;Webshell 本质上是一段可在 Web 服务器上执行的脚本代码&#xff0c;通常以文件形式存在于 Web 服务器的网站目录中。黑客通过利用 Web 应用程序的漏洞&#xff0c;如 SQL 注入、文件上传漏洞、命令执行漏洞等&#xff0c;将 Webshell 脚本上传到服务器&#x…

Spring中@Conditional注解详解:条件装配的终极指南

一、为什么要用条件装配&#xff1f; 在实际开发中&#xff0c;我们经常需要根据不同的运行环境、配置参数或依赖情况动态决定是否注册某个Bean。例如&#xff1a; 开发环境使用内存数据库&#xff0c;生产环境连接真实数据库 当存在某个类时才启用特定功能 根据配置文件开关…

【CPP】迭代器失效问题 static和inline

文章目录 迭代器失效**常见的迭代器失效场景**1. **std::vector**2. **std::deque**3. **std::list**4. **std::map / std::set**5. **std::unordered_map / std::unordered_set** **总结&#xff1a;迭代器失效场景****如何避免迭代器失效&#xff1f;** static 和 inline1. s…

visual studio安装

一、下载Visual Studio 访问Visual Studio官方网站。下载 Visual Studio Tools - 免费安装 Windows、Mac、Linux 在主页上找到并点击“下载 Visual Studio”按钮。 选择适合需求的版本&#xff0c;例如“Visual Studio Community”&#xff08;免费版本&#xff09;&#x…

conda配置channel

你收到 CondaKeyError: channels: value https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main not present in config 错误是因为该镜像源&#xff08;https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main&#xff09;可能没有被正确添加到 Conda 的配置文件中&…

Windows编译FreeRDP步骤

1. **安装必要工具** powershell # 安装 Visual Studio 2022 (勾选"C桌面开发"组件) # 安装 CMake: https://cmake.org/download/ # 安装 Git: https://git-scm.com/ 2. **安装依赖项** powershell # 使用vcpkg包管理 git clone https://github.com/Microsoft/vcpk…

Fortunately 和 luckily区别

Fortunately 和 luckily 的确是同义词&#xff0c;都表示“幸运地”&#xff0c;用于描述某件事发生得很幸运&#xff0c;带有积极、正面的含义。然而&#xff0c;尽管它们的意思相近&#xff0c;fortunately 和 luckily 在使用上有一些细微的差别。 1. 含义相似 Fortunately…

【C语言深入探索】:指针高级应用与极致技巧(二)

目录 一、指针与数组 1.1. 数组指针 1.2. 指向多维数组的指针 1.2.1. 指向多维数组元素的指针 1.2.2. 指向多维数组行的指针 1.3. 动态分配多维数组 1.4. 小结 二、指针与字符串 2.1. 字符串表示 2.2. 字符串处理函数 2.3. 代码示例 2.4. 注意事项 三、指针与文件…

基于开源AI智能名片2 + 1链动模式S2B2C商城小程序源码在抖音招商加盟中的应用与创新

摘要&#xff1a;本文深入探讨了在短视频蓬勃发展的时代背景下&#xff0c;招商加盟领域借助抖音平台所具备的独特优势。同时&#xff0c;全面剖析开源AI智能名片2 1链动模式S2B2C商城小程序源码这一创新工具&#xff0c;详细阐述其如何与抖音招商加盟深度融合&#xff0c;助力…

pthread_cond_broadcast的概念和使用案例

pthread_cond_broadcast 是 POSIX 线程&#xff08;Pthreads&#xff09;库中用于条件变量&#xff08;Condition Variable&#xff09;操作的函数&#xff0c;定义在 <pthread.h> 头文件中。它的核心作用是唤醒所有等待在某个条件变量上的线程&#xff0c;通常用于多线程…

爬虫学习笔记之Robots协议相关整理

定义 Robots协议也称作爬虫协议、机器人协议&#xff0c;全名为网络爬虫排除标准&#xff0c;用来告诉爬虫和搜索引擎哪些页面可以爬取、哪些不可以。它通常是一个叫做robots.txt的文本文件&#xff0c;一般放在网站的根目录下。 robots.txt文件的样例 对有所爬虫均生效&#…