この記事は公開されてから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について、さらに深く掘ってみようと思います。