スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Spring MVC Spring Data JPAを使ってみる

今回からデータアクセスの実装に着手したのでまとめておく。
データアクセスの実装パターンはいくつかあるが、JPAを使ってみた。なお、データベースにはH2を使用している。
処理はBookテーブルから全データを取得して結果表示するシンプルな内容とした。

■H2を使ったSpringSecurity関連の過去の記事
Spring MVC Spring Securityを使ってみる(その2)

◎動作検証にあたっての各バージョンは以下の通り
  • SpringFramework 3.2.8.RELEASE
  • Java 1.7
  • Tomcat 7.0

1.Mavenのpom.xml



org.hibernate
hibernate-entitymanager
4.2.1.Final


org.springframework
spring-orm
3.2.8.RELEASE


com.h2database
h2
1.4.178



2.datasource-config.xml

<?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/context
http://www.springframework.org/schema/context/spring-context.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">

<!-- jdbc -->
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:sql/login.sql"/>
<jdbc:script location="classpath:sql/book.sql"/>
</jdbc:embedded-database>

<!-- jpa -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="packagesToScan" value="jp.co.sample.book.entity"/>
</bean>
</beans>

「jdbc:script」タグでデータベース起動時に実行するSQLスクリプトファイルを定義できる。「login.sql」は先に紹介したSpringSecurity使用時に用意したログイン用のスクリプトファイルであり、今回新たに「book.sql」を用意した。内容は次を見てほしい。サンプルのようにスクリプトファイルは複数定義できる。
また、「transactionManager」には「JpaTransactionManager」を使用する。
「tx:annotation-driven」タグは、@Transactionalアノテーションを有効にするために定義する。
「entityManagerFactory」の「packagesToScan」のvalue値であるが、エンティティを定義しているパッケージ配下を指定すればよい。

3.book.sql


CREATE TABLE Book (
book_id BIGINT PRIMARY KEY AUTO_INCREMENT,
book_name VARCHAR(50) NOT NULL,
price INTEGER
);

INSERT INTO Book (book_name,price) VALUES ('Spring DI Sample',1000);
INSERT INTO Book (book_name,price) VALUES ('Spring AOP Sample',2000);
INSERT INTO Book (book_name,price) VALUES ('Spring DATA Sample',3000);

「book_id」については自動インクリメントを適用している。
テストデータは3件用意した。

4.BookEntity.java


package jp.co.sample.book.entity;

import java.io.Serializable;

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

