タイトル
 メニューにないコーナーはTopからいけます
TOPJavaspring → This Page

3.4.1.(Criteria API)(単一テーブルのCRUD) Spring+MVC+DB+Test構築サンプル

前提

このページに記載している内容は 2018/09/24 に書かれたものです。
掲載している画面や方法が将来的に変更されている場合があります。
また、掲載しているインストール方法は Windows 8.1 の場合です。
開発環境は
・Windows 8.1
・JDK 8
・STS(Spring Tool Suite) 3.9.5
・PostgreSQL 9.5.14
とします。

本ページは先に以下の2ページの内容を実施してからの内容となります。
1.準備
2.共通部分構築

参考書やサイトによくある
・コントローラに直接DBアクセス処理を記載
・インタフェースを使わない
といった形式ではなく、実務で良く使われているであろう
以下のようなパッケージ構成で作成します。
(Facadeパターンは面倒すぎたのでやめました)
※AOPだけオマケなのでパッケージ構成が微妙ですがご容赦を。。。
図:パッケージ構成

処理遷移もこんな感じです。
図:処理遷移

Criteria API は Spring Data JPA の機能の一部で、
・ORM機能を持つ
・RDBMSへの依存性を排除する(または薄くする)ことができる
・Javaクラスがテーブルとなり、SQLを書く必要がない
・SQL を書かずに全てJavaのコードで記述する
  →コンパイルエラーで不具合検出可能→バグが減る?
  →少し複雑なクエリを発行しようと思うと大量のコードが必要→バグが増える?
・学習コストが高い
といった特徴があります。


目次

1.pom.xml編集(PostgreSQL追加)
2.Maven Clean
3.Maven Install
4.jdbc.properties作成
5.application-config.xml編集(DB設定追加)
6.persistence.xml作成
7.Entityクラスの作成
8.Daoインタフェースの作成
9.Daoクラスの作成
10.DTOクラスの作成
11.Serviceインタフェースの作成
12.Serviceクラスの作成
13.TestController.java編集
14.index.jsp編集
15.確認実行

1.pom.xml編集(PostgreSQL追加)

まずは「pom.xml」を編集して「Maven」に「PostgreSQL」と「Criteria API」の利用に
必要なライブラリを揃えてもらいます。
プロジェクト直下にある「pom.xml」をダブルクリックして開きます。
開いたら下のタブを「pom.xml」に切り替えます(最初からpom.xmlになっている場合もあります)
図:pom.xml

以下の内容を <dependencies> から </dependencies> の間に追記して保存します。
保存すると必要なライブラリのダウンロードやビルドが始まるのでしばらく待ちましょう。

		<!-- postgreSQL -->
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>9.4-1206-jdbc42</version>
		</dependency>
		
		<!-- Spring JDBC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		
		<!--  Spring Data JPA -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>1.11.6.RELEASE</version>
		</dependency>
		
		<!-- Spring ORM -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>


2.Maven clean

プロジェクト名を右クリックして「Run As」>「Maven clean」を選択します。
「Console」に「[INFO] Finished at ...」と表示されるまで待ちましょう。
図:STS
図:Console


3.Maven install

プロジェクト名を右クリックして「Run As」>「Maven install」を選択します。
先ほどと同様に「Console」に「[INFO] Finished at ...」と表示されるまで待ちましょう。
エラーが出たら「プロジェクトのクリーン」を実施してから「Maven install」を再実施しましょう。
図:STS


4.jdbc.properties作成

データベース接続情報を持ったプロパティファイルを作成します。
プロジェクトを展開し、
/src/main/resources/
フォルダで右クリックして「New」>「File」を選択します。
図:STS

「New File」ダイアログが表示されたら、
フォルダの末尾が /src/main/resources/
となっていることを確認し、
「File name」に
jdbc.properties
と入力して「Finish」ボタンを押しましょう。
図:New File

