|
前言: JPA全稱Java Persistence API,即Java持久化API,它為Java開(kāi)發(fā)人員提供了一種對(duì)象/關(guān)系映射工具來(lái)管理Java應(yīng)用中的關(guān)系數(shù)據(jù),結(jié)合其他ORM的使用,能達(dá)到簡(jiǎn)化開(kāi)發(fā)流程的目的,使開(kāi)發(fā)者能夠?qū)W⒂趯?shí)現(xiàn)自己的業(yè)務(wù)邏輯上。 Spring Jpa 能夠簡(jiǎn)化創(chuàng)建 JPA 數(shù)據(jù)訪問(wèn)層和跨存儲(chǔ)的持久層功能,用戶的持久層Dao接口只需要繼承他自己定義好的(倉(cāng)庫(kù))接口,無(wú)需再寫實(shí)現(xiàn)類,就可以實(shí)現(xiàn)對(duì)象的CRUD操作,還有分頁(yè)排序等功能。
寫本章之前本來(lái)想寫一個(gè)SpringMVC的,后來(lái)發(fā)現(xiàn)Jpa的配置可以大大簡(jiǎn)化MVC框架的配置,就先研究研究Spring Data Jpa。 準(zhǔn)備工作:
先來(lái)看一下本章節(jié)用到的包結(jié)構(gòu)--如下圖:
實(shí)例代碼演示: ****************最后我會(huì)把本章的項(xiàng)目打包供下載************注釋部分我盡可能詳細(xì)講解**************** jar包導(dǎo)入.....(略) web.xml配置 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns="http://java./xml/ns/javaee" xmlns:web="http://java./xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java./xml/ns/javaee http://java./xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>springMVC</display-name> <!-- 同時(shí)加載多個(gè)spring配置文件可用 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-config/*.xml </param-value> </context-param> <!-- spring全局監(jiān)聽(tīng) --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 下面為Druid默認(rèn)配置,過(guò)濾掉多余的url地址 --> <filter> <filter-name>DruidWebStatFilter</filter-name> <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class> <init-param> <param-name>exclusions</param-name> <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value> </init-param> <init-param> <param-name>principalSessionName</param-name> <param-value>_dest_login_</param-value> </init-param> </filter> <filter-mapping> <filter-name>DruidWebStatFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- StatViewServlet是一個(gè)標(biāo)準(zhǔn)的Servlet --> <servlet> <servlet-name>DruidStatView</servlet-name> <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DruidStatView</servlet-name> <url-pattern>/druid/*</url-pattern> </servlet-mapping> <!-- Spring Servlet,由于把bean全部交給了SpringJap,所以Spring-mvc里面現(xiàn)在為空 --> <servlet> <servlet-name>springServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 首頁(yè) --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> spring-mvc.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:context="http://www./schema/context" xmlns:mvc="http://www./schema/mvc" xsi:schemaLocation="http://www./schema/mvc http://www./schema/mvc/spring-mvc-3.1.xsd http://www./schema/beans http://www./schema/beans/spring-beans-3.1.xsd http://www./schema/context http://www./schema/context/spring-context-3.1.xsd"> <!-- bean配置在spring-jpa.xml里,所以這里暫為空,用來(lái)初始化spring容器--> </beans> spring-jpa.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:tx="http://www./schema/tx" xmlns:context="http://www./schema/context" xmlns:jpa="http://www./schema/data/jpa" xmlns:task="http://www./schema/task" xmlns:aop="http://www./schema/aop" xsi:schemaLocation="http://www./schema/aop http://www./schema/aop/spring-aop-3.1.xsd http://www./schema/beans http://www./schema/beans/spring-beans-3.1.xsd http://www./schema/tx http://www./schema/tx/spring-tx-3.1.xsd http://www./schema/task http://www./schema/task/spring-task-3.0.xsd http://www./schema/context http://www./schema/context/spring-context-3.1.xsd http://www./schema/data/jpa http://www./schema/data/jpa/spring-jpa.xsd" default-lazy-init="true"> <description>SpringJpa配置</description> <!-- 如果spring用了jpa,并且類型為L(zhǎng)ocalContainerEntityManagerFactoryBean,則組件注冊(cè)在此配置文件出現(xiàn)即可,其余配置文件可忽略 使用component來(lái)替代annotation 自動(dòng)注冊(cè)bean, 并保證@Required、@Autowired的屬性被注入\ --> <context:component-scan base-package="com.spring.jpa"/> <!-- spring啟動(dòng)時(shí)掃描項(xiàng)目路徑下的properties文件,后續(xù)用${key }方式取出對(duì)應(yīng)值,這樣可以代碼解耦和,后續(xù)只需修改properties文件即可 --> <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <!-- dataSourse連接池相關(guān)屬性,代碼不在此貼出,會(huì)放在打包好的項(xiàng)目里面 --> <value>classpath:db.properties</value> </list> </property> </bean> <!-- 定義實(shí)體管理器工廠 Jpa配置 LocalContainerEntityManagerFactoryBean這個(gè)選項(xiàng)Spring扮演了容器的角色。完全掌管JPA --> 點(diǎn)我查看 spring生成EntityManagerFactory的三種方式 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <!-- 指定數(shù)據(jù)源 --> <property name="dataSource" ref="dataSource"/> <!-- 指定Jpa持久化實(shí)現(xiàn)廠商類,這里以Hibernate為例 --> <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/> <!-- 指定Entity實(shí)體類包路徑 --> <property name="packagesToScan" > <array> <value>com.spring.jpa</value> </array> </property> <!-- 指定JPA屬性;如Hibernate中指定是否顯示SQL的是否顯示、方言等 --> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">validate</prop> </props> </property> </bean> <!-- 重要配置:?jiǎn)⒂脪呙璨⒆詣?dòng)創(chuàng)建代理的功能 --> <jpa:repositories base-package="com.spring.jpa" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/> <!-- Hibernate對(duì)Jpa的實(shí)現(xiàn) --> <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> <!-- Jpa 事務(wù)管理器 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- 開(kāi)啟注解事務(wù) --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> <!-- 數(shù)據(jù)源配置,使用應(yīng)用內(nèi)的DBCP數(shù)據(jù)庫(kù)連接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!--property name="driverClassName" value="${db.driverClass}"/--> <property name="url" value="${db.jdbcUrl}" /> <property name="username" value="${db.user}" /> <property name="password" value="${db.password}" /> <!-- 配置初始化大小、最小、最大 --> <property name="initialSize" value="${db.initialSize}" /> <property name="minIdle" value="${db.minIdle}" /> <property name="maxActive" value="${db.maxActive}" /> <!-- 配置獲取連接等待超時(shí)的時(shí)間 --> <property name="maxWait" value="${db.maxWait}" /> <!-- 配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="${db.timeBetweenEvictionRunsMillis}" /> <!-- 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}" /> <property name="validationQuery" value="SELECT 'x' from dual" /> <property name="testWhileIdle" value="true" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <!-- 打開(kāi)PSCache,并且指定每個(gè)連接上PSCache的大小 --> <property name="poolPreparedStatements" value="${db.poolPreparedStatements}" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="${db.maxPoolPreparedStatementPerConnectionSize}" /> </bean> <!-- 啟動(dòng)對(duì)@AspectJ(面向切面)注解的支持 --> <aop:aspectj-autoproxy /> </beans>
配置好了配置文件后,我們?cè)搧?lái)寫對(duì)應(yīng)的實(shí)體類,Dao,和service了,下面給出簡(jiǎn)單的3個(gè)類: User 實(shí)體類
User EntityIUserDao 持久層(jpa對(duì)持久層簡(jiǎn)化的核心基礎(chǔ)) package com.spring.jpa.user; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; /** * 持久層接口 * @author liuyt * @date 2014-10-30 下午2:09:48 */ @Repository public interface IUserDao extends PagingAndSortingRepository<User, Long>{ /** * 通過(guò)前面的配置可以看出,Spring 對(duì) JPA 的支持已經(jīng)非常強(qiáng)大,開(kāi)發(fā)者無(wú)需過(guò)多關(guān)注 EntityManager 的創(chuàng)建、事務(wù)處理等 JPA 相關(guān)的處理 * *********************************************************************** * 然而spring對(duì)Jpa的支持不止于此,它要從根本上來(lái)簡(jiǎn)化我們的業(yè)務(wù)代碼 ** * 在沒(méi)用使用jpa支持的時(shí)候,我們的代碼應(yīng)該是這樣的: ** * 1、IUserDao 持久層接口 ** * 2、IUserDaoImpl 持久層實(shí)現(xiàn)類 ** * 3、IUserService 業(yè)務(wù)層接口.....后面不在列舉 ** * 每寫一個(gè)實(shí)體類,都要衍生出5、6個(gè)類來(lái)對(duì)他進(jìn)行操作,即使有了注解,我們可以依賴注入方式來(lái)拿到實(shí)現(xiàn)類, ** * 但是通用的CRUD等操作卻不免在每個(gè)實(shí)現(xiàn)類里聲明,你又說(shuō),我可以定義一個(gè)父類,利用泛型反射原理就可以了, ** * 但那樣你還需要為每個(gè)Dao聲明自己的實(shí)現(xiàn)類來(lái)繼承你的父類 ** * *********************************************************************** * 那么問(wèn)題來(lái)了...(不是挖掘機(jī)技術(shù))對(duì)持久層的簡(jiǎn)化技術(shù)哪家強(qiáng)? Spring Data Jpa ** * 你唯一要做的就只是聲明持久層的接口,來(lái)繼承他自身已經(jīng)封裝好的持久層接口,正如本類IUserDao一樣 ** * 可使用的接口有: ********** * Repository:是 Spring Data的一個(gè)核心接口,它不提供任何方法,開(kāi)發(fā)者需要在自己定義的接口中聲明需要的方法。** * CrudRepository:繼承Repository,提供增刪改查方法,可以直接調(diào)用。 ** * PagingAndSortingRepository:繼承CrudRepository,具有分頁(yè)查詢和排序功能(本類實(shí)例) ** * JpaRepository: 繼承PagingAndSortingRepository,針對(duì)JPA技術(shù)提供的接口 ** * JpaSpecificationExecutor: 可以執(zhí)行原生SQL查詢 ** * 繼承不同的接口,有兩個(gè)不同的泛型參數(shù),他們是該持久層操作的類對(duì)象和主鍵類型。 ** ********************************************************************************* */ } 這里為了方便演示,就不寫業(yè)務(wù)層接口了,直接上業(yè)務(wù)層service代碼 UserService 業(yè)務(wù)層 package com.spring.jpa.user; import java.util.List; import javax.annotation.Resource; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; /** * User業(yè)務(wù)層,依賴持久層 IUserDao * @author liuyt * @date 2014-10-30 下午2:37:21 */ @Service public class UserService { // 推薦用Resource來(lái)替代AutoWrite注解 @Resource private IUserDao userDao; // 新增用戶 public void saveUser(User user) { userDao.save(user); } // 刪除用戶,參數(shù)也可以為一個(gè)含有id的User對(duì)象 public void deleteUser(Long id) { userDao.delete(id); } // 查詢所有user對(duì)象,findOne為查詢單個(gè) public List<User> findAllUsers() { return (List<User>) userDao.findAll(); } /** * 根據(jù)一個(gè)分頁(yè)對(duì)象查詢user集合(還可以添加一個(gè)Store排序?qū)傩裕? * PageRequest 是spring自己封裝的請(qǐng)求分頁(yè)類,實(shí)現(xiàn)了Pageable接口,包涵從請(qǐng)求中獲得的分頁(yè)屬性(當(dāng)前頁(yè)和大?。┖瞳@取方法 * 通過(guò)調(diào)用分頁(yè)方法,返回一個(gè)Page<>一個(gè)泛型集合的分頁(yè)對(duì)象,里面包涵了通過(guò)查詢計(jì)算出的各個(gè)屬性和結(jié)果集 * 詳細(xì)類結(jié)構(gòu)和屬性請(qǐng)參閱源碼 * @param page * @return */ public Page<User> findAllUserByPage(PageRequest page) { return (Page<User>) userDao.findAll(page); } }
至此,整體SpringJpa框架就搭建好了,剩下的就是寫頁(yè)面和控制器進(jìn)行測(cè)試了,這里不做演示,因?yàn)闀?huì)在下一章節(jié)利用SpringJUnit單元測(cè)試,通過(guò)注解的方式進(jìn)行方法測(cè)試,詳情請(qǐng)移步:SpringJUnit4單元測(cè)試 |
|
|