网站建设郑州,上海注册公司注册资金,校园二手书交易网站开发,wordpress网站底部版权代码前言
我自己的业务项目#xff0c;先用kotlinspringboot 搭建#xff0c; 发现gradle支持kts脚本#xff0c;于是我就搭建试试。我就选用了最流行的Sqlite内嵌数据库,虽然H2也不错#xff0c;但是Sqlite才是最流行的。orm框架我还是选择了Mybatis-Plus #xff0c;为此中…前言
我自己的业务项目先用kotlinspringboot 搭建 发现gradle支持kts脚本于是我就搭建试试。我就选用了最流行的Sqlite内嵌数据库,虽然H2也不错但是Sqlite才是最流行的。orm框架我还是选择了Mybatis-Plus 为此中间踩了坑。项目支持javakotlin 混合编程 没有配置好Lombok 所以就没有集成了。
整个项目的代码我放在github中了各位可以下载下来看看。
https://github.com/blanexie/vxpt
项目模块结构
项目由两个小模块组成分别是 vxpt-bbs 和 vxpt-tracker
setting.gradle.kts 文件
kts脚本本质还是kotlin代码 不支持单引号字符串。
gradle项目的组织结构文件 选用的是kotlin的kts脚本。 内容如下
rootProject.name vxptinclude(:vxpt-bbs)
include(:vxpt-tracker)
父项目的build.gradle.kts 文件
需要注意的是kotlin的版本和gradle很多插件之间都有兼容关系 版本号要对应上才能使用 因此我只能使用1.5.10版本。 jdk使用的是11版本。
plugins {id(org.springframework.boot) version 2.5.0id(io.spring.dependency-management) version 1.0.11.RELEASEkotlin(jvm) version 1.5.10kotlin(plugin.spring) version 1.5.10id(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.withTypeorg.jetbrains.kotlin.gradle.tasks.KotlinCompile {kotlinOptions {freeCompilerArgs listOf(-Xjsr305strict)jvmTarget 11}}tasks.withTypeTest {useJUnitPlatform()}
}vxpt-bbs的子模块的build.gradle.kts文件
这里需要注意noArg的配置是为了解决Mybtatis需要的对象的无参构造方法的问题。这个问题官方有解决方案但是都是gradle的Groovy的脚本配置 为此我各种尝试才改成kts脚本的方式。
group com.github.blanexie.vxpt.bbs
version 0.0.1plugins {}// 必需的为了解决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方案配置无法成功放弃。JavaKotlin 混合方案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.LocalDateTimeTableName(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.CharsetConfiguration
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 ArrayListMediaType()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.StdOutImplUserMapper和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.ResourceRestController
RequestMapping(/api/user)
class UserController {//使用lateinit关键字的方式可以直接注入对象也可以使用UserController的构造方法的方式注入对象Resourcelateinit var userMapper: UserMapperGetMapping(/login)fun login(): WebResp {var userDO UserDO(12, 12vxpt, 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调用如下