使用 Spring + kotlin 实现 CURD 应用

在 10 小时前,我还对kotlinspring-boot以及gradle不是很了解,但现在已经知道该如何使用它们运行一个简单的CURD应用了(或者说玩具更合适?)

虽然网上已经有很多比我写得更好的教程,不过自己写一遍能够加深印象,并且从初学者的角度记录,所以这篇笔记适合和我一样,之前没有接触过javaspring等等这些后端相关知识的人,或许能够有所收获。

项目准备

  • 可以上网的电脑(最好能翻墙)
  • 配置好了java环境
  • 安装了IDEA(虽然可以不用,但最好有)
  • Docker(或者安装好了Mysql数据库并启动)

初始化项目

http://start.spring.io/ 下载脚手架,Group默认为com.exampleArtifact改成kotlinDemo,这里一致后面代码就可以直接拷贝。

初始化项目

点击Generate Project后会下载一个压缩包,将压缩包解压到文件夹,使用IDEA打开该文件夹,文件目录应该是这样的:

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
.
├── build.gradle
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src
├── main
│   ├── kotlin
│   │   └── com
│   │   └── example
│   │   └── koltinDemo
│   │   └── KoltinDemoApplication.kt
│   └── resources
│   ├── application.properties
│   ├── static
│   └── templates
└── test
└── kotlin
└── com
└── example
└── koltinDemo
└── KoltinDemoApplicationTests.kt

打开后会出现该界面:
import Project

表示识别为一个Gradle项目,点击“OK”即可。

然后IDEA会下载依赖,等待下载即可。

如果不成功,翻墙后重试;最难下载的应该是gradle这个包;如果不使用IDEA,使用命令行进入项目根目录,运行./gradlew build

启动项目

下载成功后,先将build.gradledependencies两个依赖先暂时注释:

1
2
3
4
5
6
7
8
dependencies {
// compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}")
compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
// runtime('mysql:mysql-connector-java')
testCompile('org.springframework.boot:spring-boot-starter-test')
}

右下角出现该提示时,表示IDEA识别到修改,点击“Import Changes”。
import changes

spring-boot-starter-data-jpaspring-boot-starter-data-jpa是用来连接数据库的,因为暂时还没有数据库直接运行会无法启动。

注释之后,就可以点击右上角的运行按钮来启动项目。
运行项目

当看到下方控制台打印了如下信息,并且没有报错,就表示运行成功:

成功启动服务器

不使用IDEA则在项目根目录下使用命令./gradlew bootRun运行项目。

如果出现该错误提示:

1
Cannot determine embedded database driver class for database type NONE

没有配置数据库

则表示需要暂时注释和数据库有关的依赖,或者在resource/application.properties中配置数据库信息。

运行成功后,打开浏览器http://127.0.0.1:8080,可以看到如下页面:

index page

虽然显示Error,但成功表示我们运行起了服务器,只是还没有配置该显示什么内容。

如果是如下内容:

not hava server

就表示根本没有服务器在运行,检查IDEA下面控制台是否和上面成功的截图一样,重新打开浏览器查看。

第一个页面

kotlinDemo文件夹下,新增Controller.kt文件,内容如下:

1
2
3
4
5
6
7
8
9
package com.example.koltinDemo

import org.springframework.web.bind.annotation.*

@RestController
class Controller {
@RequestMapping("/")
fun get() = "Hello Spring and kotlin"
}

如果使用IDEA,则更加方便

创建文件

而且只需要在新生成的文件内,添加:

1
2
3
4
5
@RestController
class Controller {
@RequestMapping("/")
fun get() = "Hello Spring and kotlin"
}

然后点击@RestController,按下键盘option + enter,如果是Windows应该是ctrl + enter?就会自动添加import org.springframework.web.bind.annotation.*这一行。

OK,到此我们第一个页面就写好了,重新运行项目(停止并启动)。刷新页面(如果还没有关闭的话,否则就再次打开127.0.0.1:8080),Wow!页面出现了“Hello Spring and kotlin”,而不是之前让人讨厌的Error字眼。

第一个页面

连接数据库

好了,令人激动的环节到了,这也是折腾了我最久的环节,虽然现在感觉So easy

初始化数据库

