🐂

Spring Boot + Jersey + H2DBでCRUDするまで

2022/03/18に公開

タイトル通り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を使用。

  1. ダウンロードしたzipファイルを任意の場所に展開する
  2. Eclipseを起動する
  3. [ファイル]→[インポート]→[Maven]→[既存Mavenプロジェクト]→[次へ]→[展開したフォルダーを選択]→[完了]
  4. 以下のようになればOK

DB構築

DB設定

まずDBを構築します。
src/main/resources/application.propertiesに以下を記載します。

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:レコードの初期設定を記載
これらのファイルはアプリケーション起動時に実行されるので、それぞれ以下のように記載します。

schema.sql
DROP TABLE IF EXISTS USERS;
CREATE TABLE USERS (
	ID IDENTITY NOT NULL PRIMARY KEY,
	FIRST_NAME VARCHAR(255),
	LAST_NAME VARCHAR(255)
);
data.sql
INSERT INTO USERS (FIRST_NAME, LAST_NAME) 
	VALUES ('hoge', 'taro');

再度アプリケーションを実行し、DBコンソールにアクセスすると今度はUSERSテーブルが存在しており、SELECT文を発行するとデータが取得できます。

データクラス作成

次にデータクラスを作成します。
src/main/java/com/example/JerseyCrudにDBのUSERSテーブルに対応したUserクラスを作成します。

User.java
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/JerseyCrudUserResource.javaを作成します。

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/JerseyCrudJerseyConfig.javaを作成し、登録処理を実装します。

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