SSH框架整合截图总结(一)

分页相关属性

 

 

 

 

---------------------------------------------------------------

 

分页思路
表单提交(只需传递当前页的值) ->action

action 调用 service中的方法
action需要完成的操作就是把表单提交的currentPage(当前页的值)传递(调用action中注入的service对象的方法)给service
PageBean pageBean=customerService.listpage(currentPage);并且返回一个list集合 该集合保存的就是处理之后的分页记录集合

 

service 调用 dao中的方法进行pagebean的封装
[service需要根据currentPage的值,将来页面需要的所有信息 封装进PageBean对象中 当然有的属性值是需要通过已知的信息 调用dao中的方法得到,或者计算得到]

 

dao中就是编写 service在封装pagebean对象时 用到的方法

 查询总的记录数

根据已知信息,把用户需要的集合查出来,返回给service

 pagebean实体类

分页显示页面(因为使用了jstl表达式  所以在页面开头需要导入  <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>)

 1                                             <TBODY>
 2                                                 <TR
 3                                                     style="FONT-WEIGHT: bold; FONT-STYLE: normal; BACKGROUND-COLOR: #eeeeee; TEXT-DECORATION: none">
 4                                                     <TD>客户名称</TD>
 5                                                     <TD>客户级别</TD>
 6                                                     <TD>客户来源</TD>
 7                                                     <TD>电话</TD>
 8                                                     <TD>手机</TD>
 9                                                 </TR>
10                                                 <c:forEach items="${pageBean.list }" var="customer">
11                                                 <TR
12                                                     style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
13                                                     <TD>${customer.custName }</TD>
14                                                     <TD>${customer.custLevel }</TD>
15                                                     <TD>${customer.custSource }</TD>
16                                                     <TD>${customer.custPhone }</TD>
17                                                     <TD>${customer.custMobile }</TD>
18                                                 </TR>                
19                                                 </c:forEach>
20                                             </TBODY>

关于分页显示页面上一页和下一页的判断

 1                                                 共[<B>${pageBean.totalCount}</B>]条记录,共[<B>${pageBean.totalPage}</B>]页
 2                                                 ,当前第[<b>${pageBean.currentPage}</b>]页
 3                                                 <!-- 这里需要做一个判断  如果当前页是第一页 就不能再点击前一页了   如果当前页时最后一页  不在显示最后一页的超链接 -->
 4                                                 <c:if test="${pageBean.currentPage!=1}">
 5                                                     [<A href="${pageContext.request.contextPath}/customer_listpage.action?currentPage=${pageBean.currentPage-1}">前一页</A>]
 6                                                 </c:if>
 7                                                 
 8                                                 <c:if test="${pageBean.currentPage!=pageBean.totalPage}">
 9                                                     [<A href="${pageContext.request.contextPath}/customer_listpage.action?currentPage=${pageBean.currentPage+1}">后一页</A>] 
10                                                 </c:if>

 --------------------------------------------------------------------------------

jsp页面中

action中:

 

 

 -------------------------------------------------------------------------------------

 模型驱动  获取表单的值 ,表单中的name属性需要和实体类中的属性名称一样 提交之后 在action中就可以使用提交后的对象

------------------------------------------------------------------------------------------------------------

条件查询,在action中判断输入的内容是否为空,不为空 则调用条件查询的方法(action调用service service 调dao中的方法)  为空  就调用方法返回表中所有的记录

输入的内容不为空   调用方法演示:

    //条件查询  输入的内容不为空
    public List<Customer> findCondition(Customer customer) {
        // TODO Auto-generated method stub
        //第一种方式:
//        SessionFactory sessionFactory=this.getHibernateTemplate().getSessionFactory();//得到sessionfactory对象
//        Session session=sessionFactory.getCurrentSession();//得到session 这里的session对象和web阶段的HttpSession不是同一个概念
//        Query query=session.createQuery("from Customer where custName like ?");
//        query.setParameter(0,customer.getCustName());
//        List<Customer> list=query.list();
        
        
        //第二种方式: 单一条件查询的时候 这种比较简单  但是多条件查询的时候  使用第三中方式最简单
//        List<Customer> list=(List<Customer>) this.getHibernateTemplate().find("from Customer where custName like ?","%"+customer.getCustName()+"%");
        
        
        //第三种方式:
        //创建离线对象,表示对那个实体类进行操作
        DetachedCriteria criteria=DetachedCriteria.forClass(Customer.class);
        //设置对实体类中的那个属性进行条件查询   如果对多个字段进行条件查询 那么只需要调用add方法即可 
        criteria.add(Restrictions.like("custName","%"+customer.getCustName()+"%"));
        //调用模板中的方法  得到集合
        List<Customer> list=(List<Customer>) this.getHibernateTemplate().findByCriteria(criteria);
        return list;
    }    

 ---------------------------------------------------------------------------

对象关系映射配置 (客户和联系人)一对多配置 

