Kotlin简介:Kotlin是一个基于JVM的静态类型编程语言,由JetBrains设计开发并开源。Kotlin能够与Java进行完全的交互,可以在同一个项目中同时使用Java和Kotlin。并且支持多种平台,包括移动端、服务端以及浏览器端,Kotlin已正式成为Android官方支持开发语言。
Spring Framework 5.0版本中已经正式支持Kotlin语言,SpringBoot从SpringBoot2开始也正式支持Kotlin。
最近刚开始学习Kotlin,也踩了一些坑,顺便总结一下基于kotlin开发的SpringBoot2.x环境搭建。
一、环境准备
- 开发工具:idea 2019
- 项目构建工具:Maven 3.6.1
- JDK:1.8.0_181
- SpringBoot:2.2.2.RELEASE
- Kotlin:1.3.61
二、构建项目
这里直接通过Maven构建一个java项目,然后对pom
文件进行修改,添加kotlin相关依赖和插件,完整的pom
文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rtxtitanv</groupId>
<artifactId>springboot-kotlin</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>springboot-kotlin</name>
<description>SpringBoot2.x kotlin 开发环境</description>
<parent>
<!-- SpringBoot 起步依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 增量编译:为了使构建更快,为Maven启用增量编译 也可以使用 -Dkotlin.compiler.incremental=true 选项运行构建 -->
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<java.version>1.8</java.version>
<kotlin.version>1.3.61</kotlin.version>
</properties>
<dependencies>
<!-- SpringBoot Web 起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- jackson kotlin 包 -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<!-- kotlin反射包 -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<!-- kotlin jdk8核心库 -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<!-- 单元测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<!-- 编译只有Kotlin的源代码时指定源代码目录 使用maven构建项目时是java
注意源代码目录与指定一致,这里改成kotlin -->
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- kotlin-maven-plugin 插件 -->
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<args>
<!-- 负责检查对JSR-305注解的支持 -->
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<!-- Kotlin的类默认都是final的,启用kotlin-spring编译器插件
该插件指定了以下注解:@Component、@Async、@Transactional、@Cacheable以及@SpringBootTest。
由于元注解的支持,标注有@Configuration、@Controller、@RestController、@Service或者@Repository
的类会自动添加open,因为这些注解标注有元注解@Component -->
<plugin>spring</plugin>
<!-- 无参(no-arg)编译器插件为具有特定注解的类生成一个额外的零参数构造函数
这个生成的构造函数是合成的,因此不能从Java或Kotlin中直接调用,但可以使用反射调用。
对于JPA支持用“jpa”插件 -->
<plugin>no-arg</plugin>
</compilerPlugins>
<pluginOptions>
<!-- 指定应用no-arg插件的自定义注解 -->
<option>no-arg:annotation=com.rtxtitanv.annotation.KtNoArgsConstructor</option>
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
项目结构如下:
编写主启动类,一个最简单的基于Kotlin的SpringBoot项目就构建完成了。
package com.rtxtitanv
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
/**
* @name com.rtxtitanv.KotlinApplication
* @description 主启动类
* @author rtxtitanv
* @date 2020/1/16 14:48
* @version 1.0.0
*/
@SpringBootApplication
class KotlinApplication
fun main(args: Array<String>) {
runApplication<KotlinApplication>(*args)
}
三、使用测试
进行一些简单的测试,看能否正常使用Kotlin开发SpringBoot应用。
1.数据模型类
这里使用Data数据类,一般情况下编译器会自动生成equals()、 hashCode()、toString()等函数,至于getter和setter,没有显示定义Kotlin会默认自动生成。
package com.rtxtitanv.model
import com.rtxtitanv.annotation.KtNoArgsConstructor
/**
* @name com.rtxtitanv.model.User
* @description 用户实体类
* @author rtxtitanv
* @date 2020/1/16 16:07
* @version 1.0.0
*/
@KtNoArgsConstructor
data class User(var id: Long? = null,// ?表示声明为Nullable变量
var userName: String? = null,
var passWord: String? = null,
var nickName: String? = null,
var age: Int? = null,
var tel: String? = null,
var addr: String? = null)
自定义如下注解主要用于Kotlin的no-arg插件,指定该注解应用于no-arg插件,即注解有该注解的类。no-arg插件会为其自动添加无参构造函数,不过该无参构造函数只能通过反射调用,如果User类主构造函数中初始化了属性值,则可以通过User()调用无参构造函数,省略no-args插件也可以,也可以反射调用无参构造函数。
package com.rtxtitanv.annotation
/**
* @name com.rtxtitanv.annotation.KtNoArgsConstructor
* @description kotlin自定义无参构造器注解
* @author rtxtitanv
* @date 2020/1/16 16:57
* @version 1.0.0
*/
annotation class KtNoArgsConstructor
2.单元测试
package com.rtxtitanv
import com.rtxtitanv.model.User
import org.junit.Test
import org.junit.runner.RunWith
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner
/**
* @name com.rtxtitanv.KotlinTest
* @description 单元测试类
* @author rtxtitanv
* @date 2020/1/16 15:33
* @version 1.0.0
*/
@RunWith(SpringRunner::class)
@SpringBootTest(classes = [KotlinApplication::class])
class KotlinTest {
private val logger: Logger = LoggerFactory.getLogger(KotlinTest::class.java)
@Test
fun kotlinTest() {
// 通过反射调用自动生成的无参构造函数
val user1 = User::class.java.newInstance()
// 在User类主构造函数中初始化了属性值,则可以通过User()调用无参构造函数,省略no-args插件也可以,也可以反射调用
// 如果没有在主构造函数中初始化属性值,则不能通过User()显式调用无参构造函数,必须要加上应用no-args插件的注解
// 且通过反射调用
val user2 = User()
logger.info("user1: " + user1.toString())
logger.info("user2: " + user2.toString())
}
}
控制台打印的日志说明自动生成了无参构造函数。
2020-01-17 21:39:21.172 INFO 15164 --- [ main] com.rtxtitanv.KotlinTest : user1: User(id=null, userName=null, passWord=null, nickName=null, age=null, tel=null, addr=null)
2020-01-17 21:39:21.172 INFO 15164 --- [ main] com.rtxtitanv.KotlinTest : user2: User(id=null, userName=null, passWord=null, nickName=null, age=null, tel=null, addr=null)
3.service层
这里省去了数据层,数据为手动模拟的,主要用于控制层返回数据测试。
package com.rtxtitanv.service
import com.rtxtitanv.model.User
/**
* @name com.rtxtitanv.service.KotlinService
* @description KotlinService接口
* @author rtxtitanv
* @date 2020/1/16 17:06
* @version 1.0.0
*/
interface KotlinService {
/**
* 根据年龄查询用户
*/
fun findUserByAge(age: Int): List<User>
}
package com.rtxtitanv.service.impl
import com.rtxtitanv.model.User
import com.rtxtitanv.service.KotlinService
import org.springframework.stereotype.Service
/**
* @name com.rtxtitanv.service.impl.KotlinServiceImpl
* @description KotlinService实现类
* @author rtxtitanv
* @date 2020/1/16 17:07
* @version 1.0.0
*/
@Service
class KotlinServiceImpl : KotlinService {
/**
* 模拟根据年龄查询用户,只是测试,返回写死的user数据
*/
override fun findUserByAge(age: Int): List<User> {
val user1 = User(1L, "aaa",
"123456", "abc",
age, "198658632", "北京")
val user2 = User(2L, "bbb",
"111222", "cba",
age, "15963247851", "上海")
val userList = ArrayList<User>()
userList.add(user1)
userList.add(user2)
return userList
}
}
4.controller层
package com.rtxtitanv.controller
import com.rtxtitanv.model.User
import com.rtxtitanv.service.KotlinService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
/**
* @name com.rtxtitanv.controller.KotlinController
* @description KotlinController
* @author rtxtitanv
* @date 2020/1/16 14:59
* @version 1.0.0
*/
@RequestMapping("/kotlin")
@RestController
class KotlinController(private val kotlinService: KotlinService) {
/**
* springboot2.x kotlin开发环境测试
*/
@GetMapping("/test")
fun helloKotlin(): String {
return "hello kotlin!"
}
/**
* 根据年龄查询用户
*/
@GetMapping("/user/{age}")
fun findUser(@PathVariable age: Int): List<User> {
return kotlinService.findUserByAge(age)
}
}
访问localhost:8080/kotlin/test
:
访问localhost:8080/kotlin/user/25
:
能正常返回json数据,说明一个基于Kotlin的简单SpringBoot2.x开发环境就搭建完成了。可以看出Kotlin非常适合开发服务器端应用程序,可以编写出简明且表现力强的代码,同时保持与现有基于Java的技术栈的完全兼容性,所以Kotlin还是有必要学习和掌握的。
代码示例