細かいところで苦戦したので、自分用のメモとして書き残します。
HerokuのアプリにHeroku Postgresを追加した状態を前提とします。
Spring Bootは2.0.4です。
ローカルマシンにpsqlコマンドをインストール
Heroku PotgresのSettings(上図)をみると「Heroku CLI」とあって、次のコマンドが書いてあります。
heroku pg:psql データストア名 --app アプリ名
自分の環境で試すとエラーになりました。ローカルマシンにpsqlを入れる必要があるとのこと。当たり前ですねw
--> Connecting to データストア名
! The local psql command could not be located. For help installing psql, see
! https://devcenter.heroku.com/articles/heroku-postgresql#local-setup
上記URLを参考に、自分のWindows 10環境へWindows Setupでインストールしました。そして、環境変数に「C:\Program Files\PostgreSQL<VERSION>\bin」を設定しました。
heroku pg:psql データストア名 --app アプリ名
--> Connecting to データストア名
psql (10.4)
SSL 接続 (プロトコル: TLSv1.2、暗号化方式: ECDHE-RSA-AES256-GCM-SHA384、ビット長: 256、圧縮: オフ)
"help" でヘルプを表示します。
アプリ名::DATABASE=>
これで無事に接続できました。
コマンド
ここはSpring BootもHerokuも関係ない部分ですが、自分がPostgresのコマンドを知らなすぎたのでメモ。
データベース一覧表示
\l
これを実行するとデータベースがたくさん出てきたのですが、他の所有者のDBもみえている…?マルチテナントなのだろうか…。
データベース選択
\c データベース名
SSL 接続 (プロトコル: TLSv1.2、暗号化方式: ECDHE-RSA-AES256-GCM-SHA384、ビット長: 256、圧縮: オフ)
データベース "xxxx" にユーザ "xxxx" として接続しました。
テーブル一覧表示
create tableでテーブルを作成した後、テーブル表示する。
\d
リレーション一覧
スキーマ | 名前 | 型 | 所有者
----------+----------+----------+----------------
public | nogizaka | テーブル | xxxxxxxxxxxxx
テーブルの詳細表示
カラムなどの詳細をみる。
\d nogizaka
スキーマは超手抜きです。
テーブル "public.nogizaka"
列 | 型 | 照合順序 | Null 値を許容 | デフォルト
------+-----------------------+----------+---------------+------------
id | integer | | |
name | character varying(64) | | |
Spring Boot
Spring Initializr
Spring Initializrでプロジェクトの雛形を作ります。dependencyは次の3つを選びました。Webはなくてもいいのですが、実行時のエンドポイントをREST APIにするために入れました。
- Web
- PostgreSQL
- JPA
application.properties
データベースへの接続内容はHeroku PostgresのSettingsにあるDatabase Credentialsをもとに次のように定義して動かしました。
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://ホスト名:ポート番号/データベース名?sslmode=require
spring.datasource.username=ユーザ名
spring.datasource.password=パスワード
最初ハマったときは次の2点が漏れてました。
- URLの「postgresql」を「postgres」としていた(Heroku CLIに書いてあるURLをコピペしてた)
- sslmodeのパラメータを付けていなかった
コード
あとはひたすら書くのみ。
Entity
package tech.kikutaro.herokupostgres;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="nogizaka")
public class Nogizaka {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
@Column(name="name")
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
setter,getterはLombok使ったほうがよいかも。
Repository
package tech.kikutaro.herokupostgres;
import org.springframework.data.jpa.repository.JpaRepository;
public interface NogizakaRepository extends JpaRepository<Nogizaka, Long> {
}
Service
package tech.kikutaro.herokupostgres;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class NogizakaService {
@Autowired
NogizakaRepository nogirepo;
public long count() {
return nogirepo.count();
}
public Nogizaka getMember(long id) {
return nogirepo.getOne(id);
}
}
とりあえず雑にcountとgetだけ。
Main
package tech.kikutaro.herokupostgres;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class HerokupostgresApplication {
@Autowired
private NogizakaService nogiService;
public static void main(String[] args) {
SpringApplication.run(HerokupostgresApplication.class, args);
}
@GetMapping("/count")
public String count() {
System.out.println(nogiService.count());
return Long.toString(nogiService.count());
}
@GetMapping("/select/{id}")
public String getName(@PathVariable("id") long id) {
return nogiService.getMember(id).getName();
}
}
実行結果
無事に動きましたー。