客户实体类(一方)中添加set集合表示所有的联系人  联系人实体类(多方)中添加一个客户对象 表示所属的客户

基本配置首先完成  之后两个实体类相互表示 建立关系

建立关系基本结构:

一方映射配置(配置实体类中set属性):

多方映射配置(配置实体类中的一方的对象属性):

 

 

linkman

linkman.hbm.xml

customer

customer.hbm.xml

 

-------------------------------------------------------------------------------------

文件上传 

上传要求

action配置

执行上传时注意导入的包

上传操作的完整代码:

需要注意的问题:在上传的时候  struts中存在上传的默认大小  struts常量配置文件路径

上传常量值(默认)大小

 

 如果上传的文件超过了默认值 会报404错误

在struts.xml中修改默认上传值

这样就能够上传20M以下的文件了  当然没有根本解决上传时的问题  因为即使设定了默认值 但是永远存在上传的文件大于设定的默认值的情况

根本解决,就是设置一个input视图,提示用户不能上传规定大小之外的文件

这样就提高了系统的容错能力

--------------------------------------------------------

struts和Hibernate中的jar冲突

在做ssh整合的时候  注意,需要删掉重复的javassist.jar

-------------------------------------------------------------------

no-session问题

问题的出现:

表中存在外键

对应的实体类

运行页面:

 运行之后:页面能够正常显示外键和基本信息

如果现在页面显示的不是外键的名称,而是外键对应的类的记录中的其他信息

显示的页面

运行之后出现错误:

 造成错误的原因:

 

虽然现在使用的是hibernateTemplate 但是底层的实现机制还是通过sessiofactory对象先创建
sesssion对象,然后调用session中的方法进行操作,因为使用模板时,得到的是与本地线程线程绑定了session,所以当dao调用结束之后,创建的线程自然就结束了,即使不手动关闭,session也会自动关闭,这就造成了当再次查询数据库的时候,出现session关闭的情况,即造成了no-session异常
造成这种异常的根本原因是在session已经关闭的情况下 ,再次对数据库进行了操作linkman.customer.cusName
第一次查询的时候,之后查询出linkman的基本信息以及它所关联表的外键,并没有查询外键对应的表的信息
当在jsp页面执行该语句的时候,会根据第一次查询出的外键的信息查询customer表,查询该外键在customer表中对应的记录中的cusName字段,显示在页面,而此时的问题就是session已经关闭了

(1)no session解决:方式一(推荐使用)
- 让session操作之后不会马上关闭,在action操作之后进行关闭
- 封装实现方式:让session延迟关闭

(2)具体使用
封装过滤器,只需要配置封装的过滤器就可以了
配置到struts2过滤器前面

核心过滤器配置:

注意:配置的session延迟关闭的过滤器需要在struts核心过滤器之前

打开上边这个类,复制类的全路径到filter-class中

 运行之后 问题解决

过滤器的执行顺序与在web.xml中配置的代码顺序有关系
写在前边的代码会先执行 在解决no-session问题的时候,所配置的过滤器代码应该写在核心控制类过滤器FilterDispatcher之前

(1)no session解决:方式二

为什么第一次不把所有数据查出来呢?

因为Hibernate框架为了优化或者提高性能,使用了懒加载的机制,lazy="true" 默认的值为true 即在配置文件中不写的话  默认是

懒加载的方式(只查询基本数据,而包含的外键数据在真正使用的时候,才会重新查数据库,在一定情况下能够减少查询的次数,提高系统运行的效率,因为有的时候只需要得到基本的数据),那么问题就出现了,对于查询的数据包含外键,就是上面的情况,查询linkman表时,只查出了基本信息,而没有把外键所在的表customer中的数据一并查出来,而在真正使用的时候才重新开始查询数据库,而我们使用的hibernateTemplate模板底层使用的是与本地线程绑定的session,即在调用dao方法查询linkman表中基本数据之后,因为线程的关闭,而session自动也进行了关闭,所以这两个优化机制在一块时就容易发生问题。

解决方法:只需要在查询的目标对象的一方的映射配置文件中配置禁止懒加载 lazy="false"  保证在查该实体类对应的表的数据的时候,把基本数据,以及外键包含的数据一块查出来,就是禁用懒加载 (如果搞不清楚双方都配置懒加载也没问题)

 

使用该方式可能会增加不必要的查询语句,系统的性能可能会降低,但在本例中,这种查询是允许的,因为我们正好需要外键对应的数据来用于显示,如果只显示基本信息,那么就没有必要查了

----------------------------------------------------------------------------------------------------------

过滤器配置格式:

核心过滤器的作用

------------------------------------------------------------------------------

action操作过程:
访问action的路径进入action,然后调用方法执行功能,最后action中有返回的结果
根据返回的结果到达指定视图进行显示,进行显示之后,就称为action操作之后,这时action操作结束

 -------------

尽量不要过滤所有

