【試行】KotlinとSpring Bootの組み合わせでIntelliJプロジェクト作成からローカル環境でのアプリケーション起動まで

# お題
表題について、実践。
KotlinもSpring Bootも業務では未経験で、何年か前に独学で少しやったくらいなので、まったくもって新鮮な気持ちで始める。

今回のソース全量は下記。
https://github.com/sky0621/try-kotlin-springboot/tree/master/trykotlinspringboot

# 開発環境
### # OS - Linux(Ubuntu)
```
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
```

### # IDE - IntelliJ IDEA
```
IntelliJ IDEA 2019.1.2 (Community Edition)
Build #IC-191.7141.44, built on May 7, 2019
JRE: 1.8.0_202-release-1483-b49 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Linux 4.15.0-47-generic
```

### # Kotlin
```
Current Kotlin plugin version: 1.3.31-release-IJ2019.1-1
```

### # Java
```
11(java version "11.0.3"
```

### # Spring Boot
```
2.1.5
```

### # Docker
```
$ sudo docker version
Client:
 Version:           18.09.2
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        6247962
 Built:             Tue Feb 26 23:52:23 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.09.2
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       6247962
  Built:            Wed Feb 13 00:24:14 2019
  OS/Arch:          linux/amd64
  Experimental:     false
```

# 実践

## プロジェクト作成

### 01) IntelliJのメニューより、 [File] -> [New] -> [Project...] を選択

### 02) Spring Assistantを選択し、Project SDKを選択後、 [Next] 押下

![Screenshot from 2019-05-28 09-08-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/cfb43824-153d-3187-af34-196bd9c51183.png)

### 03) Project Typeは「`Gradle Project`」、Languageは「`Kotlin`」、Java versionは「`11`」を選択後、 [Next] 押下

![Screenshot from 2019-05-28 09-16-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/642f2333-1bc6-d5fa-a5b9-f0e0dab7ee07.png)

### 04) 使用ライブラリの選定後、 [Next] 押下

正直、今の時点で何を使うかなんてわからない。。。
ので、適当な感覚で選定。

| Category | Name | Description | URL |
| --- | --- | --- | --- |
| Core | DevTools | Spring Boot Development Tools | https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/#using-boot-devtools |
| Web | Web | Servlet web application with Spring MVC and Tomcat | https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications |
| Template Engines | Thymeleaf | Thymeleaf templating engine | https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-template-engines |
| Security | Security | Secure your application via spring-security | https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/#boot-features-security |
| SQL | JPA | Persist data in SQL stores with Java Persistence API using Spring data and Hibernate | https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/#boot-features-jpa-and-spring-data |
| SQL | MySQL | MySQL JDBC driver | https://spring.io/guides/gs/accessing-data-mysql/ |
| SQL | JDBC | Persistent support using JDBC | https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/#boot-features-sql |

![Screenshot from 2019-05-29 09-10-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/475be9bc-4a40-7624-696b-668cfbba0a82.png)

### 05) プロジェクト名を決めて、 [Finish] 押下
後、 [Next] 押下
![Screenshot from 2019-05-29 09-11-52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/a6827b6c-298a-5396-d49a-10476381fd3f.png)

### 06) プロジェクト完成

![Screenshot from 2019-05-29 09-16-26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/90775527-8d21-967c-9979-72a693ff4932.png)

画面右下に「Unlinked Gradle project?」とあり、「`Import Gradle project`」というリンクがあるので押下。
表示されたウインドウにてデフォルトのまま「OK」押下。
すると、、、

![Screenshot from 2019-05-29 09-19-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/705bf5d8-997d-d0f9-d05d-aa1031a4fb58.png)

Gradleプロジェクトとしてのセッティング？？

そして、終わったかと思いきや、「IDE Error Occurred」。

![Screenshot from 2019-05-29 09-24-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/8eda062a-ba35-d4e5-3312-e2c7afb6e61c.png)

「`See Details and Submit Report`」押下すると、NullPointerExceptionが起きていた。。。

