后端响应式是未来,吞吐量会更大,而资源占用更少,其用到了类似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")
}
...
目前项目结构是这样:
然后打开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
然后就可以在接口里去增删改查数据了,比如增加一条数据
或者直接声明挂起函数,如下(声明等同于上面的方法)
其中mono{}是开启了一个以Mono
这里我们插入一条数据(挂起了),然后打印一下返回值(就是插入的对象),并返回这个对象
这个db提供了如savexxx,findxxx,deletexxxx等简单的操作,如果需要自己执行sql语句,需要如下:
需要注意的是,如果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的代码提示了
步骤如下:
然后如下简单配置一下
在里面执行一下,然后在同步一下
use 你的数据库名 ;
然后回去
可以把默认的(所有文件)改成这个库,并把当前文件的私有设置删掉(或者你单独改某文件也行)
然后sql语句就有代码提示了
如果有什么写的不对的请大佬们指出,我用的还不熟练,相当于给自己写了一个文档 \嘿嘿
end