我们使用Docker来运行一个数据库供我们使用,很简单:

1
docker run --name store_db -d -e MYSQL_ROOT_PASSWORD=123 -e MYSQL_DATABASE=store -p 3306:3306 mysql:latest

然后查看下是否启动成功:

1
docker ps -a

如果出现
启动 mysql

则表示创建mysql数据库成功,

同时需要注意STATUS必须为Up,且PORTS必须为0.0.0.0:3306->3306/tcp

OK,接下来就直接连接数据库并向其插入数据吧!

配置数据库信息

还记得之前注释的数据库相关依赖吗,将其取消注释(注意Import Changes):

1
2
3
4
5
6
7
8
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}")
compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
runtime('mysql:mysql-connector-java')
testCompile('org.springframework.boot:spring-boot-starter-test')
}

然后在resource/application.properties中添加如下内容:

1
2
3
4
5
6
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/store?autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=123
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = create-drop

重新启动项目,刷新页面,和之前一样?哦,那真是太好了,没有错误就是好消息。

创建实体

实体是什么,用来做什么?额,大概就是类似于约定数据库中的表会有什么样的字段,以及如何操作数据库的东西?

增加Entity.kt文件,添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.example.koltinDemo

import javax.persistence.*

@Entity
@Table(name = "user")
data class Customer(
var firstName: String = "",
var lastName: String = "",

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
var id: Long = 0
)

这将表示我们会在store数据库中,有一张user表,表会有idfirstNamelastName字段。

然后再增加Interface.kt文件,内容如下:

1
2
3
4
5
6
7
package com.example.koltinDemo

import org.springframework.data.jpa.repository.JpaRepository


interface StoreRepository : JpaRepository<Customer, Long> {
}

插入数据库

然后将Controller.kt改写为如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.koltinDemo

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*

@RestController
class CustomerController
@Autowired constructor(val repository: StoreRepository) {

@RequestMapping("/")
fun findAll() = repository.findAll()

@RequestMapping("/create", method = arrayOf(RequestMethod.POST))
@ResponseBody
fun create(@RequestBody customer: Customer): Customer = repository.save(customer)
}

OK,重启服务,再次刷新页面。页面上没有可爱的Hello Spring了,而是变成了[],但这更可爱好吗,这表示我们从数据中读取数据了!虽然数据库中还是空的。

所以我们要向数据库中插入数据,如果你有Postman那就简单多了,没有也没事,我们使用命令行来实现。

在命令行输入如下内容:

1
2
3
curl -i -H "Content-Type: application/json" -X POST 
-d '{"firstName": "Hello", "lastName": "Spring framework"}'
http://localhost:8080/create

{"firstName": "Hello", "lastName": "Spring framework"}就是我们要发送的数据。

如果显示

1
2
3
4
5
6
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 25 Nov 2017 07:10:14 GMT

{"firstName":"Hello","lastName":"Spring framework","id":1}%

就表示成功了!再次刷新我们的浏览器页面看看,有数据了!!

万一没有,检查是否有HTTP/1.1 200字样,如果没有就用Postman试试看,如下:

使用Postman 插入数据

这样是表示成功,重点是那个200 OK

插入数据成功

查找数据

当然现在也可以算实现了查找,只是查找所有的数据而已,接下来我们实现根据lastName查找数据。

Interface.kt改写为如下:

1
2
3
interface StoreRepository : JpaRepository<Customer, Long> {
fun findByLastName(name: String): List<Customer>
}

Controller变成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
class CustomerController
@Autowired constructor(val repository: StoreRepository) {

@RequestMapping("/")
fun findAll() = repository.findAll()

@RequestMapping("/create", method = arrayOf(RequestMethod.POST))
@ResponseBody
fun create(@RequestBody customer: Customer): Customer = repository.save(customer)
// 这里是新增的
@RequestMapping("/{name}")
fun findByLastName(@PathVariable name: String) = repository.findByLastName(name)
}

重启服务,先随便插入几条不同的数据,访问首页看看效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"firstName": "Hello",
"lastName": "Kotlin",
"id": 1
},
{
"firstName": "Hello",
"lastName": "World",
"id": 2
},
{
"firstName": "Hello",
"lastName": "ltaoo",
"id": 3
},
{
"firstName": "Hello",
"lastName": "Spring-boot",
"id": 4
}
]

