📝

はじめてのSpringBoot10 ~JDBC:取得結果の変換処理(RowMapper)~

2020/12/29に公開

はじめに

はじめまして
私はJavaを研修で少しかじった程度でSpringBootを使用した開発に参加し、てんやわんやしております森田和華です。
全く分からない中から少しずつ調べて実装をしていますが、自分の学習の為にも記事にして残しておこうと思い作成しております。
参考にしていただける際はそのあたりを念頭に置いたうえで参考にしていただければと思います。
もし私の記事を読んでおかしなところなどありましたらご指摘いただけると嬉しいです。

環境

SpringBootバージョン:2.4.0
Javaバージョン:8
DB:MySQL 8.0
IDE:eclipse

今回の目標

今回は、取得結果の変換処理について調べます。
変換処理が可能なインターフェースはRowMapper,ResultSetExtractor,RowCallbackHandlerがあるようですので今回はRowMapperについて調べていきたいと思います。
ちなみにResultSetExtractor,RowCallbackHandlerを利用するときはqueryメソッドを使用するようです。

◆RowMapper

RowMapperとは

JDBCのResultSetを参照して特定のPOJOにマッピングするためのインターフェース。
(POJOはごく一般的なObjectという意味らしい)
今までのqueryForList()やqueryForMap()を使うときにはEntityをセットする処理が別途必要でした。
ですがRowMapperのインターフェースを継承した実装を作って利用することで代替が出来るみたいです!
これは嬉しい。一つのEntityを何度も取得して来る予定があるとき、今後機能追加などの修正がある時はこちらを実装しておくのがいいかもしれません。

RowMapperの実装

では実際に実装してみます。
まずは新規で作るRowMapperの実装部分です。

BookRowMapper.java
package com.elpmas.test.domain.repository;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

import com.elpmas.test.domain.entity.BookEntity;

public class BookRowMapper implements RowMapper<BookEntity> {

	@Override //インターフェースのmapRowをオーバーライドする。
	public BookEntity mapRow(ResultSet rs,int rowNum) throws SQLException
	{
		//Entityにセットする処理を実装
		BookEntity book = new BookEntity();
		book.setId(rs.getInt("id"));
		book.setTitle(rs.getString("title"));
		book.setSummary(rs.getString("summary"));
		book.setClassification(rs.getString("classification"));
		book.setDelflg(rs.getInt("delflg"));

		return book;
	}
}

あとは既存のファイルに追加で実装していきます。

JDBCtestRepository.java
//追加部分のみ記述
public BookEntity GetBookById(int id) {
		String sql ="SELECT * FROM book_sample where id =?"; //バインドパラメータは:カラム名で指定
		BookRowMapper rowMapper = new BookRowMapper();
		return jdbctemplate.queryForObject(sql, rowMapper,id); //指定のEntityへの変換をrowMapperが自動で行う。
	}

	public List<BookEntity> GetAllBook()
	{
		String sql ="SELECT * FROM book_sample";
		BookRowMapper rowMapper = new BookRowMapper();
		return jdbctemplate.query(sql, rowMapper); //指定のEntityへの変換をrowMapperが自動で行う。
	}
SampleContoroller.java
//追記部分のみ記載
model.addAttribute("title",jdbcTestRepository.GetBookById(1).getTitle());
		model.addAttribute("bookAll",jdbcTestRepository.GetAllBook());
sample.html
//追記部分のみ記載
<div th:if="${title ne null}" th:text="'titleは'+${title}" ></div>
<div th:if="${bookAll ne null}" th:each="book:${bookAll}" >
	<div th:text="'ID:'+${book.id}"></div>
	<div th:text="'タイトル:'+${book.title}"></div>
	<div th:text="'概要:'+${book.summary}"></div>
	<div th:text="'分類:'+${book.classification}"></div>
</div>

RowMapperの動作確認

実装が完了したので動作を確認します。
無事に表示されています。

(おまけ)BeanPropertyRowMapperで代替可能?

BeanPropertyRowMapperはRowMapperインターフェースを実装したクラスで
以下のルールや制約を守れば使用できて、実装することなく自動マッピングが可能です。
-ルール-
・ResultSetのカラム名と指定したクラスのプロパティ名でマッピングする
・カラム名のアンダースコアを区切りとし、プロパティ名はキャメルケースでマッピングする
・String,Boolean,boolean,Byte,Short,short,Integer,int,Long,long,Float,float
,Double,double,BigDecimal,java.util.Dateなどの基本的なデータ型のみ

-制約-
・指定したクラスが入れ子構造の場合、トップレベルのクラスに対してマッピングする
・指定したクラスにはデフォルトコンストラクタか引数無しのコンストラクタが定義されている必要がある

実装例

public BookEntity GetBookUseBeanPropertyById(int id) {
		String sql ="SELECT id,title,summary,classification,delflg FROM book_sample where id =?";
		RowMapper<BookEntity> rowMapper = new BeanPropertyRowMapper<BookEntity>(BookEntity.class);
		return jdbctemplate.queryForObject(sql, rowMapper,id); //指定のEntityへの変換をrowMapperが自動で行う。
	}

次回

次回は同じく取得結果変換処理に利用するインターフェースResultSetExtractorについて調べていきたいと思います。

参考文献

インターフェース RowMapper<T>
https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/RowMapper.html
インタフェースResultSet
https://docs.oracle.com/javase/jp/8/docs/api/java/sql/ResultSet.html?is-external=true
クラスSQLException
https://docs.oracle.com/javase/jp/8/docs/api/java/sql/SQLException.html?is-external=true
Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 (著 株式会社NTTデータ)
https://www.shoeisha.co.jp/book/detail/9784798142470

Discussion