使用RouterFunctions使用Kotlin + Spring boot2 + Webflux + Thymeleaf进行实现
首先
我正在尝试将我在家里的开发环境中使用Java的部分改成Kotlin。
这是我试着创建的备忘录,目的是在这个过程中先暂时建立类似标题中所提到的环境。
环境
IntelliJ IDEA
Kotlin 1.2.20
Java 8
Spring Boot 2.0.0.RELEASE
智能IDEA
Kotlin 1.2.20
Java 8
Spring Boot 2.0.0.RELEASE
项目准备
这次我们将使用Initializer来简化操作。因为听说在IntelliJ中只有付费版才能创建Spring项目,所以我们决定从网上进行创建。至于依赖项,我们可以稍后添加,所以可以是空的也可以添加进去。
构建.gradle
1. 春季引导器
2. 春季引导器-Webflux
3. 春季引导器-Thymeleaf
在创建代码时,即使没有thymeleaf,也可以想办法解决。但是在运行时出现错误,而且完全不知道错误的原因,所以最好小心一点(耗时3小时)。
只需要将其添加到由Initializer创建的工具中。但是,我会附上当它成功运行时的全部build.gradle文件。
buildscript {
ext {
kotlinVersion = '1.2.20'
springBootVersion = '2.0.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
}
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.tasogarei'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-webflux')
compile('org.springframework.boot:spring-boot-starter-thymeleaf')
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
testCompile('org.springframework.boot:spring-boot-starter-test')
}
应用程序类
那么,我们开始实施。首先是运行引导程序的主类。
在这个例子中,我想试试使用REACTIVE,所以我使用了SpringApplicationBuilder来创建,但是使用SpringApplication.run(Application::class.java,*args)也可以运行。
package com.tasogarei.application
import org.springframework.boot.WebApplicationType
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.builder.SpringApplicationBuilder
@SpringBootApplication
class Application
fun main(args: Array<String>) {
SpringApplicationBuilder()
.sources(Application::class.java)
.web(WebApplicationType.REACTIVE)
.run(*args)
}
处理程序类
我們將創建一個處理請求的Handler。由於這次想返回HTML,所以我們使用HTML作為ContentType並使用render返回View。View的位置規則與不使用WebFlux時相同。
由于这只是一个试验,所以我们可以省略将attribute作为Map传递给render函数的步骤。
package com.tasogarei.application.handler
import org.springframework.http.MediaType
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import reactor.core.publisher.Mono
@Component
class Handler {
fun getIndex(req: ServerRequest): Mono<ServerResponse> {
return ServerResponse.ok().contentType(MediaType.TEXT_HTML).render("index")
}
}
创建RouterFunction。
我会创建一个RouterFunction。
通过创建RouterFunction,可以将所有的Mapping集中起来,所以我个人更喜欢这种方式,而不是在Controller上一个一个地进行Mapping。
不知怎么地,通过使用 accept 和 nest 等方法来处理复杂的 URL 结构,但只需写上 GET(“/”, handler::getIndex) 就能运行。
嗯,我认为对于一般的 Web 应用程序,由于很快就会增加,所以最好一开始就写得容易添加。
此外,还通过传递使用的Handler,可以在函数侧面上像routeIndex(handler: Handler)一样添加。当Handler增加时,我觉得不应该像构造函数的示例一样写,而是应该增加函数。但我不确定哪个更好。
package com.tasogarei.application.route
import com.tasogarei.application.handler.Handler
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.MediaType
import org.springframework.web.reactive.function.server.router
@Configuration
class Route(private val handler: Handler) {
@Bean
fun routeIndex() = router {
accept(MediaType.TEXT_HTML).nest {
GET("/", handler::getIndex)
}
}
}
确认行动
只需放置相应的HTML并启动浏览器进行访问,就能够看到内容了。
最后
虽然我刚开始对Dependency出现了错误而感到困惑,但现在我已经能够轻松地使用Webflux处理HTML了。
我知道使用或不使用Webflux都有其优缺点,但根据个人喜好,我打算继续使用它一段时间。