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…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
