前言
本文讲解 spring boot2 基础下,如何使用 kotlin,并无缝整合与完美交融。为了让读者更加熟悉 kotlin 的语法糖,笔者会在未来的几篇文章中,聊聊 kotlin 的新特性及其语法糖。下面话不多说了,来一起看看详细的介绍吧
环境依赖
修改 pom 文件,添加 spring boot 依赖。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<parent>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-parent</artifactid>
<version> 2.0 . 2 .release</version>
<relativepath/>
</parent>
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-jdbc</artifactid>
</dependency>
</dependencies>
|
紧接着,我们需要添加 mysql 依赖。
1
2
3
4
5
6
7
8
9
10
|
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<version> 5.1 . 35 </version>
</dependency>
<dependency>
<groupid>com.alibaba</groupid>
<artifactid>druid</artifactid>
<version> 1.0 . 14 </version>
</dependency>
|
最后,添加 kotlin 依赖。
1
2
3
4
5
6
7
8
9
10
11
12
|
<dependency>
<groupid>org.jetbrains.kotlin</groupid>
<artifactid>kotlin-stdlib-jdk8</artifactid>
</dependency>
<dependency>
<groupid>org.jetbrains.kotlin</groupid>
<artifactid>kotlin-reflect</artifactid>
</dependency>
<dependency>
<groupid>org.jetbrains.kotlin</groupid>
<artifactid>kotlin-stdlib</artifactid>
</dependency>
|
注意的是,在 kotlin 中,data class 默认没有无参构造方法,并且 data class 默认为 final 类型,不可以被继承。注意的是,如果我们使用 spring + kotlin 的模式,那么使用 @autowared 就可能遇到这个问题。因此,我们可以添加 noarg 为标注的类生成无参构造方法。使用 allopen 为被标注的类去掉 final,允许被继承。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<plugin>
<artifactid>kotlin-maven-plugin</artifactid>
<groupid>org.jetbrains.kotlin</groupid>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupid>org.jetbrains.kotlin</groupid>
<artifactid>kotlin-maven-noarg</artifactid>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupid>org.jetbrains.kotlin</groupid>
<artifactid>kotlin-maven-allopen</artifactid>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
|
至此,我们 maven 的依赖环境大致配置完毕。完整的源码,可以参见文末 github 仓库。
数据源
方案一 使用 spring boot 默认配置
使用 spring boot 默认配置,不需要在创建 datasource 和 jdbctemplate 的 bean。
在 src/main/resources/application.properties 中配置数据源信息。
1
2
3
4
|
spring.datasource.driver- class -name=com.mysql.jdbc.driver
spring.datasource.url=jdbc:mysql: //localhost:3307/springboot_db
spring.datasource.username=root
spring.datasource.password=root
|
方案二 手动创建
在 src/main/resources/config/source.properties 中配置数据源信息。
1
2
3
4
5
|
# mysql
source.driverclassname = com.mysql.jdbc.driver
source.url = jdbc:mysql: //localhost:3306/springboot_db
source.username = root
source.password = root
|
这里, 创建 datasource 和jdbctemplate。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@configuration
@enabletransactionmanagement
@propertysource (value = *arrayof( "classpath:config/source.properties" ))
open class beanconfig {
@autowired
private lateinit var env: environment
@bean
open fun datasource(): datasource {
val datasource = druiddatasource()
datasource.driverclassname = env!!.getproperty( "source.driverclassname" ).trim()
datasource.url = env.getproperty( "source.url" ).trim()
datasource.username = env.getproperty( "source.username" ).trim()
datasource.password = env.getproperty( "source.password" ).trim()
return datasource
}
@bean
open fun jdbctemplate(): jdbctemplate {
val jdbctemplate = jdbctemplate()
jdbctemplate.datasource = datasource()
return jdbctemplate
}
}
|
脚本初始化
先初始化需要用到的 sql 脚本。
1
2
3
4
5
6
7
8
9
10
11
12
|
create database /*!32312 if not exists*/`springboot_db` /*!40100 default character set utf8 */ ;
use `springboot_db`;
drop table if exists `t_author`;
create table `t_author` (
`id` bigint( 20 ) unsigned not null auto_increment comment '用户id' ,
`real_name` varchar( 32 ) not null comment '用户名称' ,
`nick_name` varchar( 32 ) not null comment '用户匿名' ,
primary key (`id`)
) engine=innodb auto_increment= 1 default charset=utf8;
|
使用 jdbctemplate 操作
实体对象
1
2
3
4
5
|
class author {
var id: long ? = null
var realname: string? = null
var nickname: string? = null
}
|
dao相关
1
2
3
4
5
6
7
|
interface authordao {
fun add(author: author): int
fun update(author: author): int
fun delete(id: long ): int
fun findauthor(id: long ): author?
fun findauthorlist(): list<author>
}
|
我们来定义实现类,通过 jdbctemplate 定义的数据访问操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
@repository
open class authordaoimpl : authordao {
@autowired
private lateinit var jdbctemplate: jdbctemplate
override fun add(author: author): int {
return jdbctemplate.update( "insert into t_author(real_name, nick_name) values(?, ?)" ,
author.realname, author.nickname)
}
override fun update(author: author): int {
return jdbctemplate.update( "update t_author set real_name = ?, nick_name = ? where id = ?" ,
*arrayof(author.realname, author.nickname, author.id))
}
override fun delete(id: long ): int {
return jdbctemplate.update( "delete from t_author where id = ?" , id)
}
override fun findauthor(id: long ): author? {
val list = jdbctemplate.query<author>( "select * from t_author where id = ?" ,
arrayof<any>(id), beanpropertyrowmapper(author:: class .java))
return list?.get( 0 );
}
override fun findauthorlist(): list<author> {
return jdbctemplate.query( "select * from t_author" , arrayof(), beanpropertyrowmapper(author:: class .java))
}
}
|
service相关
1
2
3
4
5
6
7
|
interface authorservice {
fun add(author: author): int
fun update(author: author): int
fun delete(id: long ): int
fun findauthor(id: long ): author?
fun findauthorlist(): list<author>
}
|
我们来定义实现类,service 层调用 dao 层的方法,这个是典型的套路。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@service ( "authorservice" )
open class authorserviceimpl : authorservice {
@autowired
private lateinit var authordao: authordao
override fun update(author: author): int {
return this .authordao.update(author)
}
override fun add(author: author): int {
return this .authordao.add(author)
}
override fun delete(id: long ): int {
return this .authordao.delete(id)
}
override fun findauthor(id: long ): author? {
return this .authordao.findauthor(id)
}
override fun findauthorlist(): list<author> {
return this .authordao.findauthorlist()
}
}
|
controller相关
为了展现效果,我们先定义一组简单的 restful api 接口进行测试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
@restcontroller
@requestmapping (value = "/authors" )
class authorcontroller {
@autowired
private lateinit var authorservice: authorservice
/**
* 查询用户列表
*/
@requestmapping (method = [requestmethod.get])
fun getauthorlist(request: httpservletrequest): map<string, any> {
val authorlist = this .authorservice.findauthorlist()
val param = hashmap<string, any>()
param[ "total" ] = authorlist.size
param[ "rows" ] = authorlist
return param
}
/**
* 查询用户信息
*/
@requestmapping (value = "/{userid:\d+}" , method = [requestmethod.get])
fun getauthor( @pathvariable userid: long , request: httpservletrequest): author {
return authorservice.findauthor(userid) ?: throw runtimeexception( "查询错误" )
}
/**
* 新增方法
*/
@requestmapping (method = [requestmethod.post])
fun add( @requestbody jsonobject: jsonobject) {
val userid = jsonobject.getstring( "user_id" )
val realname = jsonobject.getstring( "real_name" )
val nickname = jsonobject.getstring( "nick_name" )
val author = author()
author.id = java.lang. long .valueof(userid)
author.realname = realname
author.nickname = nickname
try {
this .authorservice.add(author)
} catch (e: exception) {
throw runtimeexception( "新增错误" )
}
}
/**
* 更新方法
*/
@requestmapping (value = "/{userid:\d+}" , method = [requestmethod.put])
fun update( @pathvariable userid: long , @requestbody jsonobject: jsonobject) {
var author = this .authorservice.findauthor(userid)
val realname = jsonobject.getstring( "real_name" )
val nickname = jsonobject.getstring( "nick_name" )
try {
if (author != null ) {
author.realname = realname
author.nickname = nickname
this .authorservice.update(author)
}
} catch (e: exception) {
throw runtimeexception( "更新错误" )
}
}
/**
* 删除方法
*/
@requestmapping (value = "/{userid:\d+}" , method = [requestmethod.delete])
fun delete( @pathvariable userid: long ) {
try {
this .authorservice.delete(userid)
} catch (e: exception) {
throw runtimeexception( "删除错误" )
}
}
}
|
最后,我们通过 springkotlinapplication 运行程序。
1
2
3
4
5
6
|
@springbootapplication (scanbasepackages = [ "com.lianggzone.demo.kotlin" ])
open class springkotlinapplication{
fun main(args: array<string>) {
springapplication.run(springkotlinapplication:: class .java, *args)
}
}
|
关于测试
这里,笔者推荐 idea 的 editor rest client。idea 的 editor rest client 在 intellij idea 2017.3 版本就开始支持,在 2018.1 版本添加了很多的特性。事实上,它是 intellij idea 的 http client 插件。参见笔者之前的另一篇文章: 快速测试 api 接口的新技能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
### 查询用户列表
get http: //localhost:8080/authors
accept : application/json
content-type : application/json;charset=utf- 8
### 查询用户信息
get http: //localhost:8080/authors/15
accept : application/json
content-type : application/json;charset=utf- 8
### 新增方法
post http: //localhost:8080/authors
content-type: application/json
{
"user_id" : "21" ,
"real_name" : "梁桂钊" ,
"nick_name" : "梁桂钊"
}
### 更新方法
put http: //localhost:8080/authors/21
content-type: application/json
{
"real_name" : "lianggzone" ,
"nick_name" : "lianggzone"
}
### 删除方法
delete http: //localhost:8080/authors/21
accept : application/json
content-type : application/json;charset=utf- 8
|
总结
通过,上面这个简单的案例,我们发现 spring boot 整合 kotlin 非常容易,并简化 spring 应用的初始搭建以及开发过程。为了让读者更加熟悉 kotlin 的语法糖,笔者会在未来的几篇文章中,聊聊 kotlin 的新特性及其语法糖。
源代码
相关示例完整代码:spring-kotlin-samples
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:http://blog.720ui.com/2018/springboot2_kotlin_prime/