当前位置: 首页 > news >正文

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-bbsvxpt-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调用如下:
在这里插入图片描述

http://www.lryc.cn/news/3254.html

相关文章:

  • Docker 容器与容器云读书笔记(一)
  • 软件设计(九)
  • FoveaBox原理与代码解析
  • Linux内核启动(1,0.11版本)启动BIOS与加载内核
  • python制作贪吃蛇小游戏,畅玩无限制
  • MySQL-InnoDB数据页结构浅析
  • Java、JSP职工人事管理系统设计与实现
  • 数据结构与算法这么难,为什么我们还要学习?
  • 剑指 Offer 52. 两个链表的第一个公共节点
  • 可以写进简历的软件测试电商项目,不进来get一下?
  • 蓝桥杯-算法-印章问题
  • 戴尔游匣G16电脑U盘安装系统操作教程分享
  • 2023数学建模美赛赛题思路分析 2023美赛 美国大学生数学建模数模
  • vue3与vue2的对比
  • 史上最全软件测试工程师常见的面试题总结(百度、oppo、中软国际、华为)备战金三银四
  • “深度学习”学习日记。卷积神经网络--用CNN的实现MINIST识别任务
  • JavaWeb--JDBC练习
  • 【LeetCode】2335. 装满杯子需要的最短总时长
  • Android 12.0 通过驱动实现禁用usb鼠标和usb键盘功能
  • C++入门——内存管理
  • MySQL-InnoDB行格式浅析
  • AXI 总线协议学习笔记(4)
  • C++复习笔记6
  • 指针的步长及意义(C语言基础)
  • SpringMVC:统一异常处理(11)
  • SpringBoot的配置与使用
  • 【Python】tkinter messagebox练习笔记
  • 2022年12月电子学会Python等级考试试卷(五级)答案解析
  • 计算机网络自定向下 -- 浅谈可靠性之rdt协议
  • 制造业升级转型:制造业上市公司-智能制造词频统计数据集