《易道客》源码剖析之四:页面多次跳转的记忆

一、介绍(测试请在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

 

 

返回《易道客》主页

 

 

 

你可能感兴趣的:(java,框架,开源,页面跳转,易道客)