![Screenshot from 2019-05-29 09-25-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/94942056-98f6-a197-65f8-6c4f56ba71f6.png)

ただ、以下の通り、ひとまず必要そうなファイルは生成されているようなので、いったんプロジェクト作成完了としよう。

![Screenshot from 2019-05-29 09-28-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/304978f9-dc56-1c96-0b2a-47f189378309.png)

## ローカル起動

ソースの中身の確認などはさておき、まずは起動。
![Screenshot from 2019-05-29 09-38-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/939979b5-1d3a-41f7-0b80-2fcb46e8e44e.png)
ん？　起動に失敗した。

```
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class


Action:

Consider the following:
	If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
	If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
```

なるほど、プロジェクト作成時のライブラリ選定で「`JPA`」とか「`MySQL`」とかDB使う想定でチェック付けたけど、「DB使うんだからデータソースの定義しろ！」ってことか。
そういえば、JDBCドライバーが必要か。
ソースコード中でDB使うコードを書いていなくても、アプリケーション起動の時点でそのへんチェック入るんだね。

## データソースの定義

ひとまず定義があればいいのかな。

```properties:[application.properties]
spring.datasource.url=jdbc:mysql://localhost:3306/xxxx
spring.datasource.username=xxxx
spring.datasource.password=xxxx
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update
```

## 再度ローカル起動

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

2019-05-30 09:05:43.971  INFO 4897 --- [  restartedMain] com.example.demo.DemoApplicationKt       : Starting DemoApplicationKt on sky0621-W950JU with PID 4897 (/home/sky0621/work/src/kotlin/github.com/sky0621/trykotlinspringboot/build/classes/kotlin/main started by sky0621 in /home/sky0621/work/src/kotlin/github.com/sky0621/trykotlinspringboot)
2019-05-30 09:05:43.977  INFO 4897 --- [  restartedMain] com.example.demo.DemoApplicationKt       : No active profile set, falling back to default profiles: default
2019-05-30 09:05:44.133  INFO 4897 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
　　　　　　　　〜〜〜　省略　〜〜〜
2019-05-30 09:05:48.459  INFO 4897 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-05-30 09:05:48.465  WARN 4897 --- [  restartedMain] com.zaxxer.hikari.util.DriverDataSource  : Registered driver with driverClassName=com.mysql.jdbc.Driver was not found, trying direct instantiation.
2019-05-30 09:05:49.579 ERROR 4897 --- [  restartedMain] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Exception during pool initialization.

com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
	at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:835) ~[mysql-connector-java-8.0.16.jar:8.0.16]
　　　　　　　　〜〜〜　省略　〜〜〜
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.1.5.RELEASE.jar:2.1.5.RELEASE]
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

　　　　　　〜〜〜　省略　〜〜〜

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
　　　　　　　　〜〜〜　省略　〜〜〜
	at com.mysql.cj.NativeSession.connect(NativeSession.java:152) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:955) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	... 53 common frames omitted
Caused by: java.net.ConnectException: Connection refused (Connection refused)
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:na]
	at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399) ~[na:na]
	at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242) ~[na:na]
　　　　　　　　〜〜〜　省略　〜〜〜
	at java.base/java.net.Socket.connect(Socket.java:591) ~[na:na]
	at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:155) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:65) ~[mysql-connector-java-8.0.16.jar:8.0.16]
	... 56 common frames omitted


Process finished with exit code 0
```
例外発生。実際にDBに接続しにいくようなので、ローカル環境にMySQLサーバ立てるか。

## ローカル環境にてMySQLサーバ起動

docker-composeでMySQLコンテナ立てることにする。
**※Dockerならびにdocker-compose自体のインストールやらセッティングやらは記事内容と無関係なので省略**

### docker-compose.ymlを作成

```yaml:[docker-compose.yml]
version: '3'
services:
  db:
    restart: always
    image: mysql:5.7.24
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_USER: localuser
      MYSQL_PASSWORD: localpass
      MYSQL_DATABASE: localdb
