Spring + Kotlin 實現最簡 CURD 應用

在 10 小時前,我還對kotlinspring-boot以及gradle不是很了解,但現在已經知道該如何使用它們運行一個簡單的CURD應用了。

于是記錄下來,雖然網上已經有很多教程,不過自己寫一遍能夠加深印象。所以這篇筆記適合和我一樣,之前沒有接觸過javaspring等等這些后端相關知識的人。

項目準備

  • 可以上網的電腦(最好能翻墻)
  • 配置好了java環境
  • 安裝了IDEA(雖然可以不用,但最好有)
  • Docker(或者安裝好了Mysql數據庫并啟動)

初始化項目

http://start.spring.io/ 下載腳手架,Group默認為com.exampleArtifact改成kotlinDemo,這里一致后面代碼就可以直接拷貝。

初始化項目

這里 kotlinDemo 寫成了 koltinDemo 導致后面都是錯的,尷尬??

點擊Generate Project后會下載一個壓縮包,將壓縮包解壓到文件夾,使用IDEA打開該文件夾,文件目錄應該是這樣的:

.
├── 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兩個依賴先暫時注釋:

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運行項目。

如果出現該錯誤提示:

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文件,內容如下:

package com.example.koltinDemo

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

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

如果使用IDEA,則更加方便

創建文件

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

@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來運行一個數據庫供我們使用,很簡單:

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

然后查看下是否啟動成功:

docker ps -a

如果出現


啟動 mysql

則表示創建mysql數據庫成功,

同時需要注意STATUS必須為Up,且PORTS必須為0.0.0.0:3306->3306/tcp

OK,接下來就直接連接數據庫并向其插入數據吧!

配置數據庫信息

還記得之前注釋的數據庫相關依賴嗎,將其取消注釋(注意Import Changes):

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中添加如下內容:

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文件,添加如下內容:

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文件,內容如下:

package com.example.koltinDemo

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


interface StoreRepository : JpaRepository<Customer, Long> {
}

插入數據庫

然后將Controller.kt改寫為如下內容:

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那就簡單多了,沒有也沒事,我們使用命令行來實現。

在命令行輸入如下內容:

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

{"firstName": "Hello", "lastName": "Spring framework"}就是我們要發送的數據。

如果顯示

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改寫為如下:

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

Controller變成這樣:

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)
}

重啟服務,先隨便插入幾條不同的數據,訪問首頁看看效果。

[
  {
    "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增加如下代碼,就按照之前添加代碼的方式位置一樣。

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

重啟服務,同樣先隨便插入幾條數據,然后用命令行或者Postman發送如下數據:

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,增加如下代碼:

@DeleteMapping("/del/{id}")
@ResponseBody
fun deleteEmployee(@PathVariable id: Long) {
    repository.delete(id)
}

重啟服務,先增加兩條記錄,然后使用命令行發送如下命令:

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

參考

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容