springboot kotlin改造

552 阅读2分钟

最近在学习kotlin语法,发现了很多有意思的语法糖。极大的减少了java代码的编写,非空判断等。通过跑一整套完整例子下来,可以完美兼容JAVA现有的写法,并能提升很多代码优化的空间,通过内置函数简化代码逻辑的编写。代码整体可读性变得很高。

各个维度上都有很大的提升,随着深入的学习,相信会有更多的便捷和高效的提升。整体架构采用springboot+kotlin+gradle+mybatisPlus来进行搭建。

Gradle 构建脚本


plugins {
   id 'org.springframework.boot' version '2.6.4'
   id 'io.spring.dependency-management' version '1.0.11.RELEASE'
   id 'org.jetbrains.kotlin.jvm' version '1.6.10'
   id 'org.jetbrains.kotlin.plugin.serialization' version '1.6.10'
}

group = 'com.wuhanpe'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'


repositories {
   maven {
      allowInsecureProtocol = true
      url 'http://192.168.100.60:18081/repository/maven-snapshots/'
   }
   mavenCentral()
}

dependencies {
   implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
   implementation 'org.springframework.boot:spring-boot-starter-web'
   developmentOnly 'org.springframework.boot:spring-boot-devtools'
   testImplementation 'org.springframework.boot:spring-boot-starter-test'
   implementation 'org.jetbrains.kotlin:kotlin-reflect'
   implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
   implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2'
   implementation 'p6spy:p6spy:3.8.5'
   implementation 'mysql:mysql-connector-java:8.0.19'
   implementation 'org.springframework.cloud:spring-cloud-starter-alibaba-nacos-config'
   implementation 'org.springframework.cloud:spring-cloud-starter-alibaba-nacos-discovery'
   implementation 'cn.hutool:hutool-all:5.3.5'
   implementation 'com.baomidou:mybatis-plus-boot-starter:3.1.0'

}

tasks.named('test') {
   useJUnitPlatform()
}
compileKotlin {
   kotlinOptions {
      jvmTarget = "1.8"
   }
}
compileTestKotlin {
   kotlinOptions {
      jvmTarget = "1.8"
   }
}

dependencyManagement {
   imports {
      mavenBom 'com.whpe:SpringCloudNacosParent:0.0.1-SNAPSHOT'
   }
}

使用的jdk8来进行的开发,后续会考虑到升级到jdk17。springboot 3.0后期开发会默认支持gradle进行构建,也在逐步尝试使用gradle来进行代码编译。现在使用的是默认的gradle语音groovy,后面也可以替换成kts的方式,利用kotlin脚本来构建。kotlin提供了一整套的解决方案,也是相当方便。

框架异同点

序列化

序列化准备用kotlin自带的序列化方案来处理,但是遇到无法处理泛型的问题,目前还未找到好的解决方式。 目前代码中对请求参数进行解析时候采用的是jackson中的jsonNode来进行处理,有点类型fastjson中的jsonObject。

val jsonNode = JsonUtils.MAPPER?.readTree(StreamUtils.copyToString(sr.inputStream, Charset.defaultCharset()))

jsonNode?.get("data") ?: return null

return JsonUtils.fromJson(jsonNode?.get("data").toString(), parameter.parameterType)

orm

orm采用mybatisPlus,这里有一个弊端。使用jdk8中的stream时,kotlin中不支持,会出现报错的情况。mybatisPlus贴心的提供了两个类来处理kotlin中的查询,更新情况,分别是KtQueryWrapper,KtUpdateWrapper。 用起来还是相当顺手的。

查询
return dataSettingMapper.selectList(KtQueryWrapper(DataSetting::class.java)
    .select(DataSetting::typeName, DataSetting::type)
    .eq(!StringUtils.isEmpty(dataSetting.customerId), DataSetting::customerId, dataSetting.customerId)
    .groupBy(DataSetting::typeName, DataSetting::type)
).map { ds -> SelectModel(ds.typeName, ds.type) }

特别需要提到的一点是kotlin中的集合操作,比jdk8中的stream还要高效很多,充分利用其语法糖特性

更新
dataSettingMapper.update(null, KtUpdateWrapper(DataSetting::class.java)
    .eq(DataSetting::id, dataSetting.id)
    .set(DataSetting::name, dataSetting.name)
)
mapper
@Repository
interface DataSettingMapper: BaseMapper<DataSetting>

非常简单的就创建了一个mapper类

内置函数

这里需要特别提到一点内置函数的使用,会让整个代码的编写上升一个台阶。

also

PaginationInterceptor().also { it.setDialectType("mysql") }

分页配置非常简单

takeIf run

dataSetting.takeIf { it.id > 0 }?.run { return updateOne(dataSetting) }

还有诸如let,apply,with等非常常用的内置函数,采用链式调用的方式,提升代码编写效率。后续也会陆续使用到。

整体感受

整体跑下来除了编译的时候,会稍微慢一些,其他各个方面都是一个极大的提升,整体非常轻松。减少了花费在写一些模板代码的时间消耗。也会在一些新项目中采用此技术栈,逐步摸透kotlin语言特性。