欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《易道客》源码剖析之四:页面多次跳转的记忆 博客分类: 易道客 java易道客页面跳转开源框架 

程序员文章站 2024-03-14 23:36:05
...

一、介绍(测试请在3.0.1以上版本)

页面多次跳转之后,还能记忆原页面的状态,是本系统的一大特色。

 

我们以“我的客户”为例,进入客户列表,点击“查询”,弹出过滤条件窗口,在客户类别中选择“线索客户”,过滤后跳转到第3页。然后在列表中间选择一个客户,点击“详述”按钮,进入详述页面,再单击“联系人”右页签,进入该客户的联系人列表,修改一个联系人信息,再增加一个联系人信息。再次回到联系人列表,点击上方的“返回”按钮,返回到“客户列表”。经过了N多次的页面跳转后……

 

此时:你会发现,你仍然停留在第3页,看到的数据仍然是刚才过滤之后的“线索客户”,左侧的单按钮,仍然选中你刚才操作的哪个客户。

 

查看视频演示

 

二、实现原理

1B/S架构中,页面跳转之后,要想返回时还记忆起以前的状态,有两种方式,第一,将该页面中所有的状态数据放入session中,再返回该页面时取出恢复。第二,将状态数据放入表单一并提交至下一个页面,在下一页面返回时,再将这些状态数据提交回来,这样第一个页面也可以读到以前的状态数据并恢复。这种方式下,如果存在多次跳转,每一步跳转,都必须带着状态数据,合理的规划就显得十分重要。本系统采用的是第二种方式。

 

2、在系统中,将状态数据分为三类:查询条件,穿越条件和分页信息。

1)查询条件:如我的客户列表中,当前列表是经过哪些查询条件过滤而得到的,如客户类别、所属区域等,这些条件数据都需要记录下来。以SEARCH_为前缀来区分。

 

2)穿越条件:标识当前列表中选中的是第几条数据,记录的是该条数据的唯一ID。以RELATION_为前缀来区分。

 

3)分页信息:符合查询条件的数据可能有很多,会有很多页,分页信息就是记录下当前的页码信息。只有两个属性:SEARCH_EgecStart(当前页开始记录的编号,就是所有符合查询条件的记录中,当前页面从第几条开始显示)和SEARCH_EgecPerNum(每页显示的条数)

 

3、在一个列表页面中,左侧单选按钮的名称是以RELATION_开头的,在列表页跳转到其他页面时,按钮值直接作为穿越条件带入到下一页面。

 

4、两个机制来保证:requestType(请求类型)和mastKeep(必须保持)

1requestType标识跳转到一个新页面时,哪些状态数据被从请求参数中取出来作为新页面表单的隐藏域。它有五种类型的值:

Aall:取出所有:包含了穿越和查询(含分页信息)

Bre:只取穿越条件(含分页信息)

Cse:只取查询条件(含分页信息)

Dall_no:取出所有:包含了穿越和查询(注:不包含分页参数)

Ese_no:只取查询条件(注:不包含分页参数)

每到一个新页面时,就根据先用getParametergetAttribute中取得requestType的值,再根据requestType的值类型,取相对应的状态数据,将这些状态数据以隐藏域的方式,放在页面表单内,当该页面跳转时,再将这些隐藏域带到下一页面。每次跳转,requestType需要根据不同的需求情况,赋于不同的值。

 

2mastKeep是个字符串数组,代表这些名称的状态数据必须取出来,不受requestType值类型的限制。它通常用于从一个列表跳转别一个列表时,记录下前一个列表的穿越条件。例如:从我的客户详述联系人列表这个过程中,在跳转到联系人列表时,必须记录下当前选中客户的唯一IDRELATION_Client_id),但不必要记录当前选中联系人的唯一IDRELATION_LinkMan_id),因为当前选中联系人的ID是由联系人列表左侧的单选按钮来记录,如果再用隐藏域来记录,就会出现在一个表单内两个重复的元素名称。这种情况下,requestType是不能使用all,re,all_no三个值,因为它们都将列出以RELATION_开头的穿越条件,联系人IDRELATION_LinkMan_id)也将会被取出作为隐藏域,就会在页面表单内出现重复的元素名称(RELATION_LinkMan_id)。此时,可以将客户IDRELATION_Client_id)放mastKeep中,此处的requestType请求参数值用sese_no就可以了。

 

5、两个form表单

