Spring MVC＋Oracleで@PersistenceContext使う

前回の記事でSpring MVCでOracleDBに接続する方法を書いたが、あの後EntityManagerを手動で作らなくても@PersistenceContextアノテーションを使うとSpringが自動で注入してくれるって知った。
けど、@PersistenceContextを書いただけでは、エラーが起きたので使用するための設定を調べてみました。。。

この前買った本には「@PersistenceContexを使うとできる」くらいしか書いてなくて最初はさっぱりだったので、初心者にもわかるようにもっと詳しく書いてほしいです。。

## servlet-context.xml(Beans定義ファイル）

``` servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

	<!-- Enables the Spring MVC @Controller programming model -->
	<mvc:annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<mvc:resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean id="templateResolver"
		class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
		<beans:property name="prefix" value="/WEB-INF/templates/" />
		<beans:property name="suffix" value=".html" />
		<beans:property name="templateMode" value="HTML5" />
	</beans:bean>
	<beans:bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
		<beans:property name="templateResolver" ref="templateResolver" />
	</beans:bean>

	<beans:bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
		<beans:property name="templateEngine" ref="templateEngine" />
		<beans:property name="characterEncoding" value="UTF-8" />
	</beans:bean>

	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver" />

	<beans:bean id="xmlViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
		<beans:property name="order" value="1" />
		<beans:property name="location" value="/WEB-INF/spring/views.xml" />
	</beans:bean>

	<context:annotation-config />
	<context:component-scan base-package="jp.test.spring" />
    <!-- ↓ここから追記 -->
	<context:property-placeholder location="classpath:jdbc.properties"/>

	<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<beans:property name="driverClassName" value="${jdbc.driverClassName}" />
		<beans:property name="url" value="${jdbc.url}" />
		<beans:property name="username" value="${jdbc.username}" />
		<beans:property name="password" value="${jdbc.password}" />
	</beans:bean>

	<beans:bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />

	<beans:bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<beans:property name="database" value="ORACLE" />
		<beans:property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
	</beans:bean>

	<beans:bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <beans:property name="packagesToScan" value="jp.test.spring.entity" />
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="jpaDialect" ref="jpaDialect" />
        <beans:property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
    </beans:bean>

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

    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- ↑ここまで追記 -->
</beans:beans>
```

※他のユーザさんの投稿の書き方を倣ってファイルのコメントに追加した部分を明記してみましたｗ

### Oracle 11g接続設定
``` servlet-context抜粋.xml
<beans:bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <beans:property name="database" value="ORACLE" />
    <beans:property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</beans:bean>
```

今回はOracle XE 11gなので"database"には"ORACLE"、"databasePlatform"には"org.hibernate.dialect.Oracle10gDialect"を設定
※Orale11gDialectはなく10gを使うらしい
※PostgreSQLやHSQLなど他のDBを使う場合はここを適時修正する
※最初Oracleの場合、何を設定するの？って思ったけどhttp://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/jpa/vendor/AbstractJpaVendorAdapter.html#setDatabase-org.springframework.orm.jpa.vendor.Database- を見たら書いてあった

### DB接続設定

DB接続設定をjdbc.propertiesに外だしにしているので src/main/resources 直下にjdbc.propertiesを新規作成

``` jdbc.properties
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521/xe
jdbc.username=(DB接続ユーザ名)
jdbc.password=(DB接続パスワード)
```

### EntityManagerFactory設定

あとはEntityManagerのEntityがいるパッケージの設定("packageToScan")に注意。
設定したパッケージ配下を探してくれるみたいなので最上位のパッケージを指定してもよいが通常Entityを格納するパッケージが決まっていると思うのでそこを指定。
今回は"jp.test.spring.entity"

``` servlet-context抜粋.xml
<beans:bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <beans:property name="packagesToScan" value="jp.test.spring.entity" />
    <beans:property name="dataSource" ref="dataSource" />
    <beans:property name="jpaDialect" ref="jpaDialect" />
    <beans:property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
</beans:bean>
```

(注)spring-ormライブラリをpom.xmlに追加する必要あり

## @PersistenceContex使用！

@PersistenceContextアノテーションを使用する準備が整ったので早速試してみる
※Entityクラスは前回のものを使用(http://qiita.com/zateon/items/f5129cd1367dc12e675d#entity%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90)
※テスト用なのでServiceクラスでEntityManager使ってます。。

``` TestServiceImpl.java
package jp.test.spring.service.impl;

import java.util.List;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import jp.test.spring.entity.NameT;
import jp.test.spring.service.TestService;

@Service("testService")
public class TestServiceImpl implements TestService {

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

	@PersistenceContext
	private EntityManager entityManager;

	@Override
	public List<NameT> getJpa() {
		logger.info("getJpa()");
//		EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa.sample");
//		EntityManager em = emf.createEntityManager();
//
//		List<NameT> nameTList = em.createNamedQuery("NameT.findAll", NameT.class).getResultList();
//		for (NameT nameT : nameTList) {
//			logger.info("id: " + nameT.getId() + " / name: " + nameT.getName());
//		}
//
//		em.close();
//		emf.close();

		List<NameT> nameTList = entityManager.createNamedQuery("NameT.findAll", NameT.class).getResultList();
		for (NameT nameT : nameTList) {
			logger.info("id: " + nameT.getId() + " / name: " + nameT.getName());
		}

		return nameTList;
	}

}
```

以上でアクセスできた＾＾