1.项目集成Spring
1.开发核心包 :导入context包
2.AOP支持 :导入Aspects包
3.测试集成 : 导入test包
4.web集成,配置监听器: 导入web包
5.整合持久层框架: 导入orm包
6.在web.xml中配置spring的监听器;
2.Spring整合JPA
1.在applicationContext.xml中配置连接池;
2.JPA配置 类似于 Hibernate的配置 ,因为Hibernate就是JPA的一个实现,所以准确地说是Hibernate的配置
与JPA很像:但是我们先学习的是Hibernate,就先入为主,我们比较了解Hibernate的配置,然后来类比学习JPA的
配置:
Hibernate的 :LocalSessionFactoryBean (SessionFactory的工厂)
JPA的: LocalContainerEntityManagerFactoryBean (EntityManagerFactory的工厂);
Hibernate的 :SessionFactory
JPA的: EntityManagerFactory
以前我们Spring整合Hibernate是让 Spring接管SessionFactory,
现在我们Spring整合JPA是让Spring接管EntityManagerFactory;
因为对象关系映射 使 java的对象与数据库的表建立了一一对应的关系,所以我们使用JPA对数据库进行CRUD
操作,已经不再直接面向数据库了,而是面向java对象实体,所以JPA中的核心对象就是 实体管理对象,即
EntityManager,Hibernate作为一个JPA的实现,它的 Session 其实就是 EntityManager的实现,因为虽然在JDBC
阶段我们操作数据库时使用的是 Connection,但是一有了 对象关系映射(orm) ,对象与实体间已经建立了连接,
我们操作的数据库不再面向 Connection ,而是面向对象实体了, 在Hibernate中我们说 Session就相当于是
JDBC中的 Connection ,这样说只是为了便于我们利用 JDBC中的一些只是来理解Hibernate,其实这样说是不对的,
因为我们现在看来,这个Session 是一个实体管理器,它是面向实体的,而JDBC中的 Connection 确实隐藏在实体中,
所以准确地说 Session 其实是通过 实体来操作 Connection ,进而实现了 类似 JDBC 操作;
关于这个理解,我们从SessionFactory的配置中就可以看出来,它里边有:
1. DataSource(连接池),
2. Hibernate一些基本设置:比如方言,自动建表,显示建表语句等等,
3. Mapping(orm)
也就是说 SessionFactory 做为Session的工厂,在生产Session是时,将 DataSource 与 Mapping进行了融合,最终
给我们生成出来的 Session 其实已经包含了对象关系映射和连接,这样导致它可以直接面向实体对象, 达到操作
数据库表的效果;
3.声明式事务管理:(用什么框架就用响应的事务管理器)
为什么是这样呢?我们在JDBC阶段就知道事务管理的本质是通过Connection来实现的,在不同的 持久层 框架中,Connection
被封装在不同的对象中:
在Hibernate框架中, Connection 被封装到 SessionFactory 中,
在JPA中 , Connection 被封装到 EntityManagerFactory 中;
这就导致了,我们在使用不同框架进行声明式事务管理时,要获得Connection就要使用不同的对象;就是不同的事务管理器;
3. SpringDataJPA 查询 (其实只是 封装了SQL语句)
1.出现目的:为了简化统一持久层各种实现技术的API; 所以 SpringDataJPA 提供了一套标准API 和不同持久层整合技术实现;
2. Spring-data-commens 一套标准API 比如 JpaRepository.class就在 这个jar包下 ;
Spring-data-jpa 基于整合JPA的一套实现;
3.具体操作:
1.写一个接口(比如Dao层接口)继承 JPARepository接口 (或者QBC查询:JpaSpecificationExecutor接口)
2.我们在 Dao 接口里边 就可以调用 JPARepository 接口的方法, JPARepository有一个默认实现类:
SimpleJpaRepository,当我们 调用获得Dao接口对象时,得到的是接口的子类代理对象proxy,当我们
调用这个代理对象proxy的方法时, 实际调用的是 SimpleJpaRepository的方法;这样实现一些既定的
CRUD操作;
3. 但是自带的API中没有条件查询,这个时候我们就要用到 Spring data Query:
1.根据方法命名规则 命名方法,自动生成 JPQL查询;
个人理解:我们通过方法命名规则不难看出,它底层实际是将方法名和传入参数解释成了一条查询语句,
所以只要你按照他的规则命名,并且传入相应的参数,它就知道如何转换成一条JPQL语句;如果
类比理解,你自定义的Dao就是 QueryRunner ,你自定义的方法就是 sql语句; 它是首先将一些
常用的CRUD封装好了,需要参数出入的,它给你提供方法,让你传入参数; 对于一些复杂的条件
查询,它可能是没办法给给你全都封装好,所以就给你提供了一个方法命名规则,然后你根据方法
命名规则命名,出入参数,它在转换成查询语句,换句话说,方法对于他来说就是查询语句,而方法
命名规则,就是它给你提供的查询语句编写规则,当然这个规则主要是应对复杂多变的条件查询;
2.注解方式:
这个就更加灵活了,它其实就是屏蔽了 底层对于方法名的解释,直接读取你方法上的注解的 hql语句
1. @Query("hql",参数1,参数2) 注解下的方法名可以随便写了,参数的顺序要和hql顺序一致;另外这个
只能做查询,不支持DML语句,就是不支持 增删改
2.在 @Query下增加 @Modifying ,另外还要开启事务,增加@Transactional
默认情况下单元测试时,事务最终会回滚; 可以通过在添加 @Rollback(false) 来阻止回滚;
4. 有条件的分页查询中的 条件的构建:
public interface Specification
/**
* Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given
* {@link Root} and {@link CriteriaQuery}.
*
* @param root 代表的是 T 所代表的类的对象, 目的是为了调出 T 类的属性名 比如 'name' 'age' ,
* @param query 构造简单条件返回,提供 where 方法;
* @param cb 构造Predicate 对象,条件对象, 构造复杂查询效果;
* @return a {@link Predicate}, must not be {@literal null}.
*/
Predicate toPredicate(Root
}
4. Spring--->hibernate
Spring--->SpringDataJPA--->JPA
这两个整合的对比分析:
Spring--->hibernate 这个整合中,hibernate做的事情是:
1. 封装了JDBC, 原生JDBC操作步骤较多,按照 hibernate 的配置,我们在DAO中通过继承 HibernateDaoSupport,
就直接可以获得CRUD操作对象 hibernateTemplate;
2. 封装了SQL语句, 原生SQL语句操作的对象是数据库的表,封装以后我们使用主要使用HQL语句,操作对象是类;
Spring--->SpringDataJPA--->JPA 这个整合中:
1. JPA的作用和Hibernate作用相同,因为Hibernate就是JPA的一个实现,所以JPA也可以做两件事情:
1. 封装了JDBC ,
2. 封装了SQL语句 ;
但是,在这个整合中,JPA只做了一件事情,那就是: 1. 封装了JDBC ,所以它的配置部分与Hibernate几乎雷同;
而对于第二件事情:2. 封装了SQL语句 ; 它交给了另一个框架: SpringDataJPA 来做,我们用一个框架可以做
的事情,现在我们却选择,用两个框架来完成,那只能说明一个问题:那就是 JPA 在 1. 封装了JDBC ,这件事情
上做得和 Hibernate 不相上下,但是 SpringDataJPA 在 2. 封装了SQL语句 ;这件事情是相当出色;下面我们
就来讨论一下 SpringDataJPA 对 SQL语句的封装;
2. SpringDataJPA 对 SQL语句的封装: (SimpleJpaRepository 作为实现类,实际上完成了对SQL语句的封装)
封装原理: SpringDataJPA 它有一个 JPARepository 接口,接口中定义了一些常用的简单的CRUD操作,
这个接口有一个默认实现类 SimpleJpaRepository
JPARepository 接口中的方法; 我们写一个 Dao 接口继承 JPARepository ,然后将这个接口注入到
Service 中,这时在Spring做注入操作时,会判断我们的接口继承了 JPARepository 然后会 利用 AOP 思想,
给我们的 Service 注入一个 SimpleJpaRepository 的对象,而这个对象中,它把常用的SQL进行了封装,极大
便利了我们常用的存的数据库操作,比如:
1. 单个对象数据保存操作,批量对数据保存;
2. 无条件删除,无条件查询操作;
3. 常用的分页查询操作,也做了封装;
5. 聊一下 JQueryEasyUI 中数据表 datagrid 的分页操作:
DataGrid属性 中有一个属性: pagination : true,就开启了分页条;
$('#grid').datagrid( {
iconCls : 'icon-forward',
fit : true,
border : false,
rownumbers : true,
striped : true,
pageList: [30,50,100],
pagination : true,
toolbar : toolbar,
url : "../../standard_pageQuery.action",
idField : 'id',
columns : columns
});
1. 当我们加载页面时,会自动传给服务端两个数据: 1.当前页面: page , 2. 每页显示记录条数 rows
2. datagrid 的url 属性会根据路径发送ajax请求, 服务器端会返回json数据:格式如下
{
"total":100,
"rows":[
{"id":"001","name":"10-20公斤","minWeight":"10",
"maxWeight":"20","minLength":"11","maxLength":"22",
"operator":"张三","operatingTime":"2016-08-18",
"company":"杭州分部"}
]
}
我们不难看出返回的json数据是一个json对象,里边有两个键:
1. total(记录总条数)
2. rows (记录内容) 这是一个json数组,数组的元素是json对象.
就是这样一种固定格式的 json 数据 grid 获取以后才能够正确解析,它会将rows中的对象的 key 和
datagrid中的columns 的字段field 的值进行匹配,生成 datagrid (数据表) 中的数据;
6. 下面我们谈谈 datagrid 中的一个很神奇的方法 load :
方法名 load 参数 param
官方API翻译: 加载和显示第一页行。如果指定的param”,它将取代与queryParams 的属性。通常一个查询通过一些参数,
这种方法可以调用从服务器加载新数据。
$('#dg').datagrid('load',{
code: '01',
name: 'name01'
});
个人理解:就是说你可以用你的 datagrid 对象调用 load 方法,如果没有传入 param参数 那么会发送ajax请求加载第一页数据
如果你调用 load 方法时传入了 param参数,那么它会作为请求参数传到服务器,从服务器加载页面,那么这个时候
这个param参数我们就可以大作文章了,因为我们可以通过控制这个param 传到服务器,控制服务器返回给我们想要的数据;