凭借Kotlin的幽雅,还有Spring Boot 2.0的简洁,可以通过简单几行代码实现大流量数据接口,同时具备背压处理能力,下面用一个简单的示例介绍接口实现步骤:
1. 开启浏览器访问https://start.spring.io/ ,通过Spring Initializer完成工程目录结构的初始化工作
注意选择生成项目的构建工具,可以根据自己的编译习惯选择Maven或者Gradle,编程语言选择Kotlin,Spring Boot版本选择2.0.4或者以上版本,根据项目信息填写group和artifact标题。
然后重点来了,需要选择哪些依赖包?因为我们要用Spring5框架的响应式编程模式提供REST接口,第一个依赖包需要Reactive Web,另外我们需要用MongoDB保存接口数据,也是通过响应式访问MongoDB,还需要一个Reactive MongoDB依赖包。
最后点击生成工程(Generate Project),解压下载后的工程压缩包。
2. 使用IDE环境打开工程目录
可以使用STS或者IntelliJ IDEA,由于IntelliJ IDEA强大的辅助完成功能,个人强烈推荐后者。
在src目录内可以找到主入口函数的类文件cn/springspace/kotlinapp/KotlinAppApplication.kt,
在该文件内我们首先需要添加数据实体bean的类定义
@Document
data class Book(val name: String, val author: String, val publish: Date)
然后添加MongoDB的访问接口,该接口继承自ReactiveMongoRepository,已默认实现了数据搜索,保存,删除等基本方法,也可以根据自己的需要添加实现一些自定义方法,本例中仅使用到保存和列表的方法就无需自定义方法了。
interface BookRepository : ReactiveMongoRepository
3. 在main函数中定义初始化数据的方法
fun main(args: Array) {
runApplication(*args) {
addInitializers(
beans {
bean {
val bookRepository = ref()
bookRepository.deleteAll()
.thenMany(
Flux.fromStream(
Stream.generate { "Spring 空间【${UUID.randomUUID()}】" }
.limit(30)))
.map { Book(it, "Michael Chen", Date()) }
.flatMap { bookRepository.save(it) }
.thenMany(bookRepository.findAll())
.subscribe { println(it) }
}
}
)
}
}
以上的数据初始化的操作分解如下:
步骤1:bookRepository.deleteAll(), 删除系统内历史数据;
步骤2:Flux.fromStream( Stream.generate { "Spring 空间【${UUID.randomUUID()}】" } .limit(30)), 生成一个数组长度为30的字符串序列,每个元素的格式为:"Spring 空间【${UUID.randomUUID()}】";
步骤3:map { Book(it, "Michael Chen", Date()) },以上一步的字符为源头生成30个Book实体类;
步骤4:flatMap { bookRepository.save(it) },保存这30个Book到MongoDB;
步骤5:thenMany(bookRepository.findAll()),检索系统内最新的Book数据;
步骤6:subscribe { println(it) },打印输出检索出来的数据。
注意:以上步骤中最后一步subscribe()最为关键,该步骤是控制启动步骤1到步骤6的总开关,没有该步骤,前面几步的动作都不会执行。
4. 添加REST API接口
凭借Kotlin优雅的DSL语言,我们可以更简洁的表达方式实现多个功能块的定义,如下部分是在beans内部添加WEB响应模块的bean:
bean {
val bookRepository = ref()
val interval = Flux.interval(Duration.ofMillis(100))
router {
GET("/books") {
ServerResponse.ok()
.contentType(MediaType.TEXT_EVENT_STREAM)
.body(Flux.zip(interval, bookRepository.findAll()).map { it.t2 })
}
}
}
其中contentType(MediaType.TEXT_EVENT_STREAM)部分控制服务端输出的数据格式为SSE方式的文本事件流,如果要简单的一次性输出所有数据,该部分的bean定义如下:
bean {
val bookRepository = ref()
router {
GET("/books") {
ServerResponse.ok().body(bookRepository.findAll())
}
}
}
5. 检查接口数据
data:{"name":"Spring 空间【b1b1faa9-2b74-48a5-aa99-52458d5e55cc】","author":"Michael Chen","publish":"2018-09-06T07:31:41.245+0000"}
data:{"name":"Spring 空间【bda0a990-ae11-4286-88f9-977ced8199d4】","author":"Michael Chen","publish":"2018-09-06T07:31:41.453+0000"}
data:{"name":"Spring 空间【3c7494b4-474d-4c89-a786-8f611dcae225】","author":"Michael Chen","publish":"2018-09-06T07:31:41.454+0000"}
data:{"name":"Spring 空间【e05b8f31-bf37-4bb3-9e74-002b9a1bd008】","author":"Michael Chen","publish":"2018-09-06T07:31:41.459+0000"}
data:{"name":"Spring 空间【a3882221-a001-4b72-b478-d04db6f498f6】","author":"Michael Chen","publish":"2018-09-06T07:31:41.495+0000"}
data:{"name":"Spring 空间【30c18fa6-d326-4ce0-9ed4-0cbbc1a20025】","author":"Michael Chen","publish":"2018-09-06T07:31:41.467+0000"}
...................