@Entity
@Table(name="Book")
public class BookEntity implements Serializable{

@Id
@Column(name="book_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private long bookId;

@Column(name="book_name", length=50, nullable=false)
private String bookName;

@Column(nullable=false)
private int price;

//getter・setterは省略

JPAを理解する上で最も重要なクラス。@Entityアノテーションを付与することにより、JPAで永続化を行うクラスとして扱われる。
各フィールドについては、「book.sql」のCREATE文と対応付けて見てもらえると分かるが、アノテーションを使ってテーブル情報とマッピングを行っている。

5.BookDao.java


package jp.co.sample.book.dao;

import java.util.List;

public interface BookDao<T> {

List<T> findAll();
}

Daoインターフェースに全データを取得するfindAllメソッドを定義。

6.BookDaoImpl.java


package jp.co.sample.book.dao;

import java.util.List;

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

import jp.co.sample.book.entity.BookEntity;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class BookDaoImpl implements BookDao<BookEntity> {

@PersistenceContext
private EntityManager manager;

@Override
@Transactional(readOnly=true)
public List<BookEntity> findAll() {
Query query = manager.createQuery("from BookEntity");
return query.getResultList();
}
}

Daoの実装クラス。データアクセス層用の@Repositoryアノテーションを付与。
@Transactionalアノテーションはオーバーライド可能で、クラスだけでなくメソッドにも付与できる。クラスとメソッド両方に付与されている場合は、メソッド側が有効となる。
EntityManagerをインジェクションするためには、@PersistenceContextアノテーションを使用する。
「manager.createQuery("from BookEntity")」の"from BookEntity"はSQLと同じようにみえるが、JPQL(Java Persistence Query Language)と呼ばれているデータ問い合わせ言語である。「BookEntity」はクラス名でありテーブル名ではないことから、操作対象が異なることが分かると思う。ちなみに「"from Book"」とした場合、「org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Book is not mapped [from Book]」と例外が発生する。

7.BookService.java


package jp.co.sample.book.service;

import java.util.List;

public interface BookService<T> {

List<T> findAll();
}

Serviceインターフェースに全データを取得するfindAllメソッドを定義。

8.BookServiceImpl.java


package jp.co.sample.book.service;

import java.util.List;

import jp.co.sample.book.dao.BookDao;
import jp.co.sample.book.entity.BookEntity;

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

@Service
public class BookServiceImpl implements BookService<BookEntity> {

@Autowired
BookDao<BookEntity> dao;

@Override
public List<BookEntity> findAll() {
return dao.findAll();
}
}

Serviceの実装クラス。サービス層用の@Serviceアノテーションを付与。
処理はdaoに委譲している。

9.BookController.java


package jp.co.sample.book.controller;

import java.util.List;

import javax.validation.Valid;

import jp.co.sample.book.entity.BookEntity;
import jp.co.sample.book.form.BookForm;
import jp.co.sample.book.service.BookService;
import jp.co.sample.util.BookUtil;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Controller
@RequestMapping("book")
public class BookController {

private static Logger logger = LoggerFactory.getLogger(BookController.class);

@Autowired
protected BookService<BookEntity> bookService;

@RequestMapping(method = RequestMethod.GET)
public String index(BookForm form) {
logger.info("index start");
return "newBook";
}

@RequestMapping(value = "list", method = RequestMethod.GET)
public String list(Model model) {
logger.info("list start");
List<BookEntity> entites = bookService.findAll();
model.addAttribute("books", entites);
return "list";
}

@RequestMapping(value = "create", method = RequestMethod.POST)
public String create(@Valid BookForm form, BindingResult result, Model model) {
logger.info("create start");
if (result.hasErrors()) {
return "newBook";
}
//TODO bookServiceより返却されたBookオブジェクトをmodelに追加する
return "result";
}
}

Controllerのクラス。プレゼンテーション層用の@Controllerアノテーションを付与。
いくつかメソッドがあるが、今回の対象はlistメソッドに絞る。引数にModelを用意しているが、これで自動的にModelのインスタンスが設定される。そのため、model.addAttribute()でNullポインタ例外は発生しない。
他のメソッドについては、過去のSpring MVC関連の記事を参考にしてほしい。

10.list.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<link href="<c:url value="/css/bootstrap.min.css" />" rel="stylesheet">
<link href="<c:url value="/css/bootstrap-theme.min.css" />" rel="stylesheet">
<script src="<c:url value="/js/bootstrap.min.js" />"></script>

<title>list</title>
</head>
<body>
<div class="container-fluid">
<table class="table table-striped">
<tr>
<th>Book Id</th>
<th>Book Name</th>
<th>Price</th>
</tr>
<c:forEach items="${books}" var="book">
<tr>
<td>${book.bookId}</td>
<td>${book.bookName}</td>
<td>${book.price}</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>

CSSにはBootstrapを使用している。

11.動作確認

リスト

アノテーションを使ってテーブル情報とマッピングする方法は、直観的に分かりやすいと感じた。

■過去のSpring関連記事
Spring関連記事 Index

スポンサーサイト

コメントの投稿

非公開コメント

プロフィール

bookmount8

Author:bookmount8
システムエンジニア。サーバーサイドでjavaを扱うことが多い。最近は、ミドルやフロント周りも関心あり。

最新記事
カテゴリ
検索フォーム
最新コメント
月別アーカイブ
これまでの訪問者数
ブロとも申請フォーム

この人とブロともになる

RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。