-----------------------------------------------------------------------------------

jstl标签--循环与判断的使用

记得在文档开头引入该标签

不需要导入jstl.jar文件,myeclipse创建项目的时候已经默认提供了这个jar,并且已经加载进项目中了

-----------------------------------------------------------------------------------------------

struts.xml中配置重定向(表单提交,数据更新之后,根据返回值,再次调用action中的方法,检索数据,然后跳到页面)

 

在执行修改操作之后,为什么不直接返回到list.jsp页面呢,因为数据已经更新,所以需要重新加载数据一次,例如点击联系人列表的超链接时,数据是通过查询数据库,然后再到list.jsp页面 呈现数据

这样能够保证 修改之后返回到的视图中的数据都是最新的数据,因为重新查询了一次数据库  包括添加联系人成功之后也需要使用重定向再次访问action检索数据  然后返回list视图

就是第一个action操作完成之后,紧接着重定向另一个action中,重新检索数据,然后在返回到视图页面

方法二:

执行完CartAction中的add方法之后,返回值为Add,但是这是不是返回到某个页面(比如返回值为login时,根据配置的信息,跳到login.jsp页面),而是重新进入到某个action中执行指定的方法  这里的action就是ProductionAction  执行的是其中的list()方法  并且向该方法中传递了参数,名称为cid 值为1  在list方法中可以根据 request.getParameter(“cid”)来获取该值,执行完list方法之后,返回值为List  所以就跳到list.jsp页面

 

 

--------------------------------------------------------------------------------------------------

Inverse属性配置

先演示一个错误

原始配置:

即现在没有配置inverse属性的值,默认是false,即双方都不放弃表的维护工作,

联系人列表

客户列表:

进行如下操作:

把百度的名称修改为百度1

修改操作能够成功

看控制台的打印:

做了两次更新操作,而且还把修改的客户对应的联系人的外键字段 置为null

联系人列表

出现上述问题的原因:现在操作的是customer,没有为该映射配置文件设置inverse属性,默认的是双向维护机制[双向指的是customer和linkman都进行外键的维护工作,customer有能力修改自己,也有能力修改linkman,同样linkman也是如此],一方(customer)一方面修改自己的内容,另一方面还会对有关联的表进行维护,所以就造成了在修改完customer表数据的时候,还把有关联的外键字段设置为null

解决这个问题的方法,就是让customer方没有对linkman方的维护能力,customer只能修改自己,而不能干预别人。至于为什么要把外键的值置为null,这个问题有待研究??????????????????

双向维护机制造成的这种情况的发生  解决这个问题 就需要让某一方放弃表的维护工作,一般都是让一方放弃,所以在customer实体类的映射配置文件中声明inverse=“true”  它的默认值是false、

现在我们再次修改一条记录

修改之气前 联系人列表 以及客户列表

 

 

 修改之后 客户列表 和联系人列表

 

 

-------------------------------------------------------------

级联删除

1.先不配置级联删除 

(0)如果不配置cascade属性值时候,直接删除客户,默认效果

把联系人外键设置null,删除客户

2.配置级联删除 cascade="delete"  因为现在是删客户  所以在客户的映射配置文件中配置该属性

删除客户表的一条记录 对应这个客户的联系人表中的记录也被删除了

控制台打印

先把联系人表中对应的外键置为null(直接删 无法删除 存在外键约束),然后删除联系人  删除客户

 

但是如果这样配置  (表示客户放弃表的维护工作) 同时不配置级联删除

删除客户的时候 就会报错

原因:既然已经放弃维护表的工作,删除的时候自然只能删除自己的数据,而没有能力对其他表进行操作,同时删除的时候存在外键的约束(联系人表中的外键依赖于客户表的主键),所以就会出现异常,因为只有先把外键的值  置为null 才能够实现删除

解决办法:配置放弃维护的同时  也配置了级联删除

这时 就能够实现正常的删除 即两个表中的数据都被删除  虽然没有能力(因为放弃了维护工作)在删除之前把外键置为null  但是因为配置了级联删除操作(反正都要删除,那么就先把影响删除的外键所对应记录删掉吧) 因此,删除的时候就不需要先把外键置为null,再进行删除操作,而是先删除了联系人表中的记录,最后删除了客户表中的记录,避免了外键约束的问题

控制台打印:

------------------------------------

级联删除时需要注意

模型驱动封装来自前端的数据 

 

根据控制台打印我们可以知道,模型驱动中自动封装了oid uid state等字段 

 

按照道理来说orders中有oid主键,就能实现删除操作,但是直接调dao进行删除的时候(级联删除),级联操作不起作用,例如,配置casecade="delete"和不配置时 效果一样  都是把关联表中的约束字段置为null 然后把orders对象删除。

只有在根据orders中的主键查询一次该对象(返回查询到的对象A),然后删除该对象A,此时级联操作才起作用  (删除order对象,并且关联对象也被删除