一、什么是SpringDataJpa
- JPA:是基于JDBC的封装,我们主要使用Hibernate对JPA的实现
- SpringDataJPA:是spring下面的一个子框架SpringData中对JPA再次进行了封装,让开发人员用起来更简单
- wenhao的jpa-spec框架:基于SpringDataJpa又封装了一次
二、集成Spring+SpringDataJpa
1.引入项目中所需要的所有包(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itsource</groupId>
<artifactId>yxb</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.springframework.version>4.2.5.RELEASE</org.springframework.version>
<org.hibernate.version>4.3.8.Final</org.hibernate.version>
<spring-data-jpa.version>1.9.0.RELEASE</spring-data-jpa.version>
<com.fasterxml.jackson.version>2.5.0</com.fasterxml.jackson.version>
<org.slf4j.version>1.6.1</org.slf4j.version>
</properties>
<dependencies>
<!-- Spring的支持包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<!-- 引入web前端的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- SpringMCV上传需要用到io包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 文件上传用到的包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
<!-- SpringMVC的json支持包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<!-- hibernate的支持包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${org.hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${org.hibernate.version}</version>
</dependency>
<!-- SpringData的支持包 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
</dependency>
<!-- SpringData的擴展包 -->
<dependency>
<groupId>com.github.wenhao</groupId>
<artifactId>jpa-spec</artifactId>
<version>3.1.1</version>
<!-- 把所有的依賴都去掉 -->
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<!-- 測試包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!-- 这个scope 只能作用在编译和测试时,同时没有传递性。表示在运行的时候不添加此jar文件 -->
<scope>provided</scope>
</dependency>
<!-- 日志文件 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<!-- 代码生成器模版技术 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.6</version>
</dependency>
<!-- shiro的支持包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.4.0</version>
<type>pom</type>
</dependency>
<!-- shiro与Spring的集成包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- poi支持的jar包 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.11</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.11</version>
</dependency>
<!-- 图片压缩功能 -->
<!-- 缩略图 -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.6</version>
</dependency>
<!-- 定时调度 -->
<dependency>
<groupId>quartz</groupId>
<artifactId>quartz</artifactId>
<version>1.5.2</version>
</dependency>
<!-- 邮件支持 -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
<build>
<finalName>aisell</finalName>
<pluginManagement>
<!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
4.dbcp.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///ibs
jdbc.username=root
jdbc.password=root
3.spring.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- 扫描包
@Controller @Service @Repository @Component
-->
<context:component-scan base-package="cn.itsource.service"/>
<!-- 开启Spring的注解支持 -->
<context:annotation-config/>
<!--
1)配置数据库连接池
dbcp.properties
2)配置JPA的EntityManagerFactory,使用FactoryBean的方式配置
3)支持全注解的事务管理 在Service层的实现类或者方法上面添加@Transactional注解即可
-->
<!--引入dbcp.properties文件-->
<context:property-placeholder location="classpath:dbcp.properties"/>
<!--配置dbcp连接池-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<!--通常情况下以下四个key都要加前缀-->
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置JPA的EntityManagerFactory【FactoryBean方式配置】-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!--引用一个数据库连接池-->
<property name="dataSource" ref="dataSource"/>
<!--指定我们的domain实体类【加了@Entity注解的实体类】在哪个包-->
<property name="packagesToScan" value="cn.itsource.domain"/>
<!--指定一个适配器-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--配置方言-->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
<!--建表策略-->
<property name="generateDdl" value="false"/>
<!--是否显示SQL-->
<property name="showSql" value="true"/>
</bean>
</property>
</bean>
<!-- Service层添加事务管理【全注解添加事务管理】 -->
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--
开启注解直接AOP
tx:annotation-driven 表示开启注解支持Spring的事务管理【AOP】,会查找默认的bean名称:transactionManager
transaction-manager属性可以指定事务管理器的bean名称,如果不指定默认找transactionManager
-->
<tx:annotation-driven transaction-manager="txManager" />
<!--
以下是集成SpringDataJPA的配置
base-package 表示指定一个包名,因为SpringDataJPA的DAO层只需要写接口,不需要写实现类【牛逼得很】
因为没有实现类,有需要创建对象,所以SpringDataJPA自动帮我们生成一个实现类,
所以扫描包就不能再使用context:component-scan扫描了,因为没有实现类,不能添加@Repository注解
factory-class="cn.itsource.factorybean.MyRepositoryFactoryBean"
SpringDataJPA默认使用SimpleJPARepository类作为自动生成的类的父类,如果需要修改就必须设置factory-class属性
-->
<jpa:repositories base-package="cn.itsource.dao" transaction-manager-ref="txManager"
factory-class="cn.itsource.factorybean.MyRepositoryFactoryBean" />
</beans>
设计思想
抽取BaseQuery用来接收前端高级查询请求参数
抽取排序方法
抽取分页方法
抽取获得Specification对象的方法
设计思想2
不想穿那么多参数
观察SimpleJpaRepository类的结构图
自定义扩展
BaseRepository
BaseRepositoryImpl
自定义的EmployeeRepository继承BaseRepository
修改配置文件指定我们自己的创建bean的方式
domain
@Entity
@Table(name="employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
private String password;
private String email;
private String headImage;
private Integer age;
//多个员工属于同一个部门【单向多对一】
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="department_id")
//@JsonIgnoreProperties 表示转化为JSON的时候忽略指定的属性
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler", "fieldHandler"})
private Department department;
......get,set省略
@Entity
@Table(name="department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
dao
BaseRepository
package cn.itsource.dao;
import cn.itsource.query.BaseQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
import java.util.List;
/**
* 自定义扩展接口,用作实际业务接口的父接口
* @param <T>
* @param <ID>
*/
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
/**
* 通过BaseQuery对象查询集合
* @param baseQuery 一般传入是BaseQuery的子类对象
* @return
*/
List<T> findAll(BaseQuery<T> baseQuery);
/**
* 通过BaseQuery对象进行分页+排序查询
* @param baseQuery 一般传入是BaseQuery的子类对象
* @return
*/
Page<T> findAllByPage(BaseQuery<T> baseQuery);
/**
* 执行jpql,支持可变参数
* @param jpql
* @param values
* @return
*/
List<T> findByJpql(String jpql, Object... values);
}
IEmployeeRepository
public interface IEmployeeRepository extends BaseRepository<Employee, Long> {
}
impl
BaseRepositoryImpl
package cn.itsource.dao.impl;
import cn.itsource.dao.BaseRepository;
import cn.itsource.query.BaseQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.List;
public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T,ID> {
private final EntityManager entityManager;
public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
this.entityManager = em;
}
@Override
public List<T> findAll(BaseQuery<T> baseQuery) {
return super.findAll(baseQuery.createSpecification());
}
@Override
public Page<T> findAllByPage(BaseQuery<T> baseQuery) {
return super.findAll(baseQuery.createSpecification(), baseQuery.createPageable());
}
@Override
public List<T> findByJpql(String jpql, Object... values) {
Query query = entityManager.createQuery(jpql);
if (values!=null) {
//设置参数
for(int i=0;i<values.length;i++){
query = query.setParameter(i+1, values[i]);
}
}
return query.getResultList();
}
}
Query:
抽取BaseQuery用来接收前端高级查询请求参数
BaseQuery
package cn.itsource.query;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
/**
* 高级查询的条件封装,放所有domain实体共有的高级查询条件
* 方便在Controller的方法参数列表中直接使用对象来接收高级查询条件参数
*/
public abstract class BaseQuery<T> {
private Long id;
//当前页码
private Integer pageNo = 1;
//每页展示行数
private Integer pageSize = 10;
//默认使用id字段排序
private String orderBy = "id";
//默认使用id字段降序排序
private String orderType = "DESC";
/**
* 创建分页规则
* @return
*/
public abstract Pageable createPageable();
/**
* 创建排序规则
* @return
*/
public abstract Sort createSort();
/**
* 创建Specification对象的抽象方法,专门交给子类去重写
* @return
*/
public abstract Specification<T> createSpecification();
public Integer getPageNoJPA() {
return pageNo-1;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getPageNo() {
return pageNo;
}
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public String getOrderBy() {
return orderBy;
}
public void setOrderBy(String orderBy) {
this.orderBy = orderBy;
}
public String getOrderType() {
return orderType;
}
public void setOrderType(String orderType) {
this.orderType = orderType;
}
}