Kotlin + SpringBootで最小のWebAPIを構築する

## 概要
- Kotlin + SpringBootを扱ってみましたので、環境構築メモです。
- Spring Data JPAでテーブルアクセスし、JSON形式でブラウザに返却するところまでを書いております。

## Springプロジェクトを作成する
- [Spring Initializr](https://start.spring.io/)を使います。
- 設定は下記のようにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469694/f4a205cf-d908-9b6e-29b3-b4ebb0cd1271.png)

## IntelliJ IDEAをダウンロード
- [IntelliJ IDEA](https://www.jetbrains.com/idea/download/)をダウンロードします。
- Community版(無料)で大丈夫です。

## 作成したプロジェクトを取り込む
- IntelliJ IDEAより [File] -> [Open...] を選択し、作成したプロジェクトを取り込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469694/cf88dbaa-978b-86bb-ef9b-8d9ffcaa0b4c.png)

## JPAをコメントアウト

```build.gradle.kts
dependencies {
//	implementation("org.springframework.boot:spring-boot-starter-data-jpa")
	implementation("org.springframework.boot:spring-boot-starter-web")
	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
	implementation("org.jetbrains.kotlin:kotlin-reflect")
	implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
	compileOnly("org.projectlombok:lombok")
	annotationProcessor("org.projectlombok:lombok")
	testImplementation("org.springframework.boot:spring-boot-starter-test")
}
```

## Controllerを書く
- Controllerクラスを書きます。
- 事前にcontrollerパッケージを作成しておきます。

```DemoController.kt
package com.example.demo.controller

import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/demo")
class DemoController {

    @GetMapping("/getAll")
    fun getAll(): ResponseEntity<String> {
        return ResponseEntity.ok("Demo")
    }

}
```

## プロジェクトを起動する
- [View] -> [Tool Windows] -> [Gradle] -> [Tasks] -> [application] -> [bootRun] を選択してプロジェクトを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469694/fd95dc59-209b-55e7-384e-8343a6d8ebde.png)

- 下記のようなログが出ればOKです。

```
18:32:18: Executing task 'bootRun'...

> Task :compileKotlin
> Task :compileJava NO-SOURCE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :bootRunMainClassName

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.3)

2021-03-13 18:32:21.905  INFO 8184 --- [           main] com.example.demo.DemoApplicationKt       : Starting DemoApplicationKt using Java 1.8.0_241 on DESKTOP-I88K5MF with PID 8184 
2021-03-13 18:32:21.905  INFO 8184 --- [           main] com.example.demo.DemoApplicationKt       : No active profile set, falling back to default profiles: default
2021-03-13 18:32:23.034  INFO 8184 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-03-13 18:32:23.050  INFO 8184 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-03-13 18:32:23.050  INFO 8184 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.43]
2021-03-13 18:32:23.128  INFO 8184 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-03-13 18:32:23.128  INFO 8184 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1155 ms
2021-03-13 18:32:23.425  INFO 8184 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-03-13 18:32:23.662  INFO 8184 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-03-13 18:32:23.677  INFO 8184 --- [           main] com.example.demo.DemoApplicationKt       : Started DemoApplicationKt in 2.308 seconds (JVM running for 2.822)
2021-03-13 18:32:26.108  INFO 8184 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-03-13 18:32:26.108  INFO 8184 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-03-13 18:32:26.116  INFO 8184 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 8 ms

```

- ブラウザで[http://localhost:8080/demo/getAll]()を表示する → Demoが表示されます。

## JPAでデータアクセスするためにMysqlを準備
- テーブルを作っておきます。

```sql
create database demo;
use demo;
create table demo (
	id int auto_increment,
	name varchar(256),
	PRIMARY KEY (id)
);
insert into demo (name) values ("test");
```

## application.propertiesに設定を追加

```application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update
```

参考：
[JavaでDB(MySQL)接続しようとするとエラーが出る解決策](https://qiita.com/xxbanikoxx/items/2de2e662357918d5e9b1)
[SpringBoot + Spring JPAでデータベースに接続する](https://qiita.com/t-iguchi/items/685c0a1bb9b0e8ec68d2)

## JPAをコメントアウトはずし、Driverの追加

```diff:build.gradle.kts

dependencies {
+	implementation("org.springframework.boot:spring-boot-starter-data-jpa")
	implementation("org.springframework.boot:spring-boot-starter-web")
	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
	implementation("org.jetbrains.kotlin:kotlin-reflect")
	implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
+	implementation("mysql:mysql-connector-java:8.0.20")
	compileOnly("org.projectlombok:lombok")
	annotationProcessor("org.projectlombok:lombok")
	testImplementation("org.springframework.boot:spring-boot-starter-test")
}
```

## Entity作成
- 事前にentityパッケージを作成しておきます。
- Demo.ktを書きます。

```kotlin:Demo.kt
package com.example.demo.entity

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id

@Entity
class Demo (
        var name: String? = null,
        @Id
        @GeneratedValue
        var id: Long? = null)
```

## Repository作成
- 事前にrepositoryパッケージを作成しておきます。
- DemoRepository.ktを作成します。

```kotlin:DemoRepository.kt
package com.example.demo.repository

import com.example.demo.entity.Demo
import org.springframework.data.repository.CrudRepository

interface DemoRepository : CrudRepository<Demo, Long> {
    fun findAllByOrderById(): Iterable<Demo>
}
```

## Controllerを修正

```kotlin:DemoController.kt

package com.example.demo.controller

import com.example.demo.entity.Demo
import com.example.demo.repository.DemoRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/demo")
class DemoController @Autowired constructor(  //修正
        val demoRepository: DemoRepository)   //修正
{                                             //修正   

    @GetMapping("/getAll")
    fun getAll(): ResponseEntity<Iterable<Demo>> {             //修正
        val demos = demoRepository.findAllByOrderById()        //修正  
        return ResponseEntity.ok(demos)                        //修正 
    }

}
```

## ブラウザで表示する
- ブラウザで[http://localhost:8080/demo/getAll]()を表示します 
- 下記のようにDBに登録されたデータが返却されていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469694/9be382fa-f336-7311-8dda-68f8729c6022.png)


## まとめ
- kotlin + Spring BootでJSONをGetするところまでやりました。何かの参考になれば幸いです。

参考:
[Getting started with Spring Data JPA](https://spring.io/blog/2011/02/10/getting-started-with-spring-data-jpa/)
[Kotlin with Spring Boot 2.0で簡単なRest APIを実装する](https://qiita.com/rubytomato@github/items/daa723db5deffc908df7)