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_11

    configurations {
        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.annotation("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.entity

import 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.config

import 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()
    @Bean
    open fun customConverters(): HttpMessageConverters {
        //创建fastJson消息转换器

        var fastJsonConverter = FastJsonHttpMessageConverter()
        //创建配置类
        var fastJsonConfig = FastJsonConfig()
        //修改配置返回内容的过滤
        fastJsonConfig.setSerializerFeatures(
            // 格式化
            SerializerFeature.PrettyFormat,
            // 可解决long精度丢失 但会有带来相应的中文问题
            //SerializerFeature.BrowserCompatible,
            // 消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)
            SerializerFeature.DisableCircularReferenceDetect,
            // 是否输出值为null的字段,默认为false
            SerializerFeature.WriteMapNullValue,
            // 字符类型字段如果为null,输出为"",而非null
            SerializerFeature.WriteNullStringAsEmpty,
            // List字段如果为null,输出为[],而非null
            SerializerFeature.WriteNullListAsEmpty
        )
        // 日期格式
        fastJsonConfig.dateFormat = "yyyy-MM-dd HH:mm:ss"

        // long精度问题
        var serializeConfig = SerializeConfig.globalInstance
        serializeConfig.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: dev
 datasource:
   #引用项目中的数据库文件
   driver-class-name: org.sqlite.JDBC
   url: jdbc:sqlite::resource:sqlite/bbs.db
   username:
   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.controller

import 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的构造方法的方式注入对象
    @Resource
    lateinit 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调用如下:
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值