插入的数据,现在我们要查询lastNameltaoo的记录,看是否存在。在地址栏后面增加/ltaoo,地址变成:http://127.0.0.1:8080/ltaoo,回车,页面只显示一条记录了,而且正是lastNameltaoo的那条,表示查询成功。

更新数据

Controller.kt增加如下代码,就按照之前添加代码的方式位置一样。

1
2
3
4
@PutMapping("/update")
fun updateUser(@RequestBody user: Customer) {
repository.save(user)
}

重启服务,同样先随便插入几条数据,然后用命令行或者Postman发送如下数据:

1
2
3
curl -i -H "Content-Type: application/json" -X PUT                                                                               ltaoo@ltaoodeMacBook-Pro
-d '{"firstName": "UPdate", "lastName": "Data", "id": 1}'
http://localhost:8080/update

表示发送的数据为{"firstName": "UPdate", "lastName": "Data", "id": 1},且这次发送的方式为PUT,之前插入数据是用POST。除了数字 1 之外,都要用双引号包裹。

这表示要将id为 1 的这条数据,firstName修改为UpdatelastName修改为Data,回车后显示200,就表示成功, 刷新页面也能看到新修改的数据。

删除数据

同样是Controller.kt,增加如下代码:

1
2
3
4
5
@DeleteMapping("/del/{id}")
@ResponseBody
fun deleteEmployee(@PathVariable id: Long) {
repository.delete(id)
}

重启服务,先增加两条记录,然后使用命令行发送如下命令:

1
2
curl -i -H "Content-Type: application/json" -X DELETE                                                                            ltaoo@ltaoodeMacBook-Pro
http://localhost:8080/del/1

表示已DELETE方式请求http://localhost:8080/del/1地址。从这里可以看到增删改查对应了四种请求方式POSTDELETEPUTGET

然后刷新浏览器页面查看所有数据,会发现原本两条数据只剩一条了,表示删除成功。

总结

到此,就完成了一个能够实现向数据库增删改查的Web应用了,全部的代码加起来可能都不超过两百行,这就是Spring-boot的强大之处吧。

当然这个应用很简陋,甚至都算不上应用,只是一个玩具,但这是作为学习Kotlin甚至说学习后端开发的一个起点,一个萌芽。

学习的过程就是不断搜索、学习、总结的过程,总体来说,从中我收获了:

  • 了解了gradle是什么,用来做什么,怎么用。
  • 了解了Spring连接数据库的方式
  • 学习如何从Post请求中接收数据
  • 知道了什么是实体
  • 知道了@RestController@RequestMapping以及@PathVariable这些装饰器?的作用
  • 知道了一个Spring项目基本结构
  • 知道了什么是包package
  • 知道了在IDEA中如何自动导包
  • kotlin语法有了一丢丢的了解

以及很多很多,收获满满,最后很感谢愿意在网上分享博客的同学。

最后附上打包的代码,虽然不知道能不能够直接运行,但能看是肯定的。
https://pan.baidu.com/s/1c2jNs3Y

遇到的问题

在过程中遇到很多问题,有自己代码写错的,也有大小写错误的,但每一个问题都值得记录下来,说不定也能给别人以启发呢。

unresolved reference xxx

复制代码后IDEA提示这个,表示这个变量找不到来源,使用option + enter也不能自动导包,我遇到的可能有两种情况

  • 该变量对应的依赖未在build.gradle中配置
  • 该变量依赖项目中的包,但是路径配置不正确

ApplicationEventMulticaster not initialized - call ‘refresh’ before multicasting events via the cont

可能是重复写了某个函数,记不太清了。

Error creating bean with name xxx

代码写得有问题,具体上面问题不知道。。。

Cannot determine embedded database driver class for database type NONE

没有配置数据库信息

Warning about SSL connection when connecting to MySQL database

数据库地址后面必须加上?autoReconnect=true&useSSL=falsejdbc:mysql://localhost:3306/Peoples?autoReconnect=true&useSSL=false

参考

原文:大专栏  使用 Spring + kotlin 实现 CURD 应用


猜你喜欢

转载自www.cnblogs.com/petewell/p/11601735.html