addCommon.jsplistCommon.jsp页面,每个页面都有两个form表单,名称分别是form1form2

 

1form1用于正常的数据请求,如:增加页面的提交、列表页面选中某记录时的修改。From1表单的requestType元素值(即该表单向下一页面提交时,requestType传什么值过去)是在展示页面之前的action中设置的。表单的隐藏域(状态数据)有哪些,是由上一页面传进来的requestType请求参数值决定的,根据值的不同,给表单加入不同的隐藏域。见上面对requestType值的解释。

 

2form2表单是个空的隐藏表单,表单元素requestType的值默认是all,在调用js方法form2Submit()提交表单时,会用传进来的参数动态改变它的值。表单的隐藏域(状态数据)是上一表单传过来的所有数据(查询条件、穿越条件、分页信息),不受上一表单传入requestType请求参数值的影响。该表单主要用于“返回”操作,或右页签按钮请求时。

 

三、源码跟踪分析

1、操作路径:

1)我的客户列表

2)查询类别为“线索客户”的客户

3)翻页至第3,选中一条数据“详述”查看

4)点击右页签“联系人”,进入联系人列表

5)选中一个联系人,并点击“修改”

6)提交修改结果

7)显示成功信息

8)返回联系人列表,点击上方“返回”按钮

9)返回客户列表,我们会发现,还是刚才的查询条件过滤出来的数据,还在第3页,左侧单选按钮还是选中刚才操作的那个客户。

 

2、跟踪分析

1)客户列表

A、调用MyClientActionexecute()方法,会出现客户列表。该方法中对“详述”按钮的配置代码:

new Button(1, "详述","buttonClick('view.action','all','view')","")

说明向详述页面跳转入,传入requestType的参数值为all

 

B、点击“查询”,客户类别选择“线索客户”,筛选。跳转到第三页,此时右键查看源代码。

form1表单中单选按钮的代码:

<input type="radio" name="RELATION_Client_id" value="402881e43bda139c013bda20deea003f">

 

表单最后有一条代码,它是记录查询条件的,即:客户类别为线索客户。

<input type="hidden" name="SEARCH_clientSortId" value="402880822d032eb6012d038278e70002"/>

 

2)点击“详述”进入详述页。

A、该页面右侧有三个页签,分别为:详述、联系人、历史。

在进入该页之前的action方法中(MyClientActionview方法),我们找到如下三行代码:

new Button(1, "详述", "form2Submit('view.action','all')",""),

new Button(1, "联系人", "form2Submit('listOne.action','all')",""),

new Button(1, "历史", "form2Submit('listFive.action','all')","")

这就是右页签的配置,第二行说明:点击联系人的,跳转到listOne.action,传入的requestType参数为all,form2表单提交跳转的。

 

B、右击查看源代码,发现form2代码如下:

<form action="" name="form2" style="display: none" method="post">
  <input type="hidden" name="requestType" value="all"/>   
  <input type="hidden" name="SEARCH_EgecStart" value="24"/>
  <input type="hidden" name="SEARCH_EgecPerNum" value="12"/>
  <input type="hidden" name="SEARCH_clientSortId" value="402880822d032eb6012d038278e70002"/>
  <input type="hidden" name="RELATION_Client_id" value="402881e43bda139c013bda20deea003f"/>
</form>

记录了分页信息中,开始位置第24条,也就是第三页,每显示12条,查询条件,和当前客户ID

 

3)点击“联系人”右页签,进入联系人列表.

A、在进入之前的actionMyClientActionlistOne方法)中,有如下代码

queryFere.setMastKeep(Constants.RELATION_+className+"_id");

表示将客户ID参数(RELATION_Client_id)加入到mastKeep列表中

 

new Button(1, "修改", "buttonClick('updateOne.action','all','update')","update_1"),

表示点击“修改”按钮时,向修改页面传入的requestType值为all,由form1表单提交完成。

 

B、右击查看源代码,发现form1表单最后几行代码如下:

<input type="hidden" name="SEARCH_EgecStart" value="24"/>
<input type="hidden" name="SEARCH_EgecPerNum" value="12"/>
<input type="hidden" name="SEARCH_clientSortId" value="402880822d032eb6012d038278e70002"/>
<input type="hidden" name="RELATION_Client_id" value="402881e43bda139c013bda20deea003f"/>

仍然带着客户列表的状态数据。

 

4)点击修改,进入联系人修改页面