jdbc.properties がエディタで開くので
以下の内容を記入して保存しましょう。
#Database Configuration
jdbc.driverClassName=org.postgresql.Driver
jdbc.url=jdbc:postgresql://localhost:5432/testdb
jdbc.username=mitchy
jdbc.password=ppp

プロパティの名前で設定値の意味はなんとなく分かると思うので
値はご自分の環境に合わせて変更しましょう。

5.application-config.xml編集(DB設定追加)

application-config.xml にもデータベース接続情報を設定します。
/src/main/resources/spring
フォルダにある
application-config.xml
をダブルクリックして開きましょう。
開いたら下のタブを「Source」にします。
(最初から「Source」になっている場合もあります)
図:STS

以下の内容に書き換えて保存しましょう。
<?xml version="1.0" encoding="UTF-8"?>

<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/data/jpa
		http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/jdbc
		http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd">
	
	<context:property-placeholder location="classpath:jdbc.properties" />
	<context:annotation-config />
	<context:component-scan base-package="jp.mitchy"/>
	
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
	
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>
	
	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="showSql" value="false" />
				<property name="database" value="POSTGRESQL" />
			</bean>
		</property>
	</bean>
	
</beans>
<context:property-placeholder location="classpath:jdbc.properties" />
は先ほど作成したプロパティファイルのパスを示す設定です。

<context:annotation-config />
で以降に作成するクラスへのアノテーションが有効になります。

<context:component-scan base-package="jp.mitchy"/>
は今から作成するクラスがあるパッケージを示す設定です。

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
はデータベース情報です。
プロパティファイルに記載された各種情報を読み込んで設定されます。
プロパティファイルを利用せず、ここに直接設定値を記載することもできますが、
プロパティファイルだけを差し替えることで簡単に環境を変更できるので
開発環境、テスト環境、本番環境など色々な環境で実行する必要がある実務では
プロパティファイルに設定値を外出しすることが一般的です。

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
は EntityManager を利用するための設定です。
Criteria API は EntityManager と組み合わせて使います。


6.persistence.xml作成

Criteria API は JPA(Java Persistence API)の中の1機能です。
JPA を使うためには persistence.xml というDB設定情報を作成しないといけません。
作成先のフォルダも決まっています。
まずはそのフォルダを作成しましょう。
src/main/resources を右クリックして「New」>「Folder」を選択します。
図:STS

「New Folder」ダイアログが表示されます。
src/main/resources が選択されていることを確認し、
「Folder name」に
META-INF
と入力して「Finish」ボタンを押しましょう。
図:New Folder

作成した src/main/resources/META-INF を右クリックして「New」>「Other」を選択します。
図:STS

「New」ダイアログが表示されます。
「XML」>「XML File」を選択して「Next」ボタンを押しましょう。
図:New

「New XML File」ダイアログが表示されます。
src/main/resources/META-INF が選択されていることを確認し、
「File name」に
persistence.xml
と入力して「Finish」ボタンを押しましょう。
図:New XML File

persistence.xml が開いたら下のタブを「Source」にします。
(最初から「Source」になっている場合もあります)
図:STS

以下の内容に書き換えて保存しましょう。
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
	xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
	http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
	
	<persistence-unit name="persistence-unit" transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
		<properties>
			<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
			<property name="javax.persistence.jdbc.driver" value="${jdbc.driverClassName}" />
			<property name="javax.persistence.jdbc.url" value="${jdbc.url}" />
			<property name="javax.persistence.jdbc.user" value="${jdbc.username}" />
			<property name="javax.persistence.jdbc.password" value="${jdbc.password}" />
			<property name="hibernate.show_sql" value="true" />
			<property name="hibernate.format_sql" value="true" />
		</properties>
	</persistence-unit>
	
</persistence>


7.Entityクラスの作成

今回は「単一テーブルのCRUD」ということで、
準備編で用意した最も単純なテーブル「department」テーブルを使うことにします。
図:department

