Spring Boot + Jersey + H2DBでCRUDするまで
タイトル通りSpring Boot環境でREST APIにJerseyを使用し、H2DBにCRUDするまでの手順をまとめます。
環境構築
Spring InitializrでSpring Bootアプリを作成
Spring Initializrにアクセスして、Spring Bootアプリの雛形を作成します。
設定値は画像の通り。
依存関係は以下を追加します。
- Lombok
アノテーションを付けるとGetter/Setterを自動的に生成してくれる便利ツール
- Spring Web
Spring MVCを使用してWebアプリケーションを開発、Tomcatを内包(いらないかも)
- jersey
JAX-RSをサポートするREST APIを開発するためのフレームワーク
- H2 Database
javaプラットフォーム上で動作するDB、メモリ上にDBを作成できたりお手軽
- JDBC API
データベース接続API
全て設定したら左下の[GENERATE]でzipファイルをダウンロードします。
Eclipseから読み込み
EclipseはPleiadesから任意のものをダウンロード、今回は2022 Java Full Editionを使用。
- ダウンロードしたzipファイルを任意の場所に展開する
- Eclipseを起動する
- [ファイル]→[インポート]→[Maven]→[既存Mavenプロジェクト]→[次へ]→[展開したフォルダーを選択]→[完了]
- 以下のようになればOK
DB構築
DB設定
まずDBを構築します。
src/main/resources/application.properties
に以下を記載します。
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
上から、以下の通りです。
- H2DBのWebコンソールを有効にする
- WebコンソールのURLパス
- ドライバークラス名
- DBのURL
- ユーザー名
- パスワード
ここまで設定出来たら、[プロジェクトフォルダー右クリック]→[実行]→[Spring Boot アプリケーション]を選択し、アプリを起動します。
正常に起動したら http://localhost:8080/h2/ にアクセスします。
ログイン画面が表示され[Connect]押下で接続できればOKです。
テーブル/レコード初期値設定
次にテーブルとレコードの初期値を設定します
src/main/resources/
に以下2つのファイルを作成して下さい。
schema.sql
:テーブルの初期設定を記載
data.sql
:レコードの初期設定を記載
これらのファイルはアプリケーション起動時に実行されるので、それぞれ以下のように記載します。
DROP TABLE IF EXISTS USERS;
CREATE TABLE USERS (
ID IDENTITY NOT NULL PRIMARY KEY,
FIRST_NAME VARCHAR(255),
LAST_NAME VARCHAR(255)
);
INSERT INTO USERS (FIRST_NAME, LAST_NAME)
VALUES ('hoge', 'taro');
再度アプリケーションを実行し、DBコンソールにアクセスすると今度はUSERS
テーブルが存在しており、SELECT文を発行するとデータが取得できます。
データクラス作成
次にデータクラスを作成します。
src/main/java/com/example/JerseyCrud
にDBのUSERSテーブルに対応したUserクラスを作成します。
package com.example.JerseyCrud;
import java.io.Serializable;
import lombok.Data;
@Data
public class User implements Serializable {
private Long id;
private String firstName;
private String lastName;
}
@Data
はlombokのアノテーションで自動的にGetterやSetterを作成してくれます。
エンドポイント作成
いよいよRestAPIのエンドポイントを作成します。
Jerseyではコントロール部分をResource
というのがお決まりのようなので、src/main/java/com/example/JerseyCrud
にUserResource.java
を作成します。
package com.example.JerseyCrud;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
// このREST APIのルートパス
@Path("/users")
public class UserResource {
// DB操作用オブジェクトをインジェクション
@Autowired
JdbcTemplate jdbcTemplate;
// GETに対応するアノテーション
@GET
// Content-Type:application/jsonで提供(レスポンス)する
@Produces("application/json")
// DBに登録されている全ての情報を返す
public ArrayList<User> readAllUsers() {
String sql = "SELECT * FROM USERS";
List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql);
ArrayList<User> userList = new ArrayList<User>();
for (Map<String, Object> result : resultList) {
User user = new User();
user.setId((Long) result.get("id"));
user.setFirstName((String) result.get("FIRST_NAME"));
user.setLastName((String) result.get("LAST_NAME"));
userList.add(user);
}
return userList;
}
@GET
// "/users"に続くパス、{}でパラメーター化
@Path("/{id}")
@Produces("application/json")
// 指定されたIDのユーザー情報を返す
public Response readUserById(@PathParam("id") Long id) throws URISyntaxException {
String sql = "SELECT * FROM USERS WHERE id = " + id;
Map<String, Object> result = jdbcTemplate.queryForMap(sql);
if (result == null) {
return Response.status(404).build();
}
User user = new User();
user.setId((Long) result.get("ID"));
user.setFirstName((String) result.get("FIRST_NAME"));
user.setLastName((String) result.get("LAST_NAME"));
return Response.status(200).entity(user).build();
}
// POSTに対するアノテーション
@POST
// Content-Type:application/jsonで実行(リクエスト)する
@Consumes("application/json")
// ユーザーを作成する
public Response createUser(User user) throws URISyntaxException {
if (user.getFirstName() == null || user.getLastName() == null) {
return Response.status(400).build();
}
String sql = "INSERT INTO USERS (FIRST_NAME, LAST_NAME) VALUES (?, ?)";
jdbcTemplate.update(sql, user.getFirstName(), user.getLastName());
return Response.status(201).build();
}
// PUTに対するアノテーション
@PUT
@Path("/{id}")
@Consumes("application/json")
@Produces("application/json")
// 指定したユーザー情報を上書きする
public Response updateUser(@PathParam("id") Long id, User user) throws URISyntaxException {
if (user == null) {
return Response.status(404).build();
}
String sql = "UPDATE USERS SET FIRST_NAME = ?, LAST_NAME = ? WHERE ID = " + id;
jdbcTemplate.update(sql, user.getFirstName(), user.getLastName());
return Response.status(200).build();
}
// DELETEに対するアノテーション
@DELETE
@Path("/{id}")
// 指定したユーザー情報を削除する
public Response deleteUser(@PathParam("id") int id) throws URISyntaxException {
String sql = "SELECT * FROM USERS WHERE id = " + id;
Map<String, Object> result = jdbcTemplate.queryForMap(sql);
if (result == null) {
return Response.status(404).build();
}
sql = "DELETE from USERS WHERE id = " + id;
jdbcTemplate.update(sql);
return Response.status(200).build();
}
}
Jersey設定
一通り処理は実装できましたが、JerseyではResourceConfigで作成したResourceクラスを登録する必要があります。
src/main/java/com/example/JerseyCrud
にJerseyConfig.java
を作成し、登録処理を実装します。
package com.example.JerseyCrud;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(UserResource.class);
}
}
少し調べましたが詳細までは分からず…、こういうお決まりだと思っておいた方が良さそうです。
実装後の構成
最終的に以下のような構成となります。
動作確認
PostmanでREST APIを実行してみます。
GET
POST
PUT
DELETE
まとめ
Spring Boot + Jersey + H2DBでCRUDを実施してみました。
Spring Bootが裏でよしなにやってくれるところが多く、実装自体は簡単でした。
しかし、裏での動きを理解できていないものを使うのも微妙に気持ち悪いところもあり、もう少し掘り下げられればなと思います。
Discussion