SpringBoot + kotlin/java + Mybatis-Plus +Sqlite + Gradle多模块项目
前言
- 我自己的业务项目,先用kotlin+springboot 搭建, 发现gradle支持kts脚本,于是我就搭建试试。
- 我就选用了最流行的Sqlite内嵌数据库,虽然H2也不错,但是Sqlite才是最流行的。
- orm框架我还是选择了Mybatis-Plus ,为此中间踩了坑。
- 项目支持java+kotlin 混合编程, 没有配置好Lombok, 所以就没有集成了。
整个项目的代码我放在github中了,各位可以下载下来看看。
https://github.com/blanexie/vxpt
项目模块结构
项目由两个小模块组成,分别是 vxpt-bbs 和 vxpt-tracker

setting.gradle.kts 文件
kts脚本本质还是kotlin代码, 不支持单引号字符串。
gradle项目的组织结构文件, 选用的是kotlin的kts脚本。 内容如下:
rootProject.name = "vxpt"include(":vxpt-bbs")
include(":vxpt-tracker")
父项目的build.gradle.kts 文件
需要注意的是kotlin的版本和gradle很多插件之间都有兼容关系, 版本号要对应上才能使用, 因此我只能使用1.5.10版本。 jdk使用的是11版本。
plugins {id("org.springframework.boot") version "2.5.0"id("io.spring.dependency-management") version "1.0.11.RELEASE"kotlin("jvm") version "1.5.10"kotlin("plugin.spring") version "1.5.10"id("org.jetbrains.kotlin.plugin.noarg") version "1.4.20"
}repositories {mavenLocal()maven {setUrl("https://maven.aliyun.com/nexus/content/groups/public/")}mavenCentral()
}subprojects {apply(plugin = "java")apply(plugin = "kotlin")apply(plugin = "idea")apply(plugin = "org.springframework.boot")apply(plugin = "io.spring.dependency-management")apply(plugin = "org.jetbrains.kotlin.plugin.spring")apply(plugin = "org.jetbrains.kotlin.jvm")apply(plugin = "org.jetbrains.kotlin.plugin.noarg")repositories {mavenLocal()maven {setUrl("https://maven.aliyun.com/nexus/content/groups/public/")}mavenCentral()}java.sourceCompatibility = JavaVersion.VERSION_11configurations {compileOnly {extendsFrom(configurations.annotationProcessor.get())}}dependencies {implementation("org.springframework.boot:spring-boot-starter-web")implementation("com.fasterxml.jackson.module:jackson-module-kotlin")implementation("org.jetbrains.kotlin:kotlin-reflect")implementation("org.jetbrains.kotlin:kotlin-stdlib")developmentOnly("org.springframework.boot:spring-boot-devtools")annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")testImplementation("org.springframework.boot:spring-boot-starter-test")}tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {kotlinOptions {freeCompilerArgs = listOf("-Xjsr305=strict")jvmTarget = "11"}}tasks.withType<Test> {useJUnitPlatform()}
}
vxpt-bbs的子模块的build.gradle.kts文件
- 这里需要注意noArg的配置,是为了解决Mybtatis需要的对象的无参构造方法的问题。这个问题官方有解决方案,但是都是gradle的Groovy的脚本配置, 为此我各种尝试,才改成kts脚本的方式。
group = "com.github.blanexie.vxpt.bbs"
version = "0.0.1"plugins {}// 必需的,为了解决kotlin数据类无参构造方法的问题,
noArg {"com.baomidou.mybatisplus.annotation.TableName"
}dependencies {implementation("org.xerial:sqlite-jdbc:3.21.0.1")implementation("com.baomidou:mybatis-plus-boot-starter:3.5.0")implementation("org.mybatis:mybatis-typehandlers-jsr310:1.0.2")implementation("com.alibaba:fastjson:2.0.23")
}
Mybatis数据对象
这里由于Mybatis的无参构造方法的问题,使用都报找不到UserDO的无参构造方法错误, 为此我尝试了多种方案,尝试方案如下:
- Spring的allOpen方案,配置无效,应该还是kts脚本的问题
- Lombok方案,配置无法成功,放弃。
- Java+Kotlin 混合方案,UserDO使用Java编写。 这个方案刚开始都无法编译Java类,尝试好久最后发现是我把
java代码写在src/main/kotlin目录下了,导致无法识别, 最后我把所有代码都放入src/main/java目录下才成功,src/main/java目录可以识别kotlin代码和java代码,但是src/main/kotlin目录只能识别kotlin代码。 - Kotlin官方的noArg方案,刚开始也无法成功,计划要使用混合编程方案, 最后改了下配置成功了,官方教程中只有Groovy脚本,无kts脚本,我自己尝试出来的。
package com.github.blanexie.vxpt.bbs.user.meta.entityimport com.baomidou.mybatisplus.annotation.IdType
import com.baomidou.mybatisplus.annotation.TableId
import com.baomidou.mybatisplus.annotation.TableName
import java.time.LocalDateTime@TableName("user")
class UserDO(@TableId(type = IdType.AUTO)var id: Long?,var email: String,var nickName: String,var password: String,var coverImg: String?,var role: String,var sex: Int,var status: Int,var createTime: LocalDateTime,var updateTime: LocalDateTime,
) {
}
Mybtatis的数据对象的LocalDateTime序列化问题
LocalDateTime 是java8出来的时间对象,用于替换性能不好的Date类, 按理来说早就应该支持了, 但是我引入的最新的Mybatis-Plus包中的Mybatis就是无法识别,我尝试的解决方案如下:
- 自定义TypeHandler方案, 尝试到一半放弃,因为发现更好的方案, 但是这个方案应该也是行的通的
- 引入Mybatis的补丁包,
implementation("org.mybatis:mybatis-typehandlers-jsr310:1.0.2")
Http的HttpMessageConverters转换器
这个是在对象放回给浏览器端的时候,json序列化对象的设置类,我选用了fastjson,虽然他安全系数不高,但是他API好用啊,我业务项目,无所谓。 配置如下:
package com.github.blanexie.vxpt.bbs.util.configimport com.alibaba.fastjson.serializer.SerializeConfig
import com.alibaba.fastjson.serializer.SerializerFeature
import com.alibaba.fastjson.serializer.ToStringSerializer
import com.alibaba.fastjson.support.config.FastJsonConfig
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
import org.springframework.boot.autoconfigure.http.HttpMessageConverters
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.http.MediaType
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
import java.math.BigInteger
import java.nio.charset.Charset@Configuration
@ConditionalOnClass(WebMvcConfigurer::class)
@Order(Ordered.HIGHEST_PRECEDENCE)
open class WebConfig : WebMvcConfigurer {constructor() : super()@Beanopen fun customConverters(): HttpMessageConverters {//创建fastJson消息转换器var fastJsonConverter = FastJsonHttpMessageConverter()//创建配置类var fastJsonConfig = FastJsonConfig()//修改配置返回内容的过滤fastJsonConfig.setSerializerFeatures(// 格式化SerializerFeature.PrettyFormat,// 可解决long精度丢失 但会有带来相应的中文问题//SerializerFeature.BrowserCompatible,// 消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)SerializerFeature.DisableCircularReferenceDetect,// 是否输出值为null的字段,默认为falseSerializerFeature.WriteMapNullValue,// 字符类型字段如果为null,输出为"",而非nullSerializerFeature.WriteNullStringAsEmpty,// List字段如果为null,输出为[],而非nullSerializerFeature.WriteNullListAsEmpty)// 日期格式fastJsonConfig.dateFormat = "yyyy-MM-dd HH:mm:ss"// long精度问题var serializeConfig = SerializeConfig.globalInstanceserializeConfig.put(Integer::class.java, ToStringSerializer.instance)serializeConfig.put(BigInteger::class.java, ToStringSerializer.instance)serializeConfig.put(Long::class.java, ToStringSerializer.instance)serializeConfig.put(Long::class.javaObjectType, ToStringSerializer.instance)fastJsonConfig.setSerializeConfig(serializeConfig)//处理中文乱码问题var fastMediaTypes = ArrayList<MediaType>()fastMediaTypes.add(MediaType.APPLICATION_JSON)fastMediaTypes.add(MediaType(MediaType.TEXT_HTML, Charset.forName("UTF-8")))fastMediaTypes.add(MediaType(MediaType.TEXT_PLAIN, Charset.forName("UTF-8")))fastMediaTypes.add(MediaType(MediaType.APPLICATION_FORM_URLENCODED, Charset.forName("UTF-8")))fastMediaTypes.add(MediaType.MULTIPART_FORM_DATA)fastJsonConverter.setSupportedMediaTypes(fastMediaTypes)fastJsonConverter.setFastJsonConfig(fastJsonConfig)//将fastjson添加到视图消息转换器列表内return HttpMessageConverters(fastJsonConverter)}
}
Sqlite配置问题
- Sqlite使用很方便,只要使用DBeaver工具创建一个sqlite数据,建好边,最后把数据库文件复制到resource目录下,就能直接使用了。
- Sqlite是内嵌数据库,会充分使用内存的,不用考虑数据库链接池(druid)等,并且druid还有一些配置不兼容sqlite, 所以我直接使用了默认的HikariPool连接池。
配置目录截图如下:

配置文件内容如下:
# Tomcat
server:port: 8899#spring
spring:profiles:active: devdatasource:#引用项目中的数据库文件driver-class-name: org.sqlite.JDBCurl: jdbc:sqlite::resource:sqlite/bbs.dbusername:password:#mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
UserMapper和UserController类如下
- UserMapper按照说明文档来,没有啥问题
- UserController类有个依赖注入的问题。 依赖注入有多种方式,我选择了
lateinit var的方式
package com.github.blanexie.vxpt.bbs.user.controllerimport com.github.blanexie.vxpt.bbs.user.dao.UserMapper
import com.github.blanexie.vxpt.bbs.user.meta.entity.UserDO
import com.github.blanexie.vxpt.bbs.util.WebResp
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime
import javax.annotation.Resource@RestController
@RequestMapping("/api/user")
class UserController {//使用lateinit关键字的方式可以直接注入对象,也可以使用UserController的构造方法的方式注入对象@Resourcelateinit var userMapper: UserMapper@GetMapping("/login")fun login(): WebResp {var userDO = UserDO(12, "12@vxpt", "12vxpt", "sagsdg", "https://21gsfsa", "user", 1, 1, LocalDateTime.now(), LocalDateTime.now())userMapper.insert(userDO)return WebResp.success(userDO)}@GetMapping("/logout")fun logout(): WebResp {var selectById = userMapper.selectById(12)return WebResp.success(selectById)}@GetMapping("/register")fun register(): WebResp {return WebResp.success()}}
启动截图
启动控制台如下:

postman调用如下:

相关文章:
SpringBoot + kotlin/java + Mybatis-Plus +Sqlite + Gradle多模块项目
前言 我自己的业务项目,先用kotlinspringboot 搭建, 发现gradle支持kts脚本,于是我就搭建试试。我就选用了最流行的Sqlite内嵌数据库,虽然H2也不错,但是Sqlite才是最流行的。orm框架我还是选择了Mybatis-Plus ,为此中…...
Docker 容器与容器云读书笔记(一)
最近都没时间看书,闲暇之余看看书,写写笔记,记录一下这难得的时光。 docker容器的出现 2013年初, 一个名字从云计算领域横空出世,并在整个IT行业激起千层浪,这就是Docker。Docker选择容器作为核心和基础&…...
软件设计(九)
软件设计(八)https://blog.csdn.net/ke1ying/article/details/128954569?spm1001.2014.3001.5501 81、模块A将学生信息,即学生姓名、学号、手机等放到一个结构体系中,传递给模块B,模块A和B之间的耦合类型为 什么耦合…...
FoveaBox原理与代码解析
paper:FoveaBox: Beyond Anchor-based Object Detectorcode:https://github.com/taokong/FoveaBox背景基于anchor的检测模型需要仔细设计anchor,常用方法之一是根据特定数据集的统计结果确定anchor的number、scale、ratio等,但这种…...
Linux内核启动(1,0.11版本)启动BIOS与加载内核
从电源到启动BIOS 从我们按下启动电源到BIOS,按下电源–>主板会向电源组发出信号–> 接受到信号后,当主板收到电源正常启动信号后,主板会启动CPU(CPU重置所有寄存器数据,并且初始化数据),比如32位系统ÿ…...
python制作贪吃蛇小游戏,畅玩无限制
前言 大家早好、午好、晚好吖 ❤ ~ 现在这年头,无论玩个什么游戏都有健康机制, 这让我们愉悦玩游戏得步伐变得承重起来, 于是无聊之下我写了个贪吃蛇小游戏,来玩个快乐 代码展示 导入模块 import random import sys import …...
MySQL-InnoDB数据页结构浅析
在MySQL-InnoDB行格式浅析中,们简单提了一下 页 的概念,它是 InnoDB 管理存储空间的基本单位,一个页的大小一般是 16KB 。 InnoDB 为了不同的目的而设计了许多种不同类型的 页: 存放表空间头部信息的页存放 Insert Buffer信息的…...
Java、JSP职工人事管理系统设计与实现
技术:Java、JSP等摘要:现在随着我们这个社会的计算机技术的快速发展,计算机在企业管理中得到普遍的应用,现在我们利用计算机在实现企业职工的管理越来越重要。当今社会是快速发展的信息社会,自动化信息的作用也变得越来…...
数据结构与算法这么难,为什么我们还要学习?
文章目录前言1. 数据结构与算法是什么?2. 为什么数据结构与算法很难?3. 如何系统学习数据结构与算法?🍑 复杂度🍑 线性表🍑 树形结构🍑 图🍑 排序🍑 字符串🍑…...
剑指 Offer 52. 两个链表的第一个公共节点
摘要 剑指 Offer 52. 两个链表的第一个公共节点 一、双指针解法 使用双指针的方法,可以将空间复杂度降至 O(1)。只有当链表 headA headB都不为空时,两个链表才可能相交。因此首先判断链表 headA和 headB是否为空,如果其中至少有一个链表为…...
可以写进简历的软件测试电商项目,不进来get一下?
前言 说实话,在找项目的过程中,我下载过(甚至付费下载过)N多个项目、联系过很多项目的作者,但是绝大部分项目,在我看来,并不适合你拿来练习,它们或多或少都存在着“问题”ÿ…...
蓝桥杯-算法-印章问题
这个题真的顶啊!思路:n种图案,m张印章,每一个图案的概率是1/n,这个概率以后用P表示首先我们定义dp[i][j]是买了i张印章(对应于上面的m),凑齐j种图案的概率(对应于上面的n…...
戴尔游匣G16电脑U盘安装系统操作教程分享
戴尔游匣G16电脑U盘安装系统操作教程分享。有用户在使用戴尔游匣G16电脑的时候遇到了系统问题,比如电脑蓝屏、自动关机重启、驱动不兼容等问题。遇到这些问题如果无法进行彻底解决,我们可以通过U盘重新安装系统的方法来解决,因为这些问题一般…...
2023数学建模美赛赛题思路分析 2023美赛 美国大学生数学建模数模
将在本帖更新2023美国大学生数学建模数模美赛各个赛题思路,大家可以点赞收藏! 一、参赛报名 组队参赛(每队人数3人,专业不限)。 二、赛题思路及资料 会在本帖更新思路分析,Q群可领取模型代码/赛题思路资料…...
vue3与vue2的对比
Vue 3.0 和 Vue 2.0 是 Vue 前端框架的两个主要版本,它们有着不同的更新和优化: Vue 3.0 主要更新内容: 采用 TypeScript 作为开发语言,提高了代码的类型安全性。 速度更快,内存使用更少,支持大规模数据处…...
史上最全软件测试工程师常见的面试题总结(百度、oppo、中软国际、华为)备战金三银四
1、面试:神州数码1.介绍你下你项目中一个自动化实现的流程2.你觉得做自动化的意义在哪里 >需要对之前已经实现的功能进行回归测试、保证当前版本更新的内容不能影响到之前已经实现好的功能3.你们做自动化产生了什么结果 >测试报告、报错截图和报错日志、测试报…...
“深度学习”学习日记。卷积神经网络--用CNN的实现MINIST识别任务
2023.2.11 通过已经实现的卷积层和池化层,搭建CNN去实现MNIST数据集的识别任务; 一,简单CNN的网络构成: 代码需要在有网络的情况下运行,因为会下载MINIST数据集,运行后会生成params.pkl保留训练权重&…...
JavaWeb--JDBC练习
JDBC练习5.1 需求5.2 案例实现5.2.1 环境准备5.2.2 查询所有5.2.3 添加数据5.2.4 修改数据5.2.5 删除数据5.1 需求 完成商品品牌数据的增删改查操作 查询:查询所有数据添加:添加品牌修改:根据id修改删除:根据id删除 5.2 案例实…...
【LeetCode】2335. 装满杯子需要的最短总时长
2335. 装满杯子需要的最短总时长 题目描述 现有一台饮水机,可以制备冷水、温水和热水。每秒钟,可以装满 2 杯 不同 类型的水或者 1 杯任意类型的水。 给你一个下标从 0 开始、长度为 3 的整数数组 amount ,其中 amount[0]、amount[1] 和 a…...
Android 12.0 通过驱动实现禁用usb鼠标和usb键盘功能
1.1概述 在12.0的系统产品定制化开发中,在进行定制中有关于usb键盘和usb鼠标的需求中,产品要求禁止usb口挂载usb鼠标和usb键盘,所以需要要求在usb挂载类型的时候 判断如果是usb鼠标和usb键盘就不让挂载,这就需要从驱动方面入手来解决这个问题,接下来看下驱动的某些挂载usb…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
