Webアプリ作成 Spring Boot
④DBからデータ取得(DAOパターン)

一覧画面にDBからデータを取得し、その値を表示するということをゴールに行っていきます。

今後DBの中身を確認したりデータ作成したりは「TablePlus」というツールを使用して実施していきます。
使い方や設定方法以下を参考にしてみてください。

テーブル構成

テーブル構成は以下の3テーブルとします。
diary:日記のデータを格納
category_code:検索条件の分類を管理
users:ログインユーザを管理

テーブル名項目名PKNULL
diaryidserial×
categoryvarchar(2)××
contenttext×
datedate××
update_datetimetimestamp×
テーブル名項目名PKNULL
category_codeidserial×
group_cdvarchar(2)×
cdvarchar(2)×
namevarchar(20)×
テーブル名項目名PKNULL
usersidserial×
user_idvarchar(10)××
passwordvarchar(60)××
usernamevarchar(50)×

※PostgreSQLのデータ型は以下を参考にしてください
https://www.postgresql.jp/document/9.3/html/datatype.html

テーブル作成

DBに接続してCREATE文を実行するのでいいのですが、
Spring Bootにて設定することができますので、そちらで実施していきます。
「src/main/resources」配下に「schema.sql」を作成します。
作成したファイルに以下を記述します。