A、在进入之前的actionMyClientActionupdateOne方法)中,有如下代码

voneFere.setTopButtons(

new Button(1, "确认", "formSubmit('updateOneDone.action','all')",""),

new Button(1, "返回","form2Submit('listOne.action','se')",""));

代表修改页面上的两个按钮:确认和返回。确认时,调用的form1提交的,传入下页面的requestType值为all。返回是调用form2提交的,传入的参数为se

 

B、右击查看源代码,发现form1表单最后几行代码如下:

<input type="hidden" name="SEARCH_EgecStart" value="24"/>
<input type="hidden" name="SEARCH_EgecPerNum" value="12"/>
<input type="hidden" name="SEARCH_clientSortId" value="402880822d032eb6012d038278e70002"/>
<input type="hidden" name="RELATION_LinkMan_id" value="402881e43bda139c013bda20df390069"/>
<input type="hidden" name="RELATION_Client_id" value="402881e43bda139c013bda20deea003f"/>

还带着客户列表的状态,只是多了一个穿越条件,就是联系人的ID值。

 

5)点击“确认”,弹出“修改成功”信息提醒页。

A、在处理提交的actionMyClientActionupdateOneDone方法)中,有如下代码

ActionContext.getContext().put("nextRequextType","se");

它是说明,在下一页面,也就是显示“修改成功”的信息提醒页面中,form表单的requestType元素值采用se,之所以之么做,是因为信息提醒页面展示3秒后,会返回到联系人列表页。联系人列表页面form1中不需要穿越条件,因为它本身有单选按钮,如果也出穿越条件,就会出现两个名称为RELATION_LinkMan_id的元素。而RELATION_Client_id是不会丢失的,因为它放在mastKeep列表中。

 

B、在住息提醒页有如下代码:

<input type="hidden" name="requestType" value="<s:property value="nextRequextType" default="se_no"/>"/>

表示向下个页面(联系人列表)传递的requestType值,是由action中提交过来的,即se

 

6)再次回到联系人列表

A、再次在actionMyClientActionlistOne方法)中查看,有如下代码

new Button(1, "返回","form2Submit('list.action','se_no')","")

表示返回客户列表时,调用的form2表单提交跳转的,传入的requestType参数为se_no

 

B、右击查看源代码,发现form1表单最后几行代码如下:

<input type="hidden" name="SEARCH_EgecStart" value="24"/>
<input type="hidden" name="SEARCH_EgecPerNum" value="12"/>
<input type="hidden" name="SEARCH_clientSortId" value="402880822d032eb6012d038278e70002"/>
<input type="hidden" name="RELATION_Client_id" value="402881e43bda139c013bda20deea003f"/>
</form>

发现上面代码丢弃了RELATION_LinkMan_id在隐藏域,而RELATION_Client_id仍在,是因为前一页面页面传来的requestType值是se,RELATION_Client_idaction中已经加入了mastKeep列有。

 

Form2的表单代码如下:

 <form action="" name="form2" style="display: none" method="post">
<input type="hidden" name="requestType" value="all"/> 
<input type="hidden" name="SEARCH_EgecStart" value="24"/>
<input type="hidden" name="SEARCH_EgecPerNum" value="12"/>
<input type="hidden" name="SEARCH_clientSortId" value="402880822d032eb6012d038278e70002"/>
<input type="hidden" name="RELATION_LinkMan_id" value="402881e43bda139c013bda20df390069"/>
<input type="hidden" name="RELATION_Client_id" value="402881e43bda139c013bda20deea003f"/>
</form>

From2因为是所有的,不受requestType限制,所以全部出来。在此时点击“返回”按钮到客户列表时,客户列表页面出form1表单,这些以RELATION_开头的穿越条件和分页信息都会丢失,因为这我传过去的requestType参数将为se_no注:form2Submit()这个js方法改变requestTyper元素的值)。之所以传这个参数,是因为在客户列表的form1表单中,有单选按钮(名称为RELATION_Client_id)和分页信息,只需要将查询条件作隐藏域即可。

 

7)点击返回到客户列表,可以看到还是以前的查询条件,记录数还是过滤后的条数,单选按钮还停留在之前选中的客户上。

 

四、相关的类

1ShowUtil.java 显示工具类,被jsp调用,输入隐藏域。

2Constants.java 里面定义了几个相关的常量。

3addCommon.jsplistCommon.jsp

4)各个action

 

 

返回《易道客》主页