1テーブルにつき対応した1Entityクラスを作成します。
プロジェクト名を右クリックして「New」>「Class」を選択します。
図:STS

「New Java Class」ダイアログが表示されます。
・「Package」は「jp.mitchy.entity」と入力
・「Name」は「Department」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
図:New Java Class

作成された「Department.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="department")
public class Department {
	@Id
	@Column
	private Long id;
	
	@Column(length=50,nullable=false)
	private String name;
	
	public Department() {
	}
	
	public Department(Long id, String name) {
		this();
		this.id = id;
		this.name = 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;
	}
	
	@Override
	public String toString() {
		return "[id=" + id + ",name=" + name + "]";
	}
	
}
クラス名の上に @Entity アノテーションを付けることで、
このクラスがエンティティクラスとして登録されます。

また、@Table アノテーションで実際のテーブルの名前とクラスを結びつけます。
テーブル名とクラス名が同一の場合は省略可能です。

テーブルのカラムに合わせて id と name をメンバフィールドに持ちます。

プライマリーキーとなるカラムのフィールドには @Id アノテーションを付けます。
これがないと実行時にエラーとなります。

カラムのフィールドには @Column アノテーションを付けます。
属性として長さやnull許可有無などを追加できます。

あとはコンストラクタと表示用の toString メソッドだけの簡単な構造です。


8.Daoインタフェースの作成