```

### MySQLコンテナ起動

```
$ sudo docker-compose up
Creating network "trykotlinspringboot_default" with the default driver
Pulling db (mysql:5.7.24)...
5.7.24: Pulling from library/mysql
177e7ef0df69: Pull complete
cac25352c4c8: Pull complete
8585afabb40a: Pull complete
1e4af4996053: Pull complete
c326522894da: Pull complete
9020d6b6b171: Pull complete
55eb37ec6e5f: Pull complete
1a9d2f77e0e7: Pull complete
d7e648ad64aa: Pull complete
4120d828ea6b: Pull complete
3b39dc5451af: Pull complete
Creating trykotlinspringboot_db_1_7075558a2fe2 ... done
Attaching to trykotlinspringboot_db_1_dae5d2a605f3
db_1_dae5d2a605f3 | Initializing database
db_1_dae5d2a605f3 | 2019-05-30T00:33:54.062776Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
db_1_dae5d2a605f3 | 2019-05-30T00:33:54.510746Z 0 [Warning] InnoDB: New log files created, LSN=45790
db_1_dae5d2a605f3 | 2019-05-30T00:33:54.597840Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
db_1_dae5d2a605f3 | 2019-05-30T00:33:54.670311Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 9acfcca7-8272-11e9-98b0-0242ac1c0002.
db_1_dae5d2a605f3 | 2019-05-30T00:33:54.671851Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
db_1_dae5d2a605f3 | 2019-05-30T00:33:54.672400Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.

　　〜〜〜　省略　〜〜〜

db_1_dae5d2a605f3 | 2019-05-30T00:34:06.132207Z 0 [Warning] 'tables_priv' entry 'user mysql.session@localhost' ignored in --skip-name-resolve mode.
db_1_dae5d2a605f3 | 2019-05-30T00:34:06.132223Z 0 [Warning] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode.
db_1_dae5d2a605f3 | 2019-05-30T00:34:06.136900Z 0 [Note] Event Scheduler: Loaded 0 events
db_1_dae5d2a605f3 | 2019-05-30T00:34:06.137378Z 0 [Note] mysqld: ready for connections.
db_1_dae5d2a605f3 | Version: '5.7.24'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
```

### MySQLコンテナ起動確認

```
$ sudo docker ps
[sudo] password for sky0621: 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
358a3965bd0e        mysql:5.7.24        "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        0.0.0.0:3306->3306/tcp, 33060/tcp   trykotlinspringboot_db_1_dae5d2a605f3
```

```
$ sudo docker ps
[sudo] password for sky0621: 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
358a3965bd0e        mysql:5.7.24        "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        0.0.0.0:3306->3306/tcp, 33060/tcp   trykotlinspringboot_db_1_dae5d2a605f3
$
$ sudo docker exec -it 358a3965bd0e /bin/sh
# mysql -u localuser -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.24 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| localdb            |
+--------------------+
2 rows in set (0.00 sec)

mysql> 
```

### データソースの定義

`docker-compose.yml`記載のDB接続情報に従い、以下のように修正。

```properties:[application.properties]
spring.datasource.url=jdbc:mysql://localhost:3306/localdb
spring.datasource.username=localuser
spring.datasource.password=localpass
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update
```

## 再々度ローカル起動

今度は起動したようだ。
![Screenshot from 2019-05-30 09-40-53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180599/a716dfa9-302d-f988-92f7-fe596b162a61.png)

```
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
```
非推奨のJDBCドライバーを使っていたことで警告されていた様子。
「ドライバはSPIを介して自動的に登録され、ドライバクラスの手動ロードは通常不要です。」とのこと。
ライブラリ選定時に「`JDBC`」にチェック付けたけど、それが不要だったんだろうか・・・。

# 備考
Springプロジェクトの作成は、IntelliJ に標準で付いていた Spring Assistant を使った。
以下に同様の機能を持っていると思われるWeb版(?)もあるみたい。
https://start.spring.io/