关于spring整合前两大框架的一些小问题04
关于spring中对延迟关闭session的配置,以及工具类BaseDao和BaseAction
一、HibernateTemplate执行查询时的一些小问题
1.当两个PO类的关系是多对一时:
我们知道在多对一关系中,查询总是会先查询“一”的一方,而一的一方中是含有集合的,一谈到集合就不得不考虑关于hibernate中集合的加载策略,
集合的加载策略默认是懒加载的,我们可以自己手动的去配guanlu置这个加载策略!
然而我们这里讨论的是:当查询“一”的一方的数据完毕时session就会被关闭,而集合中的数据并没有加载所以在页面想获取时是获取不到的,我们想要懒加载能加载到数据,所以必须要延迟关闭session这样才能保证能查询到数据!
而这里我们想要延迟关闭session应该怎么做呢?spring提供了一个过滤器OpenSessionInViewFilter,只要请求还没有结束就不会关闭session
在web.xml中配置这样一个过滤器
<!-- 延迟关闭session的过滤器 ,这个过滤器是由spring提供的 需要在struts过滤器之前执行才可以这样一来session就是由我们这个过滤器创建的,到时候关闭也是由过滤器延迟关闭-->
<filter>
<filter-name>openSession</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter> <filter-mapping>
<filter-name>openSession</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
二、关于工具类BaseDao的思想与编写!
1.根据项目代码可知,我们在Dao层操作的代码很多都是重复性很大的代码,而人对于重复性的东西是能简化就简化的,例如增删改查基本上在每个Dao中的相似性极高,我们就可以将重复性的代码抽取出来,将其写成一个工具类,然后以后的Dao只需要去继承这个类即可,不需要再去写一些重复性的代码!
2.思想的构图如下:
在这里我们要附带介绍一下this关键字
this是指当前运行时类的对象,不是指当前对象,注意 观察下面代码的结果
public class Parent {
public void init(){
System.out.println("我是Parent的init 1");
this.demo();
} public void demo(){
System.out.println("我是Parent 的 demo 2");
}
}
public class Child extends Parent {
@Test
public void fun(){
init();
}
//研究发现this关键字,是指的运行时类的对象
public void init(){
super.init();
System.out.println("我是Child的 init 3");
this.demo();
}
public void demo(){
System.out.println("我是Child的demo 4");
}
}
运行后的结果为:
我是Child的 init 1
我是Child的 init 4
我是Child的 init 3
我是Child的 init 4
所以this指的是当前运行时类的对象
3.如图我们所考虑的是泛型里面将会是什么类型,我们如何得到这个类型来编写HQL语句?这个是我们所要考虑的!
解决办法:① 我们不知道泛型将会是什么类型可以将BaseDao定义为泛型类用变量T来表示泛型的类型 ②我们在BaseDao的实现类中BaseDaoImpl里面的无参构造里面加上这样的代码,当Spring的IOC创建Dao层的实例时这个构造就会被调用:(下面是代码片段)
//用来表示当前运行时类的泛型的类型
private Class<?> beanClass;
//TODO BaseDaoImpl的编写
public BaseDaoImpl() {
//得到被参数化的类型实例
ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass();//得到运行时类的泛型类型
//得到泛型的实际类型,而且这里的泛型只有一个。
beanClass =(Class<?>) parameterizedType.getActualTypeArguments()[0];
}
ParameterizedType这个类用来得到被参数化的类型的实例,然后调用该类的getActualTypeArguments()得到Type[]类型的数组,因为是由泛型的类型转换过来的所以我们可以放心强转为Class类型
Class类型是Type类型的子类 然后这个工具类的编写步骤和代码如下:
①创建一个接口为BaseDao(面向接口编程),在里面定义好所有常用的抽象方法,如,查询所有,根据OID查询,条件查询,条件查询的分页版,根据OID删除,添加方法、修改方法等
②创建实现类BaseDaoImpl,实现类只用去实现接口的所有方法即可。由上图可知我们每一个Dao都需要继承HibernateDaoSupport,所以我们继承这个类,到时候其他Dao只需要继承本实现类即可
③编写正常的Dao接口,这个接口为了得到BaseDao接口里面的方法和最后调用BaseDaoImpl所以必须继承这个接口得到里面所有的抽象方法
④编写正常Dao接口的实现类,由接口中已经继承了HibernateDaoSupport类所以我们只需要继承这个类即可使用所有的方法,这样使代码得到重用! BaseDao<T>接口代码如下:
public interface BaseDao<T> { //保存用户
public void save(T t);
//删除指定用户
public void delete(T t);
//保存或更新
public void saveOrUpdate(T t);
//查询所有
public List<T> findAll();
//根据Id查询指定数据
public T findById(Serializable id);
//单纯的条件查询
public List<T> findAll(String condition, Object[] params);
//带分页的条件查询
public int getTotalRecord(String condition,Object[] params);
public List<T> findAll(String condition, Object[] params, int startIndex,
int pageSize); //离线条件查询查询,可以可以参考hibernate笔记。
public List<T> findAll(DetachedCriteria criteria); //离线查询的分页版本
public List<T> findAll(DetachedCriteria criteria, int startIndex,int pageSize); }
BaseDao接口
BaseDaoImpl<T>实现类代码如下:
public class BaseDaoImpl<T>extends HibernateDaoSupport implements BaseDao<T> {
//用来表示当前运行时类的泛型的类型
private Class<?> beanClass;
//TODO BaseDaoImpl的编写
public BaseDaoImpl() {
//得到被参数化的类型实例
ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass();//得到运行时类的泛型类型
//得到泛型的实际类型,而且这里的泛型只有一个。
beanClass =(Class<?>) parameterizedType.getActualTypeArguments()[0];
}
//保存用户
public void save(T t) {
this.getHibernateTemplate().save(t); }
//删除指定用户
public void delete(T t) {
this.getHibernateTemplate().delete(t); }
//保存或更新,如果含有OID标识则会进行更新,如果没有OID标识那么就进行保存
public void saveOrUpdate(T t) {
this.getHibernateTemplate().saveOrUpdate(t); } public T findById(Serializable id) {
// TODO Auto-generated method stub
return (T) this.getHibernateTemplate().get(beanClass,id);
} //查询所有初级版
public List<T> findAll() { //getName()得到的是全限定类名,在hql里面指定全限定类名才是最完整的写法
return this.getHibernateTemplate().find("from "+beanClass.getName());
} //查询所有中级版之条件查询
public List<T> findAll(String condition, Object[] params) {
String hql="from "+beanClass.getName()+" where 1=1"+condition;
// TODO Auto-generated method stub
return this.getHibernateTemplate().find(hql, params);
} //关于分页的方法
public int getTotalRecord(String condition,Object[] params) {
//通过hql语句的条件查询的之聚合函数查询
List<Long> count =this.getHibernateTemplate().find("select count(c) from "+beanClass.getName()+" c where 1=1"+condition,params); return count.get(0).intValue();
} ////查询所有终级版之条件查询
public List<T> findAll(String condition, Object[] params, int startIndex,
int pageSize) {
String hql="from "+beanClass.getName()+" where 1=1 " +condition;
//也可以直接使用QBC查询方式里面提供了分页的API但是HQL查询没有实现分页API我们需要自己去完善
//执行execute()方法需要在里面传递一个回调对象,我们可以直接去实现接口实现回调接口
List<T> list=this.getHibernateTemplate().execute(new MyHibernateCallback<T>().setHql(hql).setParams(params).setStartIndex(startIndex).setPageSize(pageSize));
return list; }
//离线条件查询
public List<T> findAll(DetachedCriteria criteria) { return this.getHibernateTemplate().findByCriteria(criteria);
}
//离线条件查询的分页版
public List<T> findAll(DetachedCriteria criteria, int startIndex,
int pageSize) {
// TODO Auto-generated method stub
return this.getHibernateTemplate().findByCriteria(criteria, startIndex, pageSize);
} }
BaseDaoImpl实现
StaffDao接口如下:
public interface StaffDao extends BaseDao<CrmStaff> {
public CrmStaff find(String loginName,String loginPwd);
/* 继承工具接口BaseDao的到接口中所有的抽象方法
* public List<CrmStaff> findAll();
public CrmStaff findById(String staffId);*/
/*public CrmStaff updateStaff(String staffId);*/
}
StaffDao
StaffDaoImpl实现如下:
public class StaffDaoImpl extends BaseDaoImpl<CrmStaff> implements StaffDao { //这个longin是我们保留下来的独有的方法,其他方法在BaseDaoImpl中已经写好了
public CrmStaff find(String loginName, String loginPwd) {
//HibernateTemplate和Session一样所以可以使用HQL语句查询
List<CrmStaff> list=this.getHibernateTemplate().find("from CrmStaff where loginName=? and loginPwd=?", loginName,loginPwd);
if(list.size()==1){
return list.get(0);
}
return null;
} /* public CrmStaff updateStaff(String staffId) {
// TODO Auto-generated method stub
return this.getHibernateTemplate().get(CrmStaff.class, staffId);
}*/ /*我们已经写好了工具类只需要继承就可以实现重复的Dao层代码
* public List<CrmStaff> findAll() {
return this.getHibernateTemplate().find("from CrmStaff");
} //编辑前的查询操作,通过Id查询,还有修改时先根据Id查询到持久态的对象再进行修改
public CrmStaff findById(String staffId){
//使用get方法得到对象
return this.getHibernateTemplate().get(CrmStaff.class, staffId); }*/ }
StaffDaoImpl
三、BaseAction工具类的编写细节
1.在动作类中有许多重复的东西,例如:需要依赖Service层、需要继承ActionSupport类、需要实现模型驱动,还有常用的方法 push、set、put、session域的获得等都是重复的需要写的东西,我们可以写一个工具类来简化这些代码!
2.编写的思想和BaseDao一样,所以思考的地方还是泛型如何获得,如何编写如何创建模型驱动所需要的实例,我们比BaseDao多需要一个东西,那就是反射使用newInstance来创建模型驱动需要的实例。代码如下:
public class BaseAction<T> extends ActionSupport implements ModelDriven<T> { private T t; public T getModel() {
return this.t;
}
public BaseAction() {
try {
//(得到运行时类的泛型)得到被参数化的类型
ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass();
Class<?>clazz=(Class<?>) parameterizedType.getActualTypeArguments()[0];
this.t=(T) clazz.newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
/*
* 常用的一些方法的简写:
* 压栈方法push
* set方法
* put方法
* 放到会话Session中
* 放到Application中
*/ public void push(Object o){
ActionContext.getContext().getValueStack().push(o);
} //将对象包装成Map放到栈顶,如果栈顶就是一个Map那么直接将数据放进去,取的key就能取到对象
public void set(String key,Object o){
ActionContext.getContext().getValueStack().set(key, o);
}
//将对象放到ActionContext中
public void put(String key,Object value){
ActionContext.getContext().put(key, value); }
//将对象信息放到session域中(放到session域中的方式有两种,一个是直接put进值栈,一个是得到HttpSession对象调用setAttribute放入进去)
//这个是直接put进去的
public void putSession(String key,Object value){
/*HttpSession session=ServletActionContext.getRequest().getSession();
session.setAttribute(key, value);*/
ActionContext.getContext().getSession().put(key, value); }
//将对象信息放到application域中(放到application域中的方式有两种,一个是直接put进值栈,一个是得到ServletContext对象调用setAttribute放入进去)
public void putApplication(String key,Object value){
/*ServletContext application = ServletActionContext.getServletContext();
application.setAttribute(key, value);*/
ActionContext.getContext().getApplication().put(key, value);
}
/***********************上面都是公共的东西,下面由spring注入实例来使用*********************************/
//spring注入service是默认为单例的,只要不是修改的成员变量则不会出现并发访问问题,这里我们调用的全是方法所以不会出现并发访问问题
//员工的service
private StaffService staffService;
//如果你导入了插件包以后你这个setter方法的名称与spring是id名称对应时就会自动注入
public void setStaffService(StaffService staffService) {
this.staffService = staffService; }
//职位的service
private PostService postService;
public void setPostService(PostService postService) {
this.postService = postService;
}
//部门的service
private DepService depService;
public void setDepService(DepService depService) {
this.depService = depService;
}
//课程类别的service
private CourseTypeService courseTypeService;
public void setCourseTypeService(CourseTypeService courseTypeService) {
this.courseTypeService = courseTypeService;
}
//班级的service
private ClassesService classesService;
public void setClassesService(ClassesService classesService) {
this.classesService = classesService;
} //注意当进程这个工具类时为了让子类得到由spring创建的service实例(1.安装了整合插件2.名字和spring service类 id名称相同。那么就会自动注入)
//我们需要提供get方法
public StaffService getStaffService() {
return staffService;
}
public PostService getPostService() {
return postService;
}
public DepService getDepService() {
return depService;
}
public CourseTypeService getCourseTypeService() {
return courseTypeService;
}
public ClassesService getClassesService() {
return classesService;
} }
BaseAction
然后想要编写Action类时就只需要继承BaseAction即可,所有的东西已经写进去,而且当服务器接收一个请求,就会创建一个Action的实例所以BaseAction的构造方法也会被初始化进去!
继承BaseAction代码如下:可以看到我们将从前复杂的代码进行了简化,而且编写通用的模型驱动,每个Action所单独的Service
//继承BaseAction进行改造
public class StaffAction extends BaseAction<CrmStaff> {
/*private StaffService staffService;
//如果你导入了插件包以后你这个setter方法的名称与spring是id名称对应时就会自动注入
public void setStaffService(StaffService staffService) {
this.staffService = staffService; }*/ //使用模型驱动必须自己创建对象容器然后等着表单传递过来然后封装到模型驱动中,前提是你要继承ActionSupport
/*private CrmStaff crmStaff = new CrmStaff();
public CrmStaff getModel() { return crmStaff;
}*/ /***********登录验证*************/
public String login() throws Exception {
// 登录验证
//CrmStaff sqlCrmStaff=staffService.login(crmStaff);
//改造后
CrmStaff sqlCrmStaff=getStaffService().login(this.getModel());
//如果返回值不为null则保存session
if(sqlCrmStaff!=null){
/*HttpSession session=ServletActionContext.getRequest().getSession();
session.setAttribute("sqlsqlCrmStaff", sqlCrmStaff);*/
//改造后,装进session域中
putSession("sqlsqlCrmStaff", sqlCrmStaff); return SUCCESS;
} //如果为null则保存错误信息,this.addFieldError("", "*用户名或密码错误!");没有指定错误字段的位置
this.addFieldError("", "用户名或密码错误!");
//请求转发显示到登录页面
return "login";
} public String home(){
return "home"; } /***********查询所有员工*************/
public String findAll() throws Exception {
// 1.查询所有员工
/*List<CrmStaff> crmStaffs=staffService.findAllStaff();*/
//改造后
List<CrmStaff> crmStaffs=getStaffService().findAllStaff(); /****************************************************************/
// 2 将结果存放到值栈,方便jsp获得数据
// * 方式1:context (map)存放 put(key ,value) ,jsp页面获得 “#key” 。
// ActionContext.getContext().put(key, value)
// * 方式2:root (值栈) ,push(obj) ,一般数据为JavaBean 或 Map ,jsp页面获得“属性名” 或“key” 。
// ActionContext.getContext().getValueStack().push(o)
// * 方式3:root (值栈) ,set(key ,value) ,一般数据为List ,jsp页面获得“key”
// set() 底层 new Map(key,value) ,将 push(map )
/****************************************************************/
/* ActionContext.getContext().put("crmStaffs", crmStaffs); */
//改造后
put("crmStaffs", crmStaffs);
return "findAll";
} /***********编辑前的回显工作*************/
//已经在工具BaseAction中定义,当我们继承时方法已经到这个类里面来了,只是我们看不到
/*private DepService depService;
public void setDepService(DepService depService) {
this.depService = depService;
}*/
public String findPreEdit(){ //1.得到请求传来的参数
/*CrmStaff oneStaff= staffService.findPreEidt(crmStaff.getStaffId());*/
//改造后
CrmStaff oneStaff= getStaffService().findPreEidt(this.getModel().getStaffId()); //2.将得到的对象压入栈顶
ActionContext.getContext().getValueStack().push(oneStaff);
//改造后
push(oneStaff); //3.得到所有的部门然后ValueStack的set方法set进值栈中
//查询所有部门有问题,需要解决 /*List<CrmDepartment> allDep = depService.findAllDep();*/
//改造后
List<CrmDepartment> allDep = getDepService().findAllDep(); /*ActionContext.getContext().getValueStack().set("allDep",allDep);*/
//改造后
set("allDep",allDep); return "findPreEdit";
}
/**********保存编辑内容****************/
public String edit(){
//保存所有的传过来的信息
/*staffService.updateStaff(crmStaff);*/
//改造后
getStaffService().updateStaff(this.getModel()); return "edit";
} }
BaserAction
可以多看看细细品味!!!
关于spring整合前两大框架的一些小问题04的更多相关文章
- spring整合quartz时间任务调度框架
spring整合quartz框架 1.创建maven工程 2.导入jar包(pom.xml) <dependencies> <dependency> <groupId&g ...
- Spring整合SpringMVC + Mybatis基础框架的配置文件
目录 前言 1. Mybatis层编写 2. Spring层编写 1. Spring整合Mybatis 2. Spring整合service 3. SpringMVC层编写 1. 编写web.xml ...
- Spring系列之——Spring事务以及两大核心IOC和AOP
1 Spring事务 1.1 Spring事务是什么(百度) 事务是对一系列的数据库操作(比如插入多条数据)进行统一的提交或是回滚操作,如果插入成功,那么一起成功,如果中间一条出现异常,那么回滚之前的 ...
- 算法---数组总结篇2——找丢失的数,找最大最小,前k大,第k小的数
一.如何找出数组中丢失的数 题目描述:给定一个由n-1个整数组成的未排序的数组序列,其原始都是1到n中的不同的整数,请写出一个寻找数组序列中缺失整数的线性时间算法 方法1:累加求和 时间复杂度是O(N ...
- Java Web J2EE下的两大框架SSH和SSM对比
当下流行的两种企业开发MVC开源框架,是我们Java程序猿必备知识能力.MVC,即模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界 ...
- 前端两大框架 vue 和 react 的区别
1. 设计思想 vue: vue的官网介绍说vue是一种渐进式框架,采用自底向上增量开发的设计: react: 采用函数式编程,推崇纯组件,数据不可变,单向数据流: 2. 编写语法 vue: 采用单文 ...
- spring基础:什么是框架,框架优势,spring优势,耦合内聚,什么是Ioc,IOC配置,set注入,第三方资源配置,综合案例spring整合mybatis实现
知识点梳理 课堂讲义 1)Spring简介 1.1)什么是框架 源自于建筑学,隶属土木工程,后发展到软件工程领域 软件工程中框架的特点: 经过验证 具有一定功能 半成品 1.2)框架的优势 提高开发效 ...
- Java 学习笔记 两大集合框架Map和Collection
两大框架图解 Collection接口 由第一张图,我们可以知道,Collection接口的子接口有三种,分别是List接口,Set接口和Queue接口 List接口 允许有重复的元素,元素按照添加的 ...
- Flask框架简介,常用扩展包及两大核心
Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架. Flask 本身相当于一个内核,其他几乎所有的功能都 ...
随机推荐
- JMeter接口测试响应数据中乱码问题解决方法
乱码产生原因: 结果处理编码与被测对象的编码不一致,JMeter是默认按照ISO-8859-1编码格式进行解析. 解决方法一: 根据接口文档或者找开发确认项目编码是哪种,因为有的项目用的是GBK,有的 ...
- 分享下超实用的用skura frp做内网穿透的经验
操作目的: 使无公网ip的主机能被外网访问,实现ssh对服务器的远程管理 硬件准备: 1.服务端:skura frp主机(skura frp 免费提供,有待创建) 2.客户端:接在无线路由器(内网)上 ...
- Python学习小记(2)---[list, iterator, and, or, zip, dict.keys]
1.List行为 可以用 alist[:] 相当于 alist.copy() ,可以创建一个 alist 的 shallo copy,但是直接对 alist[:] 操作却会直接操作 alist 对象 ...
- Magicodes.IE基础教程之导出Pdf
原文作者:hueifeng 说明 本教程主要说明如何使用Magicodes.IE.Pdf完成Pdf收据导出 要点 导出PDF数据 自定义PDF模板 导出单据 如何批量导出单据 导出特性说明 PdfEx ...
- 解决本地请求不到json问题,老是出现跨域
有时候我们需要在本地模拟请求json数据,但是老是出现谷歌跨域的问题, 网上找了方法,说是把json和HTML文件放在同一目录,还有的是页面引用时加上callback的. 但是不知道咋的,可能是本人不 ...
- mybatis 配置--->确认jar包是否正确
mybatis 配置之前,首先要确保服务器jar包是否成功 配置jar包如下添加mybaties-3.5.2. jar, maven 的 pom.xml 配置如下,查看配置是否成功见 如上分类 Mav ...
- CF547E Mike and Friends [AC自动机,离线树状数组]
#include <cstdio> #include <queue> #include <vector> #define pb emplace_back using ...
- nodejs 使用 body-parser 获取网页内容
var bodyParser = require('body-parser'); var urlencodedParser = bodyParser.urlencoded({ extended: fa ...
- Java设计模式之Iterator
public interface Aggregate { //调用iterator方法生成实现Iterator接口的类的实例 public abstract Iterator iterator(); ...
- 剑指offer-面试题50-第一个只出现一次的字符-哈希表
/* 题目: 求字符串第一个只出现一次的字符. */ /* 思路: 使用map遍历两次,第一次计数,第二次找到计数为1的第一个字符. */ #include<iostream> #incl ...