次に実際にデータベース操作をするDAO(Data Access Object)を
作りたいところですが、実務ではインタフェースを作り、
そのインタフェースを実装したクラスにすることが多いので
今回もまずはインタフェースを作成します。
インタフェースを使うメリットは自分で調べて下さい(^^;;

同じく1テーブルにつき対応した1DAOインタフェースを作成します。
プロジェクト名を右クリックして「New」>「Interface」を選択します。
図:STS

「New Java Interface」ダイアログが表示されます。
・「Package」は「jp.mitchy.dao」と入力
・「Name」は「DepartmentDao」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
図:New Java Interface

作成された「DepartmentDao.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.dao;

import java.util.List;

import jp.mitchy.entity.Department;

public interface DepartmentDao {
	public List<Department> getAllEntity();
	public Department findById(Long id);
	public void addEntity(Department entity);
	public void updateEntity(Department entity);
	public void removeEntity(Department data);
	public void removeEntity(Long id);
}
メソッド名を見てなんとなく何をするメソッドか想像はつくと思いますが、
上からそれぞれ
・全レコード取得
・1レコード取得
・レコード追加
・レコード更新
・レコード削除(引数がエンティティ)
・レコード削除(引数がID)
です


9.Daoクラスの作成

先ほど作成したインタフェースを実装したクラスを作成します。
同じく1テーブルにつき対応した1DAOクラスを作成します。
プロジェクト名を右クリックして「New」>「Class」を選択します。
図:STS

「New Java Class」ダイアログが表示されます。
・「Package」は「jp.mitchy.dao.impl」と入力
・「Name」は「DepartmentDaoImpl」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
図:New Java Class

作成された「DepartmentDaoImpl.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.stereotype.Repository;
// import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import jp.mitchy.dao.DepartmentDao;
import jp.mitchy.entity.Department;

@Repository
public class DepartmentDaoImpl implements DepartmentDao {

	@Autowired
	private LocalContainerEntityManagerFactoryBean factory;
	
	@PersistenceContext
	private EntityManager manager;
	
	public DepartmentDaoImpl() {
		init();
	}
	
	public void init(){
		// @Autowired がうまく機能しない場合は以下のコメントを外す
		// SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
	}
	
	public List<Department> getAllEntity() {
		System.out.println("getAllEntity()");
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<Department> query = builder.createQuery(Department.class);
		Root<Department> root = query.from(Department.class);
		query.select(root);
		return manager.createQuery(query).getResultList();
	}

	public Department findById(Long id) {
		System.out.println("findById(id)");
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<Department> query = builder.createQuery(Department.class);
		Root<Department> root = query.from(Department.class);
		query.select(root).where(builder.equal(root.get("id").as(Long.class), id));
		return manager.createQuery(query).getSingleResult();
	}
	
	public void addEntity(Department entity) {
		System.out.println("addEntity(entity)");
		EntityManager manager = factory.getNativeEntityManagerFactory().createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		// Criteria API は INSERT サポート対象外のため EntityManager でレコード追加
		manager.persist(entity);
		manager.flush();
		transaction.commit();
	}

	public void updateEntity(Department entity) {
		System.out.println("updateEntity(entity)");
		EntityManager manager = factory.getNativeEntityManagerFactory().createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaUpdate<Department> update = builder.createCriteriaUpdate(Department.class);
		Root<Department> root = update.from(Department.class);
		update.set(root.get("name"), entity.getName()).where(builder.equal(root.get("id").as(Long.class), entity.getId()));
		Query query = manager.createQuery(update);
		query.executeUpdate();
		transaction.commit();
	}

	public void removeEntity(Department entity) {
		System.out.println("removeEntity(entity)");
		EntityManager manager = factory.getNativeEntityManagerFactory().createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaDelete<Department> delete = builder.createCriteriaDelete(Department.class);
		Root<Department> root = delete.from(Department.class);
		delete.where(builder.equal(root.get("id").as(Long.class), entity.getId()));
		Query query = manager.createQuery(delete);
		query.executeUpdate();
		transaction.commit();
	}

	public void removeEntity(Long id) {
		System.out.println("removeEntity(id)");
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<Department> query = builder.createQuery(Department.class);
		Root<Department> root = query.from(Department.class);
		query.select(root).where(builder.equal(root.get("id").as(Long.class), id));
		Department entity = manager.createQuery(query).getSingleResult();
		this.removeEntity(entity);
	}

}
クラス名の上に @Repository アノテーションを付けることで、
MVCにおけるデータ層のクラスとして Spring のDIコンテナに bean として登録されます。

factory フィールドに @Autowired アノテーションを付けることで
自動的に EntityManagerFactoryBean のオブジェクトがバインドされます。
manager フィールドに @PersistenceContext アノテーションを付けることで
自動的に EntityManager のオブジェクトがバインドされます。

init メソッドの内容は基本的には不要です。
場合によっては必要になることがありますが、
本サイトのサンプルでは必要ありません。

Criteria API を使うにはいくつかの手続きが必要になります。
まずは
CriteriaBuilder builder = manager.getCriteriaBuilder();
で CriteriaBuilder のオブジェクトを作成します。

データ取得の際は CriteriaBuilder からさらに CriteriaQuery のオブジェクトを作成します。
引数には対象のエンティティクラスを指定します。

次に query.from で SQL でいう「FROM テーブル名」に該当する Root オブジェクトを作成します。

あとは CriteriaQuery のオブジェクトに対して select したり、
where で条件を付けたりしてレコードを検索取得します。
複数条件を付ける場合はメソッドチェーンで次々と後ろにメソッドを継足していきます。

最後に
レコード単体なら manager.createQuery(query).getResultList();
レコード複数なら manager.createQuery(query).getSingleResult();
で結果を取得できます。

実は Criteria API にはレコード登録の機能がありません。
そのため、EntityManager の機能を使って登録します。
persist メソッドでエンティティの追加を実行します。
flush メソッドを実行するまではメモリ内の管理情報にだけ追加が実行されます。
(flush しなくても独自のタイミングで実行される)

次に問題なのがトランザクション制御です。
実は EntityManager の利用ではトランザクションが
・共有トランザクション
・独立トランザクション
の2種類あります。
自分でトランザクションを制御したい場合は独立トランザクションを使う必要があります。
共有トランザクションはトランザクションのタイミングが
コンテキスト側で自動制御となります。

独立トランザクションを利用するためには
LocalContainerEntityManagerFactoryBean から取得した
EntityManager を使ってトランザクションを発行します。
このあたりがちょっとややこしいところです・・・

レコードの更新は CriteriaUpdate、レコードの削除は CriteriaDelete を
CriteriaQuery の代わりに作成します。

更新や削除も検索と同様に Root を作って where を指定します。
そして最後に Query に対して executeUpdate() メソッドで実行です。

と、このように制約や独自の動きが色々とありすぎて
個人的には好きではありません(爆)
自分がアーキテクトの立場になったら採用しないだろうなぁ(^^;;


10.DTOクラスの作成

Controller が Service の結果を受け取るために使うDTOクラスを作成します。
次ページ以降の複数サービスで共通的に使えるように今回は汎用的なDTOクラスにします。
プロジェクト名を右クリックして「New」>「Class」を選択します。
図:STS

「New Java Class」ダイアログが表示されます。
・「Package」は「jp.mitchy.dto」と入力
・「Name」は「TestResultDto」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
図:New Java Class

作成された「TestResultDto.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.dto;

import java.util.List;

/**
 * TestControllerに返すServiceの戻り値のDTO
 * 
 * @param <T> Serviceごとに型が違うので総称型で対応
 */
public class TestResultDto<T> {
	private T entity;
	private List<T> list;
	
	public T getEntity() {
		return entity;
	}
	public void setEntity(T entity) {
		this.entity = entity;
	}
	public List<T> getList() {
		return list;
	}
	public void setList(List<T> list) {
		this.list = list;
	}
	
}
総称型 <T> については特に解説しないので自分で調べて下さい(^^;;
今回のサンプルでは TestController が result.jsp に
1レコードとリストの2種類しか返さず、
Service も同じく1レコードとリストの2種類だけを返すものにしています。


11.Serviceインタフェースの作成

次にサービス層のインタフェース・クラスを作ります。
今回もまずはインタフェースを作成します。
プロジェクト名を右クリックして「New」>「Interface」を選択します。
図:STS

「New Java Interface」ダイアログが表示されます。
・「Package」は「jp.mitchy.service」と入力
・「Name」は「DepartmentService」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
図:New Java Interface

作成された「DepartmentService.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.service;

import jp.mitchy.dto.TestResultDto;
import jp.mitchy.entity.Department;

public interface DepartmentService {
	public TestResultDto<Department> execute(Department entity);
}
エンティティを引数とし、TestResultDto を返す execute メソッドのみのシンプルなインタフェースです


12.Serviceクラスの作成

先ほど作成したインタフェースを実装したクラスを作成します。
プロジェクト名を右クリックして「New」>「Class」を選択します。
図:STS

「New Java Class」ダイアログが表示されます。
・「Package」は「jp.mitchy.service.impl」と入力
・「Name」は「DepartmentServiceImpl」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
図:New Java Class

作成された「DepartmentServiceImpl.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.service.impl;

import java.util.List;

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

import jp.mitchy.dao.DepartmentDao;
import jp.mitchy.dto.TestResultDto;
import jp.mitchy.entity.Department;
import jp.mitchy.service.DepartmentService;

@Service
public class DepartmentServiceImpl implements DepartmentService {
	
	@Autowired
	private DepartmentDao dao;
	
	public DepartmentServiceImpl() {
		init();
	}
	
	public void init(){
		// @Autowired がうまく機能しない場合は以下のコメントを外す
		// SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
	}

	public TestResultDto<Department> execute(Department entity) {
		TestResultDto<Department> result = new TestResultDto<Department>();
		
		// INSERT
		dao.addEntity(entity);
		
		// UPDATE
		entity.setName("廃止");
		dao.updateEntity(entity);
		
		// DELETE
		dao.removeEntity(entity.getId());
		
		// SELECT 単体
		Department entity2 = dao.findById(2L);
		result.setEntity(entity2);
		
		// SELECT 複数
		List<Department> list = dao.getAllEntity();
		result.setList(list);

		return result;
	}
	
}
クラス名の上に @Service アノテーションを付けることで、
サービス層のクラスとして Spring のDIコンテナに bean として登録されます。

dao フィールドに @Autowired アノテーションを付けることで
自動的に DepartmentDaoImpl のオブジェクトがバインドされます。

execute メソッドの内容は単一テーブルのCRUDということで、
・INSERT
・UPDATE
・DELETE
・SELECT 単体
・SELECT 複数
を実施するようにしています。
※サービス単位でのトランザクション制御は後のページでやります。


13.TestController.java編集

jp.mitchy.controller にある TestController.java を変更し、
今回作成したサービスを呼び出して実行するようにします。
内容を以下のように書き換えて保存しましょう。
前もって作成しておいた test メソッドは削除してかまいません。
package jp.mitchy.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import jp.mitchy.dto.TestResultDto;
import jp.mitchy.entity.Department;
import jp.mitchy.service.DepartmentService;

@RequestMapping("/test/*")
@Controller
public class TestController {
	
	@Autowired
	private DepartmentService deptService;
	
	@RequestMapping(value = "/dept", method = RequestMethod.GET)
	public String dept(Model model) {
		// ------------------------------
		// 単テーブルのCURD確認
		// ------------------------------
		
		Department entity = new Department(4L, "新事業部");
		
		// サービスの実行
		TestResultDto<Department> dto = deptService.execute(entity);
		
		// 結果をセット
		model.addAttribute("data", dto.getEntity());
		model.addAttribute("list", dto.getList());

		// view/test/result.jsp を表示
		return "test/result";
	}
	
}

deptService フィールドに @Autowired アノテーションを付けることで
自動的に DepartmentServiceImpl のオブジェクトがバインドされます。

dept メソッドに
@RequestMapping(value = "/dept", method = RequestMethod.GET)
を付けることで http://サーバ/プロジェクト名/test/dept
の URL に対応します。

dept メソッドではサービスを実行します。
サービスでは ID=4 のレコードを追加、変更、削除し、
さらに ID=2 のレコードを取得、全レコードを取得します。
取得結果は DTO にセットして Controller に返します。
Controller はサービスから受け取った結果をモデルにセットし、
view/test/result.jsp を表示するようにして処理終了です。


14.index.jsp編集

最後に、作成した処理を呼び出せるように index.jsp を編集します。
src/main/webapp/index.jsp を開き、内容を以下のように書き換えて保存しましょう。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>

<html>
	<head>
		<meta charset="utf-8">
		<title>Welcome</title>
	</head> 
	<body>
		<c:url value="/test/dept" var="messageUrl1" />
		<a href="${messageUrl1}">Department Test</a><br/>
	</body>
</html>


15.確認実行

念のためにいつもの「Maven Clean」「Maven Install」をやっておきましょう。
エラーが出たら「Project」>「Clean」をやってから
再度「Maven Install」です。

プロジェクト名を右クリックして「Run As」>「Run On Server」を選択します。
図:STS

少し時間がかかりますが「Console」に状況が表示されていきます。
しばらくすると内蔵ブラウザが立ち上がり、「Department Test」と表示されます。
図:ブラウザ

「Department Test」のリンクをクリックしてみましょう。
リンク先 /test/dept に連動する TestController クラスの dept メソッドが呼び出され、
/WEB-INF/view/test/result.jsp が表示されることが確認できます。
テーブル操作も正常に実行されていますね。
(Consoleの出力内容も確認してみましょう)
図:ブラウザ

長かったですが、以上で Criteria API を使った単一テーブルのCRUDの
サンプル構築は完了です。


ダウンロード

作成したプロジェクトのソースをダウンロードできます。
341WebDbSample4CriteriaAPI.zip


更新履歴

2018/09/24 新規作成

TOPJavaspring → This Page
Valid CSS!