kotlin的语法优势
kotlin相对java的优势有很多,这里就不一一介绍。 只说两个我们常用的。
- 非空类型,直接在类型定义时定义数据是否非空。可以减少90%以上的空指针异常,其它10%可能在你依赖的包里面。
- ?. 可空值调用,这个方法可以减少90%以上的可空判断,代码量大大减少。 其它的就太多了,具体可以在其它地方搜一搜,或者有兴趣的可以留言讨论。
本文的主题是如何用kotlin构建一个spring boot应用。
spring对kotlin的支持可以说是亲儿子级别,spring boot文档里面的代码示例都是两种语言。而且spring官方特地提供了一篇用kotlin构建spring boot的官方指南。 使用kotlin构建spring boot应用 本文的要点大部分基于该示例,但用更简单的方式介绍。
如何从idea创建一个使用kotlin的spring boot项目
- 打开idea,点击 File -> New -> Project。
- 在 New Project 对话框中,选择 Spring Initializr。
- 在 Spring Initializr 对话框中,输入项目的 Group、Artifact、Name 等信息。
- 在 Dependencies 选项卡中,选择 Spring Boot DevTools、Spring Web、Spring data JPA 等依赖。
- 点击 Next 按钮,选择项目的存储位置。
- 点击 Finish 按钮,等待项目创建完成。
如何从spring initializr创建一个使用kotlin的spring boot项目
- 打开spring initializr,输入项目的 Group、Artifact、Name 等信息。
- 点击 Add Dependencies 按钮,选择 Spring Boot DevTools、Spring Web、Spring data JPA 等依赖。
- 点击 Generate 按钮,下载项目的压缩包。
- 解压压缩包,用idea/或者其它开发工具打开项目。
如何在现有项目中添加kotlin支持
使用前面的两个方法,都是新建项目,下面我们介绍一下如何在现有的java项目中添加kotlin支持。详情参考kotlin官方文件Adding Kotlin to a Java project – tutorial
- 在使用maven构建的项目添加kotlin依赖
- 修改pom.xml添加在build块添加下列配置,以下配置可以使你的项目能正确识别和编译kotlin代码
<properties>
<!--此处根据你需求选择,选择对应的kotlin版本。-->
<!--如果是使用的spring boot脚手架搭建的项目,可以不写-->
<!--如果使用其它方式搭建的spring bott项目,请根据你的版本使用对应的kotlin版本-->
<kotlin.version>2.2.21</kotlin.version>
</properties>
<build>
<pluginManagement><!-- Lock down plugin versions to avoid using Maven defaults (can be moved to a parent pom file) -->
<plugins>
<!-- No maven-compiler-plugin needed with Kotlin extensions -->
</plugins>
</pluginManagement>
<plugins>
<!-- Activate Kotlin Maven plugin for main and test sources -->
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<!-- Ensure Kotlin code can reference Java code -->
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>default-test-compile</id>
<phase>test-compile</phase>
<configuration>
<sourceDirs>
<sourceDir>src/test/kotlin</sourceDir>
<sourceDir>src/test/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 在pom.xml中添加kotlin相关的库依赖,这些依赖库是kotlin运行时必须的
<dependencies>
<!--下面两个模块是kotlin运行必备库,一个是kotlin标准库,一个是kotlin反射库-->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<!--下面是kotlin的jackson支持,使jackson能正确处理kotlin的一些特殊数据类型,比如 UInt,UByte等 -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
</dependencies>
- 在使用gradle构建的项目中添加kotlin依赖
- 添加kotlin编译插件。
plugins {
// kotlin编译插件,将kotlin代码编译为jvm字节码
kotlin("jvm") version "2.2.21"
// kotlin的spring插件,主要目的是让kotlin生成的类能正确的被spring容器识别并代理
kotlin("plugin.spring") version "2.2.21"
// 这个是让kotlin能正确处理jpa实体,如果没有使用jpa,可以不用添加该插件
kotlin("plugin.jpa") version "2.2.21"
}
- 在依赖中添加相关的kotlin依赖
dependencies {
// 下面两个模块是kotlin运行必备库,一个是kotlin标准库,一个是kotlin反射库
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib")
// 下面是kotlin的jackson支持,使jackson能正确处理kotlin的一些特殊数据类型,比如 UInt,UByte等
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
}
经过上面的配置之后,就可以在项目中使用kotlin快乐的编码了。
使用kotlin构建项目
kotlin保持了和java一样的包结构。但支持在一个文件中声明多个类。但仍然推荐和java保持一样的包目录结构。这样我们就可以在不破坏现有结构的情况下,充分利用kotlin的语法优点。
- 项目入口文件
这个文件和java版本的差别较大。
@SpringBootApplication
class AppApplication {
@Bean
fun dateTimeProvider(): DateTimeProvider {
return DateTimeProvider { Optional.of(ZonedDateTime.now()) }
}
}
fun main(args: Array<String>) {
runApplication<AppApplication>(*args)
}
项目入口文件和正常java的项目入口文件基本一致,需要注意的是kotlin的main方法不依赖任何类,所以main方法要写在AppApplication类的外部。
我们可以在AppApplication中添加更多的 @Bean. 比如上面的代码中就声明了一个类型为DateTimeProvider,名称为dateTimeProvider的bean
- 一个controller的示例
@RestController
@RequestMapping("/users")
class UserController(
private val userService: UserService
) {
@GetMapping("{id}")
fun getUser(
@PathVariable("id") id: Long
): UserDto {
return userService.findById(id)?:throw NoSuchElementException("用户不存在")
}
}
- RestController/RequestMapping注解和java的没有任何区别。
- GetMapping/PathVariable等方法上的注解和java版本的没有任何区别。
- 当使用构造注入时,和java的构造函数注入没有本质的区别,但语法更简洁。
- 其它层的文件,基本和controller一致,就不再过多赘述。
- 接下来我们可以使用kt的语法优势,编写更简洁的代码了。