[Java][Spring Boot] DAOを作ってJPQLを操ってみる。

2016.07.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Spring BootのMVCの意味を考えると、コントローラーにデータベースにアクセスするコードを書くべきでは無い様です。
DAO(Data Access Object)を使用する事で実現できます。
そこで、これまでの記事の様にEntity、Repository、Service、Controllerではなく、Entity、DAO、Controllerの構成で作ってみます。
また、より低レベルなJPQLへの入り口にも触れてみました。

環境

Mac OSX 10.10.5 Yosemite
Eclipse Mars2
Java 8
Spring Boot 1.3.6
PostgreSQL 9.5.1

準備

テーブル:fruit

CREATE TABLE fruit (
    id VARCHAR(2) NOT NULL,
    name VARCHAR(10),
    price integer,
    PRIMARY KEY(id)
);

INSERT INTO fruit VALUES
  ('1','apple',300),
  ('2','orange',200),
  ('3','banana',100);
postgres=# select * from fruit;
 id |  name  | price 
----+--------+-------
 1  | apple  |   300
 2  | orange |   200
 3  | banana |   100
(3 rows)

コード

build.gradle(依存関係のみ抜粋)

dependencies {
	compile('org.springframework.boot:spring-boot-starter-data-jpa')
	compile('org.springframework.boot:spring-boot-starter-jdbc')
	compile('org.projectlombok:lombok:1.16.6')
	compile('org.springframework.boot:spring-boot-starter-web')
	runtime('org.postgresql:postgresql')
	testCompile('org.springframework.boot:spring-boot-starter-test') 
}

application.yml(DB接続設定)

spring:
  datasource:
    url : jdbc:postgresql://localhost/データベース名
    username : XXXXX
    password : YYYYY
    driverClassName : org.postgresql.Driver

エンティティ

package com.jpa.mydao;

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

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Entity
@Data
@Table(name="fruit")
public class Fruit {

	@Id
	private String id;
	private String name;
	private Integer price;

}

11行目、Entity設定
12行目、Lombok。getter/setterを設定する目的。
[Java]Lombokでコードを短縮させる。
13行目、テーブル「fruit」に繋げる設定。

DAOインターフェース

package com.jpa.mydao.dao;

import java.io.Serializable;
import java.util.List;

public interface FruitDao <T> extends Serializable {

	public List<T> getAll();
	public List<T> getWhereId(String id);
	
}

DAOで使用するメソッドを作成。

DAOオブジェクト

package com.jpa.mydao.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;

import com.jpa.mydao.Fruit;

@Repository
public class FruitDaoJpql implements FruitDao<Fruit>{

	private EntityManager entityManager;
	
	public FruitDaoImpl() {
		super();
	}
	
	public FruitDaoImpl(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
	
	@Override
	public List<Fruit> getAll() {
		Query query = entityManager.createQuery("from Fruit");
		List<Fruit> list = query.getResultList();
		entityManager.close();
		return list;
	}

	@Override
	public List<Fruit> getWhereId(String id) {
		List<Fruit> list = entityManager
							.createQuery("from Fruit where id = :id")
							.setParameter("id", id)
							.getResultList();
		return list;
	}

}

ここでDAOインターフェースを使用します。
18行目22行目のコンストラクタはLombokでも良いのですが、ちゃんと書いた方が分かりやすいかなと思いました。
Lombok使用なら、クラスに@AllArgsConstructorと@NoArgsConstructorですね。

26~32行目、DAOインターフェースで作成したメソッド、getAll()。
メソッド名通り、全レコードを取得するように設定します。
28行目、EntityManager.createQuery()でJPQLを作成できます。
"from Fruit"は、SQL"select * from fruit;"と同じ意味です。
注意点すべきはテーブル名で、エンティティに設定したクラス名を指定しましょう。
SQLのように、小文字でテーブルを直に指定しようとすると、QuerySyntaxExceptionが発生します。
29行目、クエリ実行結果をListに入れます。

34~42行目、指定したIDに一致するレコードを取得するメソッド、getWhereId()。
今度はQueryをショートカットして実行結果をListに入れています。
38~39行目、getAll()とはJPQLが違いパラメータidを設定するので、
setParameter("キー", パラメータ)と設定し、JPQLクエリに「:キー」と設定してパラメータを参照させます。

コントローラー

package com.jpa.mydao;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.jpa.mydao.dao.FruitDaoJpql;

@RestController
public class EntityManagerController {

	@PersistenceContext
	EntityManager entityManager;
	
	FruitDaoJpql dao;
	
	@PostConstruct
	public void init() {
		dao = new FruitDaoJpql(entityManager);
	}
	
	@RequestMapping(value="/all", method=RequestMethod.GET)
	public List<Fruit> all() {
		List<Fruit> list = dao.getAll(); 
		return list;
	}
	
	@RequestMapping(value="/where", method=RequestMethod.GET)
	public List<Fruit> where(@RequestParam("id") String id) {
		List<Fruit> list = dao.getWhereId(id); 
		return list;
	}

}

17行目、@RestControllerを設定。
ターミナルからcurlコマンドで取得結果を表示して確認するためです。

20~21行目、@PersistenceContextでアプリ起動時にBeanに登録されるEntityManagerを結びつけています。
EntityManagerは1つのアプリで1度しか設定できず、複数設定するとエラーとなります。

25~28行目、@PostConsructでコンストラクタ実行後に自動的に呼ばれるメソッドを作り、DAOオブジェクトにEntityManagerを渡します。
これは、残り2つのメソッドを使用するための準備だと思ってください。

30~34行目、メソッドall()。
FruitDaoJpql.getAll()で、テーブルfruitの全レコードを取得し、Listを返します。
その返し値をreturnに指定。

36~40行目、メソッドwhere()。
FruitDaoJpql.getWhereId()の引数にidを渡して、対象のレコードを取得し、Listを返します。
返し値をreturnに指定。

ターミナルから実行

all()

$ curl http://localhost:8080/all
[{"id":"1","name":"apple","price":300},{"id":"2","name":"orange","price":200},{"id":"3","name":"banana","price":100}]

where()

$ curl http://localhost:8080/where?id=1
[{"id":"1","name":"apple","price":300}]

さいごに

これでコードがシンプルになるのでは無いでしょうか。
今度はJPQLについて、さらに深く掘ってみようと思います。