EC2+RDS+Spring bootで簡単なAPIを作ってみる①

# 概要
spring bootプロジェクトをEC2インスタンス上にデプロイし，とてもシンプルなAPIを作成する手順です．
①ではまずEC2にプロジェクトをデプロイして，POJOを返すAPIを作成してます．

## 本記事のゴール
まずはPOJOを返すとてもシンプルなREST APIをEC2インスタンス上に構築します．
MySQLに接続してデータを取得するのは次回となります．

## 対象者
本記事は細かくspring bootやAWSについての説明はしません．
そのため，とりあえずspringを使ってAWSを試したいという方向けです．

## なお本記事は以下の環境や知識がある前提で進めます
* AWSアカウント
* Java実行環境
* maven環境
* SSH
* （無料版でもいいのでintelliJがあると望ましい）

## 環境
* JDK1.8
* Java8 
* spring boot 2.1.1


## 1. spring bootプロジェクトの作成 ~ REST API構築

### プロジェクト作成

まずは[Spring initializr](https://start.spring.io/)でspring bootプロジェクトの雛形を生成します．
spring initializrとはその名の通り，簡単にspring bootプロジェクトの雛形を作成できます．
バージョン指定ができる他，指定したライブラリなどが入った状態で雛形を作成できるため，とても便利です．

GroupとArtifactはそのままにしましょう．
重要なのはDependenciesです．
Dependenciesに以下を追加しましょう．

* Web
* JPA
* Lombok
* MySQL

追加すると以下のようになります．
![screenshot-start.spring.io-2019.01.31-20-35-37.png](https://qiita-image-store.s3.amazonaws.com/0/214145/ee9883a4-83e3-31fd-cf4d-0ebcfdc538e3.png)


`Generate Priject` を押してプロジェクトをダウンロードしましょう．

### API構築

先ほどダウンロードしたプロジェクトを解凍し，IDEなどで開いてみましょう．
本記事ではintelliJを使用します．

まずは `pom.xml` にあるJPAとMySQLのライブラリをコメントアウトします．
本記事で使用しませんが，次回より使用します． また，ここでコメントアウトしないと後にエラーの原因となります．

```pom.xml
...
       <dependencies>
		<!--<dependency>-->
			<!--<groupId>org.springframework.boot</groupId>-->
			<!--<artifactId>spring-boot-starter-data-jpa</artifactId>-->
		<!--</dependency>-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!--<dependency>-->
			<!--<groupId>mysql</groupId>-->
			<!--<artifactId>mysql-connector-java</artifactId>-->
			<!--<scope>runtime</scope>-->
		<!--</dependency>-->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
...

```

**main配下を以下のようなパッケージ構成にしましょう**
> main
└ java
   　   ┗   com.example.demo
 　　　　┣ controller
　　　　　　　└　PersonController.java
 　　　　┣ service
　　　　　　　└　PersonService.java
 　　　　┣ model
　　　　　　　└　Person.java
　　　　└ DemoApplication.java

intelliJで見て以下のようになっていれば大丈夫です．
<img width="359" alt="スクリーンショット 2019-02-05 0.21.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/214145/e26ee274-80fc-298b-9c02-760dcc395bcb.png">

**それではファイルをそれぞれ以下のように書き換えてください**

```Person.java
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Data
public class Person {
    private String name;
    private Integer age;
    private String gender;
}
```

```PersonService.java
@Service
public class PersonService {
    public Person getPerson(){
        return new Person().builder()
            .name("hoge")
            .age(16)
            .gender("man")
            .build();
    }
}
```

```PersonController.java
@RestController
@RequiredArgsConstructor
public class PersonController {
    private final PersonService personService;

    @RequestMapping(path= "person", method = RequestMethod.GET)
    public Person getPerson(){
        return personService.getPerson();
    }
}
```

*それぞれ`impoet文`を省略してありますので，適宜必要なimport文を記述してください．*


**それでは実行してみましょう**

`http://localhost:8080/person`にアクセスして，以下のようなレスポンスがあれば大丈夫です．
<img width="178" alt="スクリーンショット 2019-02-05 0.30.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/214145/0fc2a880-c81e-5a97-f671-56c6651bd7a0.png">

### パッケージ化する
EC2インスタンス上で実行するため，今回作成したプロジェクトをパッケージ化します．

```
$ mvn clean package
```

これで`target/`にjarファイルが生成されます．

## 2. EC2インスタンスの作成 ~ ターミナルからインスタンスにアクセスしてみる
それではEC2インスタンスを作成してみましょう．
### EC2インスタンスを作成する
まずはAWSにアクセスしましょう．

**①ツールバーのサービスからEC2へ移動します．**
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-02-17.png](https://qiita-image-store.s3.amazonaws.com/0/214145/1e963f3d-6b12-8755-f54e-8120b8afa4cd.png)

**②インスタンスの作成をクリックします．**
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-02-50.png](https://qiita-image-store.s3.amazonaws.com/0/214145/0c9cc906-ded5-b9a4-31dd-046f316affec.png)

**③一番上のAmazon Linuxを選択します．**
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-03-07.png](https://qiita-image-store.s3.amazonaws.com/0/214145/1a9303c5-1043-3764-c976-269ec05bcd8b.png)

**④インスタンス詳細の設定へ**
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-03-32.png](https://qiita-image-store.s3.amazonaws.com/0/214145/ef160096-9e67-7b53-6f5d-fbe912d3c8ad.png)

**⑤セキュリティグループの設定ページまでスキップします**
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-06-15.png](https://qiita-image-store.s3.amazonaws.com/0/214145/0c5aa968-cc7e-2f1d-77cf-cfd507db2d3f.png)

**⑥ルールの追加を行う**
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-06-54.png](https://qiita-image-store.s3.amazonaws.com/0/214145/a83f20d3-9164-7e33-f9c7-0cf1e0174968.png)
完了したら`確認と作成`をクリックします．

**⑦インスタンスの起動**
`起動`をクリックしてインスタンスを起動しましょう．
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-07-35.png](https://qiita-image-store.s3.amazonaws.com/0/214145/aec14141-df3c-4614-00af-db22f65c5754.png)

**⑧キーペアの作成**
まずはキーペア名を入力します．
ダウンロードを行ってからインスタンスの作成を行います．
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-08-17.png](https://qiita-image-store.s3.amazonaws.com/0/214145/acd0591a-7292-6357-17bb-0d71998c7083.png)

インスタンスの作成は以上で完了です．

### EC2インスタンスにsshアクセスしてみる

先ほど作成したインスタンス情報を見てみます．
**パブリックDNSをコピーしておきましょう．**
![screenshot-us-east-2.console.aws.amazon.com-2019.02.05-11-12-13.png](https://qiita-image-store.s3.amazonaws.com/0/214145/d650260a-a215-7ffd-e37f-8e99bd858f55.png)


ダウンロードしたpemファイルを用いてEC2インスタンスにsshアクセスしてみましょう．
*DNSに`ec2-user@`を付けてユーザ指定でログインする必要があります*

```
$ ssh -i ~/Downloads/demo.pem ec2-user@先ほどコピーしたパブリックDNS

// 念の為yum upadateしておきましょう
$ sudo yum update

```

**※ 本来pemファイルは`.ssh/`配下などの適切な場所に配置しましょう．**

アクセスできたら，てきとうなコマンドを実行してみましょう．(lsやcdなど)

### jarファイルをEC2インスタンス上に配置する

sftpコマンドを用いて，ローカルに先ほど作成した`target`配下のjarファイルを，ec2インスタンス上に配置します．

インスタンスから`exit`などでログアウトするか別タブで先ほどのspring bootプロジェクトのディレクトリに移動します．

それでは`sftp`でファイルを転送します．

```
$ sftp -i ~/Downloads/demo.pem ec2-user@先ほどコピーしたパブリックDNS

$ sftp> put target/demo-0.0.1-SNAPSHOT.jar
Uploading target/demo-0.0.1-SNAPSHOT.jar to /home/ec2-user/demo-0.0.1-SNAPSHOT.jar
targ 100%   18MB   1.1MB/s   00:16
```

アップロードが完了したらもう一度EC2インスタンスにログインしてみましょう．

```
$ ssh -i ~/Downloads/demo.pem ec2-user@先ほどコピーしたパブリックDNS

 __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

$ ls
demo-0.0.1-SNAPSHOT.jar
```

lsコマンドでjarファイルがアップロードされていることを確認しましょう．

### jarファイル実行

それではec2インスタンス上のjarを実行をします．

```
$ $ java -jar demo-0.0.1-SNAPSHOT.jar
Exception in thread "main" java.lang.UnsupportedClassVersionError: org/springframework/boot/loader/JarLauncher : Unsupported major.minor version 52.0
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:808)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:443)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:65)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:349)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:348)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:430)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:323)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:363)
	at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
```

おっとエラーが起きました．
今回ローカルではJava1.8で開発を行ったのですが，Amazon linuxでデフォルトで入っているJavaのバージョンは1.7になっているためエラーが発生します．

```
$ java -version
java version "1.7.0_201"
OpenJDK Runtime Environment (amzn-2.6.16.0.78.amzn1-x86_64 u201-b00)
OpenJDK 64-Bit Server VM (build 24.201-b00, mixed mode)
```

まずはJava1.8をインストールしましょう．

```
$ sudo yum install -y java-1.8.0-openjdk.x86_64
```

`alternatives`コマンドでバージョンを切り替えます

```
$ sudo alternatives --config java

2 プログラムがあり 'java' を提供します。

  選択       コマンド
-----------------------------------------------
*+ 1           /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
   2           /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java

Enter を押して現在の選択 [+] を保持するか、選択番号を入力します:2

$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
```

バージョンが切り替わった事を確認したら再度実行してみます．

```
$ java -jar demo-0.0.1-SNAPSHOT.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)
~
2019-02-05 02:55:55.282  INFO 8556 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
~
```

無事起動できたらブラウザから，もしくはcurlなどでアクセスしてみましょう．

<img width="1070" alt="スクリーンショット 2019-02-05 12.13.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/214145/7e2070d2-98a6-11a0-dde3-e316ed9d1445.png">

```
$ curl http://作成したec2インスタンスのDNS:8080/person
{"name":"hoge","age":16,"gender":"man"}
```

無事にjsonが返ってきてますね．

以上，EC2 + spring bootで簡単にAPIを作成する編でした．
色々端折った所も多いので，躓いたポイントなどコメントしていただけると助かります．

※ 使用していない時はインスタンスを停止しておくことをオススメします．

次回
EC2+RDS+Spring bootで簡単なAPIを作ってみる②　※執筆中