はじめに
「PoCやるんだけど、こういうの用意できない?
とりあえず動けばいいから明日までに」
どうする
いやです
という言葉を飲み込んで
さっさと作っていきましょう。
いろいろ選択肢があるのは存じていますが、当方JavaエンジニアなのでバックエンドはSpring Bootです。
インフラには、忙しいときの心強い味方 Heroku を使います。
環境
OS
- macOS Catalina
ツール・ソフトウェア
- IntelliJ IDEA 2020.2.4
- Java v1.8.0_111
- Git v2.29.2
- Heroku CLI v7.47.0 (https://devcenter.heroku.com/articles/heroku-cli)
バックエンドから
Spring Initializrで雛形を生成します。
PCの都合でJavaは8。
Dependencies(ライブラリ)ですが、Spring WebがあればとりあえずOK。
Lombokは…IDEの設定にひと手間かかるのでやめときます。急いでるので。
zipをダウンロード&解凍し、任意のIDEで開いたら、まずダミーデータを返すAPIを作っていきます。
com.example
パッケージの下にcontroller
とmodel
を追加し、以下のクラスを作成します。
package com.example.demo.model;
// 部署クラス
public class Department {
public String name;
public Department(String name) {
this.name = name;
}
}
package com.example.demo.model;
// 社員クラス
public class Employee {
public String name;
public Department department;
public Employee(String department, String name) {
this.department = new Department(department);
this.name = name;
}
}
package com.example.demo.controller;
import com.example.demo.model.Employee;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
@GetMapping // 『GET /api/employees』で実行されるようにマッピング
public List<Employee> getEmployees() {
List<Employee> results = new ArrayList<>();
results.add(new Employee("営業", "社員 太郎"));
results.add(new Employee("開発", "社員 次郎"));
return results;
}
}
DemoApplication
を起動します。
IDEの機能でも、コマンドラインから./gradlew bootRun
でもOKです。
ブラウザを開き、http://localhost:8080/api/employees
にアクセス。
動いてますね。ヨシ。
Heroku上で動かす
次は稼働環境を用意します。
Heroku上にデプロイしてAPIを公開してみましょう。
リンク先でHerokuの無料アカウントを作成したら、右上のメニューから「Create new app」を選択。
好きなアプリ名を入力し、ふたたび「Create new app」をクリック。
アプリが作成されると、デフォルトで「Deployment」タブが開いてるかと思います。
デプロイ方法(Deployment method)が3つ並んでいますので、「Heroku Git」を選択。
その下に書かれている手順とコマンドに従って、アプリをデプロイします。
ざっくり言うと、gitリポジトリをローカルに作成→herokuをリモートに設定→push という流れです。
Heroku CLIのインストールを忘れずに。
HerokuはgradleとSpring Bootを自動で認識してくれるので、設定ファイルの追加等は不要です。
エラーが出ずに終了したら、「Overview」タグを開いて右側のアクティビティを確認。
無事にデプロイされたようです。
続いて右上の「Open App」ボタンをクリック。404画面が出てきますが、くじけずURLに「/api/employees」を追加。
これでOK。これ以降はpushするたびにアプリが自動で更新されていきます。便利!
DBを用意する
続いてDBですが、Herokuに任せます。
Herokuアドオンの「Heroku Postgres」は、容量は小さいながら無料・速攻でDBが使えるのです。
「Resources」タブの「Add-ons」から検索します。
プランは「Hobby Dev - Free」を選択し、さっそく作成。
あっという間にご用意されました。
DBと繋ぐ
先ほど作成したSpring Bootアプリから、DBに接続していきます。
まずはライブラリを追加しましょう。build.gradle
を開き、dependencies
に以下を追加します。
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.flywaydb:flyway-core'
runtimeOnly 'org.postgresql:postgresql'
ORマッパーには、DBがシンプルだとラクなSpring Data JPAを選択します。
あとはPostgreSQLのドライバと、テーブル作成がラクになるのでFlywayも入れておきます。
(これらはSpring Initializrでも追加できたのですが、設定が必要になるので後回しにしました)
ここからはDBと接続するための設定です。
src/main/resources/application.properties
に以下の行を追加します。
spring.datasource.url=spring.datasource.url=${JDBC_DATABASE_URL}
Herokuの環境変数には、DB接続用の文字列がJDBC_DATABASE_URL
として格納されています。
Heroku上で動いているときなら取得できるのですが、ローカルではできません。
ということで、Herokuから接続文字列をもらってきましょう。Herokuのドキュメントを参考に、以下のコマンドを実行。
heroku run echo \$JDBC_DATABASE_URL -a (Herokuアプリ名)
表示された「jdbc:postgresql://…」という文字列を、ローカルの環境変数に設定します。
IntelliJであれば、DemoApplication.java
を右クリック→「Edit 'DemoApplication'…」から設定できます。
application.properties
にベタ書きでも動くのですが、GitHubなどで一般公開しないように注意してください。
続いて、コードをSpring Data JPAの形式に書き換えていきます。
もしここでクラスが見つからないというエラーが出る場合、ライブラリのダウンロードが行われていないかもしれないので、プロジェクトのビルドやIDEの再起動を試してみてください。
com.example
パッケージの下に`repository``を追加し、以下のインタフェースを作成。
package com.example.demo.repository;
import com.example.demo.model.Employee;
import org.springframework.data.repository.CrudRepository;
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
}
model
パッケージ以下のクラスを修正。
package com.example.demo.model;
import javax.persistence.Entity;
import javax.persistence.Id;
// 部署クラス
@Entity
public class Department {
@Id
private Integer id;
public String name;
}
package com.example.demo.model;
import javax.persistence.*;
// 社員クラス
@Entity
public class Employee {
@Id
private Integer id;
public String name;
@ManyToOne
public Department department;
}
EmployeeController
のgetEmployees
も修正。
Repositoryのメソッドを使い、DBからデータを取得するようにします。
@GetMapping // 『GET /api/employees』で実行されるようにマッピング
public Iterable<Employee> getEmployees() {
return employeeRepository.findAll();
}
最後に、Flyway用のSQLを作成します。
src/main/resources
の下にdb/migration
フォルダを作成し、中にSQLファイルを入れておくと、
アプリケーション起動時に自動でセットアップしてくれます。
-- V1_0__create_table.sql
CREATE TABLE department(
id serial PRIMARY KEY,
name varchar(40) NOT NULL
);
CREATE TABLE employee(
id serial PRIMARY KEY,
department_id integer REFERENCES department(id),
name varchar(40) NOT NULL
);
-- V1_1__insert_data.sql
INSERT INTO department(id, name)
VALUES (1, '営業1課'),
(2, '開発2課');
-- 自動採番のIDを強引に付与したので、シーケンス管理用の値を再設定
SELECT setval('department_id_seq', MAX(id))
FROM department;
INSERT INTO employee(id, department_id, name)
VALUES (1, 1, '社員 三郎'),
(2, 2, '社員 四郎');
SELECT setval('employee_id_seq', MAX(id))
FROM employee;
では、もう一度アプリケーションを起動します。
しっかり動いているようです。
これをHerokuにpushすると…
git add .
git commit -am "db access"
git push heroku master
無事に反映されました。
さいごに
とりあえず大急ぎでAPIサーバをセットアップしました。
APIを誰でも実行できたり、ローカルとサーバで同じDBを参照していたりと問題は山積みですが、一旦ここで区切ります。
次回の記事では、フロントエンドも大急ぎで立ち上げていきます。