Kotlin 协程 + Spring webflux 开发后端

前言

后端响应式是未来,吞吐量会更大,而资源占用更少,其用到了类似Android系统的Loop(事件循环)机制,而协程可以减少线程等待的消耗,并且同步式的编程方式使代码可读性更高,两个仿佛天生就是一对,所以就来简单的了解并配置一下Kotlin 协程 + Spring webflux的后端项目

正文

项目配置采用Gradle(毕竟我是做Android开发的,所以一切亲Android体系),数据库用的Mysql

build.gradle.kts

plugins {
    id("org.springframework.boot") version "2.3.5.RELEASE"
    id("io.spring.dependency-management") version "1.0.10.RELEASE"
    kotlin("jvm") version "1.4.10"
    kotlin("plugin.spring") version "1.4.10"
}

dependencies {
    //spring webflux 响应式服务端框架,使用方法基本等同spring mvc(除了返回值)
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    //webflux 返回值的协程支持
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
    //webflux await的协程支持
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive")
    //异步数据库支持
    implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
    //mysql 的异步数据库支持
    implementation("dev.miku:r2dbc-mysql")
    //json解析(默认就是jackson)
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    //webflux kt扩展
    implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
    //kt反射
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    //kotlin核心库
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    //网络请求
    implementation("com.squareup.okhttp3:okhttp:3.14.9")
}

...

目前项目结构是这样:

Kotlin 协程 + Spring webflux 开发后端_第1张图片

然后打开application.properties文件增加以下配置

#修改端口号
server.port=xxxxx (最好大于一万并小于65535,具体自行搜索)
#
#配置mysql r2dbc
spring.r2dbc.password=mysql密码
spring.r2dbc.username=mysql用户名
spring.r2dbc.url=r2dbcs:mysql://mysql的ip:mysql端口/mysql的数据库名

然后spring webflux的操作其他还是跟spring mvc是一样的,这里就不赘述,唯一不同的是返回值

示例controller

import kotlinx.coroutines.reactor.mono
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.r2dbc.core.DatabaseClient
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import javax.annotation.Resource

/**
 * creator: lt  2020/11/11  [email protected]
 * effect : test的接口
 * warning:
 */
@RestController
@RequestMapping("/api/ad")
class TestInterface {

    @GetMapping("/findAll")
    fun findAll(): Flux //返回Flux表示是个list

    @GetMapping("/addData")
    fun addData(): Mono //返回Mono表示是单个对象
}

示例数据库表的实体类和数据库操作对象

import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import org.springframework.data.repository.kotlin.CoroutineSortingRepository

/**
 * creator: lt  2020/11/11  [email protected]
 * effect : 表实体类
 * warning:
 */
@Table("feedback")
class TestBean(
        @Id
        var id: Long? = null,//如果id为null,则为自增,并且需要var
        val create_time: Long = 0,
        val content: String? = null,
        val user_id: Long = 0,
        val urls: String? = null,
        val is_solve: Int = 0,
        val solve_time: Long = 0,
)

/**
 * creator: lt  2020/11/11  [email protected]
 * effect : 数据库操作类
 * warning:
 */
interface TestDB : CoroutineSortingRepository

然后就可以在接口里去增删改查数据了,比如增加一条数据

Kotlin 协程 + Spring webflux 开发后端_第2张图片

或者直接声明挂起函数,如下(声明等同于上面的方法)

其中mono{}是开启了一个以Mono为返回值的协程,而TestDB实现了CoroutineSortingRepository接口,所以其内的大部分方法都是suspend的
这里我们插入一条数据(挂起了),然后打印一下返回值(就是插入的对象),并返回这个对象

这个db提供了如savexxx,findxxx,deletexxxx等简单的操作,如果需要自己执行sql语句,需要如下:

Kotlin 协程 + Spring webflux 开发后端_第3张图片

需要注意的是,如果flux内的suspend lambda走完的话,这个接口就完成了,也就是说如果是在回调中在调用channel.send是无效的,需要改成使用协程的形式

自己执行sql语句还有以下的api:

//查询,返回Flux
databaseClient.execute("select * from client_user").as(ClientUser.class)
                .fetch()
                .all();
//插入,返回Mono
databaseClient.insert().into(ClientUser.class)
                .using(clientUser)
                .fetch().rowsUpdated();

 返回Flux也可以这样写

或者也可以这样自定义使用sql,参考: https://docs.spring.io/spring-framework/docs/current/reference/html/languages.html   1.8.2

interface TestDB : CoroutineSortingRepository {
    @Query("select * from feedback")
    fun getAll(): Flux

    @Query("select * from feedback where id = :id")
    suspend fun get(id: Long): TestBean

    @Query("select * from feedback where id = 1")
    fun get2(): Mono

    suspend fun getById(id: Long): TestBean
}

api参考: https://docs.spring.io/spring-data/jpa/docs/2.4.7/reference/html/#reference  6.3 

然后使用基本就ok了,可以直接运行测试一下

扩展

1.可能你需要java和kt代码混写,但用的是gradle,可能会不去编译java代码,导致出现NoClassDefFoundError

此时只需要在项目的build.gradle.kts中的最外层添加如下代码即可,原因是java代码不知道代码入口了

sourceSets {
    main {
        java.srcDirs("src/main/kotlin")
    }
}

2.可能第一次自己写sql没有绑定到数据库表上,如下图,然后我就大概说一下怎么绑定,绑定完就会有sql的代码提示了

步骤如下:

Kotlin 协程 + Spring webflux 开发后端_第4张图片

Kotlin 协程 + Spring webflux 开发后端_第5张图片

然后如下简单配置一下

Kotlin 协程 + Spring webflux 开发后端_第6张图片

会弹出

在里面执行一下,然后在同步一下

use 你的数据库名 ;

然后回去

Kotlin 协程 + Spring webflux 开发后端_第7张图片

可以把默认的(所有文件)改成这个库,并把当前文件的私有设置删掉(或者你单独改某文件也行)

Kotlin 协程 + Spring webflux 开发后端_第8张图片

Kotlin 协程 + Spring webflux 开发后端_第9张图片

然后sql语句就有代码提示了

Kotlin 协程 + Spring webflux 开发后端_第10张图片

如果有什么写的不对的请大佬们指出,我用的还不熟练,相当于给自己写了一个文档 \嘿嘿

end

你可能感兴趣的:(kotlin协程,SpringBoot,Kotlin,spring,协程,webflux,Kotlin,mysql,r2dbc)