CREATE TABLE IF NOT EXISTS diary(
  id serial,
  category varchar(2),
  title varchar(50) NOT NULL,
  content text,
  date date NOT NULL,
  update_datetime timestamp,
  PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS category_code(
  id serial,
  group_cd varchar(2),
  cd varchar(2),
  name varchar(20),
  PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS users(
  id serial,
  user_id varchar(10) NOT NULL,
  password varchar(60) NOT NULL,
  username varchar(50),
  PRIMARY KEY(id)
)


次に「src/main/resources」配下に存在する「application.properties」の末尾に以下1行追加します。

spring.datasource.initialization-mode=always


これを記述すると毎回以下SQLファイルが存在する場合、起動時に毎回実行されます。
・schema.sql(テーブル追加等を記述してデータ定義をする)
・data.sql(データ追加等を記述してデータ操作をする)
今回は「schema.sql」が対象です。

毎回実行されてしまうため、SQL文は一工夫が必要です。
CREATE文に「IF NOT EXISTS」を記載しています。
これを記述することで存在していなければ作成となります。
これがないと2回目以降実行する場合「既に存在しています」とエラーになってしまいます。

実際にアプリケーションを実行してみましょう。
実行できたらDBを確認してみてください。作成されているはずです。

コンソール上から確認する方法
データベース、ユーザーを指定して対話モードに入ります。

./psql -d diary -U appuser

接続後以下コマンドを実行すると表示されます。

\dt;

DAOパターン

DBとの接続はDAOパターンというもので実施していきます。
DAOパターンとはビジネスロジックとデータアクセスの処理を分けて記載することです。

それぞれの独立性を高めることで、修正や拡張する際にメンテナンスしやすくなります。

DAO作成

Entityクラス作成

DBのデータ格納用クラス、Entityクラスを作成していきます。
第3章でコントローラーを作成したようにentityパッケージを作成し、「Diary.java」を作成します。
取得した日記一覧のデータを格納します。

「Diary.java」に以下を記載します。それぞれの値にsetter、getterを用意しています。

package diary.entity;

import java.sql.Timestamp;

public class Diary {
	
	private int id;
	private String category;
	private String title;
	private String content;
	private String date;
	private Timestamp update_datetime;
	private String name;

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public Timestamp getUpdate_datetime() {
		return update_datetime;
	}
	public void setUpdate_datetime(Timestamp update_datetime) {
		this.update_datetime = update_datetime;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

repositoryクラス作成

データベースにアクセスするクラスを作成していきます。
repositoryパッケージを作成します。

今後の拡張性やテストのしやすさを考慮して、インターフェースを作成します。
repositoryパッケージ上で右区クリックし、「New」→「Interface」を選択します。


「Name」を「IDiaryDao」としFinishを選択します。

作成したインターフェース以下を記載します。
findListメソッドを作成し、これを使用してデータを取得できるようにします

package diary.repository;

import java.util.List;
import diary.entity.Diary;

public interface IDiaryDao {
	// 登録されている日記を取得
	List<Diary> findList();
}


インターフェースを作成したので実際の実装クラスを作成していきます。
Nameを「DiaryDao」とします。
Interfacesをしているすると自動で継承のコードを記載してくれますので、「Add」を選択して、
先ほど作成したインターフェースを指定します。

作成したクラスに以下を記載します。

package diary.repository;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

import diary.entity.Diary;

@Repository
public class DiaryDao implements IDiaryDao {
	
	private final NamedParameterJdbcTemplate jdbcTemplate;

	@Autowired
	public DiaryDao(NamedParameterJdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	@Override
	public List<Diary> findList() {
		StringBuilder sqlBuilder = new StringBuilder();
		sqlBuilder.append("SELECT d.id, d.category, d.title, d.content, TO_CHAR(d.date, 'YYYY/MM/DD') AS date, d.update_datetime, c.name "
				+ "FROM diary AS d INNER JOIN category_code AS c ON d.category = c.cd "
				+ "WHERE c.group_cd = '01'");

		String sql = sqlBuilder.toString();

		// パラメータ設定用Map
		Map<String, String> param = new HashMap<>();
		//タスク一覧をMapのListで取得
		List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql, param);
		//return用の空のListを用意
		List<Diary> list = new ArrayList<Diary>();

		//データをDiaryにまとめる
		for(Map<String, Object> result : resultList) {
			Diary diary = new Diary();
			diary.setId((int)result.get("id"));
			diary.setCategory((String)result.get("category"));
			diary.setTitle((String)result.get("title"));
			diary.setContent((String)result.get("content"));
			diary.setDate((String)result.get("date"));
			diary.setUpdate_datetime((Timestamp)result.get("update_datetime"));
			diary.setName((String)result.get("name"));
			list.add(diary);
		}
		return list;
	}
}
ポイント

15行目に@RepositoryはDBにアクセスするクラスに付与するアノテーションです。
これを指定することでDIコンテナの管理対象となります。

18~23行目にSpring機能の一つデータベースアクセスを簡単にできる「jdbcTemplate」を定義しています。@Autowired と指定して依存性を注入することができます。
コンストラクタインジェクションのパターンを利用し、コンストラクタで依存性の注入を行なっています。他にも「セッターインジェクション」「フィールドインジェクション」の種類があります。

28〜32行目で実際に実行するSQLを定義しています。

34行目で設定したMapは別章で検索条件を指定した際に設定するように定義しています。

37行目〜は実際にDBへアクセスしデータを格納しています。
「jdbcTemplate.queryForList」でSQLの実行をしているます。
queryForList → 複数レコード取得する際に使用。取得結果が0件でもエラーとならない。
取得したデータEntityクラスに詰めて返却しています。

ビジネスロジック部分であるサービスクラスを作成します。
repositoryパッケージを作成し、「DiaryService.java」を作成します。

その中に以下を記載します。

package diary.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import diary.repository.IDiaryDao;
import diary.entity.Diary;

@Service
@Transactional
public class DiaryService {

	private final IDiaryDao dao;

	@Autowired
	public DiaryService(IDiaryDao dao) {
		this.dao = dao;
	}

	public List<Diary> findList() {
		return dao.findList();
	}
}
ポイント

12行目に@Serviceはサービスクラスに付与するアノテーションです。
これを指定することでDIコンテナの管理対象となります。

13行目に@Transactionalクラスの上に記載しています。これを記載するとクラス内のメソッド全てが例外時に自動でロールバックしてくれます。メソッド単位で指定することも可能です。
(プラスでプロパティを設定することも可能で、タイムアウトの設定等もすることができます。)

14行目以降はDaoクラスをコンストラクタインジェクションして、findListメソッドを実行をするメソッドを作成しています。
引数にインターフェースを指定していることでIDiaryDaoインターフェースをimplementsしているクラスであれば、受け取ることが可能になります。

ポイント

今回のポイントのおさらいです。
・Springには起動時に自動で実行されるsqlファイルがある
・DAOパターンを利用してデータ取得
・「@Autowired」を使用して依存性を注入

次回は実際に画面の検索条件を元に取得したデータを画面に表示していきます。

タイトルとURLをコピーしました