一、移动、复制页的逻辑实现

移动、复制页的功能是在设计调查页面的时候需要实现的功能。规则是如果在同一个调查中的话就是移动,如果是在不同调查中的就是复制。

无论是移动还是复制,都需要注意一个问题,那就是页面在一个调查中的位置问题,这就需要一个变量来标识该该页面在一个调查中的位置。我们在Page对象中添加一个成员变量orderNo,该变量是float类型的变量,默认值和pageId相同,在设置pageId的同时设置好orderNo,我们使用该变量来对一个调查中的所有页面进行排序。

移动、复制页的流程就是:

在设计调查页面中的页面上给出一个超链接:”移动、复制页“->Action查找到所有的Survey并将所有Survey中的所有页面显示出来,用户选择在页面之前还是之后并提交->Action根据原页面和目标页面进行判断是需要进行移动页面还是复制页面,并调用相应的方法进行移动、复制页->重定向到设计调查页面上。

1.移动页面的实现分析

移动页面的实现相对来说要简单很多。首先,移动页面一定是在同一个调查中,所以我们只需要将原页面的orderNo进行相应的更改即可,更改之后重定向到设计调查页面上查看更改是否生效。

2.复制页面的实现分析

复制页面相对移动页面来说要复杂的多,首先复制页面不是在同一个调查中,而且需要将原来的页面进行拷贝,Page对象中有几个成员变量,特别是questions成员变量更应该着重考虑。复制页面非常容易被误导成变量的引用复制,实际上不是这样,所谓复制就是将原来的对象原原本本的拷贝一份,即使原来的对象不存在了,拷贝的那份对象也能够毫无影响的继续运作。

这里借助串行化技术实现对对象的深度复制。串行化使用到的技术主要是对象流和内存流。对象序列化之后写入内存,让后再从内存中取出来形成新的对象。这样就完成了对对象的深度复制。实现深度复制的代码如下:

 //实现深度复制的方法
//在实现深度复制之前必须修改Bean类中的相关字段,
//比如Page类中的pageId必须加上transient修饰,还有Question类中的questionId字段也必须加上transient修饰
private Serializable copyPage(Page oldPage) {
oldPage.getQuestions().size();
try {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(oldPage);
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bais);
Serializable serializable=(Serializable) ois.readObject();
return serializable;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}

实现深度复制需要注意几点:

  (1).在进行深度复制之前,必须解决懒加载可能出现的异常。以上的代码中,接收了一个Page对象,首先调用了该对象的getQuestions().size();这么做是为了防止出现懒加载异常的情况。如果不这么做的话会出现什么情况呢?在复制该对象之前,由于Page对象的questions成员变量默认启用了懒加载策略。所以并不会到数据库中查询Question对象填充questions成员变量。这样一来深度复制之后的Page对象中的questions对象就没有实际的值。一旦调用该成员变量就会出现懒加载异常。

  (2).深度复制之前必须修改Bean中的定义。将Page类中的pageId使用transient关键字修饰,同样,也需要对Question类中的questionId使用transient关键字修饰。transient关键的作用就是在串行化对象的时候忽略该字段。这样得到的深度复制后的页面对象中的相应字段就是null。比如Page对象,它的pageId为NULL,同时该对象中的所有questions列表中的Question对象中的questionId也是NULL。因为需要重新保存到数据库,如果不这么做就会报错,因为无论是Page对象还是Question对象都是主键自动增长的。当然我们能够手动设置pageId和questionId为NULL,但是并不管用,原因未明,所以直接使用transient关键字对其进行修饰是最最快最省事的方法。

3.orderNo的设置问题。

  我在这里设置orderNo值越小,排名越靠前,反之排名越靠后。

  如果是需要放到第一页的前面,则将目标也的orderNo的值设置为比第一页的orderNo小0.01,如果放置到最后一页的后面,则设置目标页的orderNo的值为最后一页的orderNo大0.01,其他情况下使用两者的平均值。 

  所有的orderNo的值都保留两位小数点。

因为需要知道页面中的最大页码和最小页码,所以在PageService中就需要提供两个方法判断获取最大值和最小值的方法。

     @Override
public boolean isLastPage(Page page) {
String hql="from Page where survey.surveyId=? order by orderNo desc";
List<Page>pages=this.pageDao.findEntitysByHQL(hql,page.getSurvey().getSurveyId());
return pages.get(0).getPageId()==page.getPageId();
}
@Override
public boolean isFirstPage(Page page) {
String hql="from Page where survey.surveyId=? order by orderNo asc";
List<Page>pages=this.pageDao.findEntitysByHQL(hql,page.getSurvey().getSurveyId());
return pages.get(0).getPageId()==page.getPageId();
}

4.实现移动页的代码

 /**
* 移动的规则就是:
* 如果是最前面的页面,则将页面的orderNo设置为第一个页面的orderNo-0.01,
* 如果是最后面的一个页面,则将页面的orderNo设置为最后一个页面的orderN+0.01,
* 如果是中间的一个页面,则使用两边orderNo的平均值
*
* @param position
* @param oldPage
* @param newPage
*/
private void doMovePage(String position, Page oldPage, Page newPage) {
//第一种情况是position是0,代表是放到目标页的前面
if("0".equals(position)){
//如果是放到目标页的前面的话,需要考虑目标页是不是第一页的情况
if(isFirstPage(newPage)){
//是第一页的话使用第一页的orderNo-0.01
oldPage.setOrderNo(newPage.getOrderNo()-0.01F);
}else{
//否则的话取平均值
oldPage.setOrderNo((this.getPrePage(newPage).getOrderNo()+newPage.getOrderNo())/2);
}
}else if("1".equals(position)){//第二种情况是position是1,带包是放到目标页的后面
//如果是放到目标页的后面,需要考虑目标页是不是最后一页的情况
if(isLastPage(newPage)){
oldPage.setOrderNo(newPage.getOrderNo()+0.01F);
}else{
//否则的话取平均值
oldPage.setOrderNo((this.getNextPage(newPage).getOrderNo()+newPage.getOrderNo())/2);
}
}
pageService.updatePage(oldPage);
}

5.实现复制页的代码:

 //不同页面之间使用页面复制,深度复制
private void doCopyPage(String position, Page oldPage, Page newPage) {
Page copyPage=(Page) this.copyPage(oldPage);
//第一种情况是position是0,代表是放到目标页的前面
if("0".equals(position)){
//如果是放到目标页的前面的话,需要考虑目标页是不是第一页的情况
if(isFirstPage(newPage)){
//是第一页的话使用第一页的orderNo-0.01
copyPage.setOrderNo(newPage.getOrderNo()-0.01F);
}else{
//否则的话取平均值
copyPage.setOrderNo((this.getPrePage(newPage).getOrderNo()+newPage.getOrderNo())/2);
}
}else if("1".equals(position)){//第二种情况是position是1,带包是放到目标页的后面
//如果是放到目标页的后面,需要考虑目标页是不是最后一页的情况
if(isLastPage(newPage)){
copyPage.setOrderNo(newPage.getOrderNo()+0.01F);
}else{
//否则的话取平均值
copyPage.setOrderNo((this.getNextPage(newPage).getOrderNo()+newPage.getOrderNo())/2);
}
}
float temp=copyPage.getOrderNo();
copyPage.setSurvey(newPage.getSurvey());
pageService.addNewPage(copyPage);
copyPage.setOrderNo(temp);
pageService.updatePage(copyPage);
for(Question question:copyPage.getQuestions()){
questionService.saveQuestion(question);
}
}
//实现深度复制的方法
//在实现深度复制之前必须修改Bean类中的相关字段,
//比如Page类中的pageId必须加上transient修饰,还有Question类中的questionId字段也必须加上transient修饰
private Serializable copyPage(Page oldPage) {
oldPage.getQuestions().size();
try {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(oldPage);
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bais);
Serializable serializable=(Serializable) ois.readObject();
return serializable;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}

之前曾经在Survey对象中添加了量个字段,minOrderno和maxOrderno,这两个字段和现在的问题完全没有关系,但是在之后的参与调查中的导航功能有密切的关系。

二、移动页的实现演示

在第一个调查中移动有四页,而且页面都按照顺序进行了排序。现在想要将第一页移动到第三页和第四页之间。

  首先,单击第一页旁边的”移动、复制页“超链接,跳转到选择位置的界面上去,该界面显示了所有的调查中的所有的页面。而且原页面使用了重色标注出来了。

我们单击第三页的”之后“单选按钮,然后点击之后的确定,直接跳转到设计调查页面上去了,同时我们发现,第一页真的到了第三页和第四页之间,同时第一页原来的位置被第二页所取代。

其实想要实现这个效果有两种方式可以是西安,第一种是放到放到第三页之后,第二种是放到第四页之前,这里选择一种即可。

三、复制页的实现演示

现在我一共创建了6个调查,其中第一个调查设计的最多,有四页的问题。我给第二个调查添加几个页面并添加几个问题如下图所示:

现在我想将第一个调查中的标题为“第一页”的页面复制到第二个调查中的第二页和第三页之间

步骤如下,单击第一个调查的标题为“第一页”的页面中的“复制、移动页”超链接。

然后单击确定按钮,发现跳转到了调查二,同时原页面已经被复制到了指定的位置。

【Java EE 学习 72 下】【数据采集系统第四天】【移动/复制页分析】【使用串行化技术实现深度复制】的更多相关文章

  1. 【Java EE 学习 69 下】【数据采集系统第一天】【实体类分析和Base类书写】

    之前SSH框架已经搭建完毕,现在进行实体类的分析和Base类的书写.Base类是抽象类,专门用于继承. 一.实体类关系分析 既然是数据采集系统,首先调查实体(Survey)是一定要有的,一个调查有多个 ...

  2. 【Java EE 学习 74 下】【数据采集系统第六天】【使用Jfreechart的统计图实现】【将JFreechart整合到项目中】

    之前说了JFreechart的基本使用方法,包括生成饼图.柱状统计图和折线统计图的方法.现在需要将其整合到数据采集系统中根据调查结果生成三种不同的统计图. 一.统计模型的分析和设计 实现统计图显示的流 ...

  3. 【Java EE 学习 70 下】【数据采集系统第二天】【Action中User注入】【设计调查页面】【Action中模型赋值问题】【编辑调查】

    一.Action中User注入问题 Action中可能会经常用到已经登陆的User对象,如果每次都从Session中拿会显得非常繁琐.可以想一种方法,当Action想要获取User对象的时候直接使用, ...

  4. 【Java EE 学习 67 下】【OA项目练习】【SSH整合JBPM工作流】【JBPM项目实战】

    一.SSH整合JBPM JBPM基础见http://www.cnblogs.com/kuangdaoyizhimei/p/4981551.html 现在将要实现SSH和JBPM的整合. 1.添加jar ...

  5. 【Java EE 学习 77 下】【数据采集系统第九天】【使用spring实现答案水平分库】【未解决问题:分库查询问题】

    之前说过,如果一个数据库中要存储的数据量整体比较小,但是其中一个表存储的数据比较多,比如日志表,这时候就要考虑分表存储了:但是如果一个数据库整体存储的容量就比较大,该怎么办呢?这时候就需要考虑分库了, ...

  6. 【Java EE 学习 72 上】【数据采集系统第四天】【增加调查logo】【文件上传】【动态错误页指定】【上传限制】【国际化】

    增加logo的技术点:文件上传,国际化 文件上传的功能在struts2中是使用文件上传拦截器完成的. 1.首先需要在页面上添加一个文件上传的超链接. 点击该超链接能够跳转到文件上传页面.我给该表单页面 ...

  7. 【Java EE 学习 75 下】【数据采集系统第七天】【二进制运算实现权限管理】【使用反射初始化权限表】【权限捕获拦截器动态添加权限】

    一.使用反射动态添加权限 在该系统中,我使用struts2的时候非常规范,访问的Action的形式都是"ActionClassName_MethodName.action?参数列表" ...

  8. 【Java EE 学习 71 下】【数据采集系统第三天】【分析答案实体】【删除问题】【删除页面】【删除调查】【清除调查】【打开/关闭调查】

    一.分析答案实体 分析答案实体主要涉及到的还是设计上的问题,技术点几乎是没有的.首先需要确定一下答案的格式才能最终确定答案实体中需要有哪些属性. 答案格式的设计是十分重要的,现设计格式如下: 在表单中 ...

  9. 【Java EE 学习 78 下】【数据采集系统第十天】【数据采集系统完成】

    一.项目源代码地址 二.项目演示

随机推荐

  1. python常用模块(模块和包的解释,time模块,sys模块,random模块,os模块,json和pickle序列化模块)

    1.1模块 什么是模块: 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文 ...

  2. Thinkphp文件上传

    1.在IndexController.class.php里面写2个方法,shangchuan用来显示页面,upload是上传文件的方法. <?php namespace Home\Control ...

  3. React的井字过三关(3)

    这是React井字棋项目的最后一篇笔记,记述AI实现. 一. 是开头都会说的原理 但凡懂一点围棋的人都知道"大场"这个概念,可以浅显地把它理解为布局时棋盘上各处的要点.棋谚&quo ...

  4. js常用字符串处理方法

    JS自带函数concat将两个或多个字符的文本组合起来,返回一个新的字符串.var a = "hello";var b = ",world";var c = a ...

  5. placeholder实现的两种方式

    /** * PlaceHolder组件 * $(input).placeholder({ * word: // @string 提示文本 * color: // @string 文本颜色 * evtT ...

  6. Tensorflow使用环境配置

    windows中不能直接使用Tensorflow,所以得费点劲.(2016.11.29更新,TensorFlow 0.12 中已加入初步的 Windows 原生支持) 先是直接使用了<Deep ...

  7. SqlServer批量刷数据执行事务回滚语句备份

    企业进行对数据库执行刷数据工作,一段很长的语句希望同时成功或者失败时用到. 1.建立测试环境 /**************************************************** ...

  8. SQL Server性能计数器收集汇总方案(Reporting Service)

    通过收集计数器信息,并将计数器信息汇总为不同粒度存储,以Reporting Service报表服务器显示.以下是计数器收集汇总的基本架构. 笔者需要收集的SQL Server计数器包括:SQL Ser ...

  9. sql server 字符串转成日期格式

    在SQL Server数据库中,SQL Server日期时间格式转换字符串可以改变SQL Server日期和时间的格式,是每个SQL数据库用户都应该掌握的.本文我们主要就介绍一下SQL Server日 ...

  10. 【IOS】自定义可点击的多文本跑马灯YFRollingLabel

    需求 项目中需要用到跑马灯来仅展示一条消息,长度合适则不滚动,过长则循环滚动. 虽然不是我写的,但看了看代码,是在一个UIView里面放入两个UILabel, 在前一个快结束的时候,另一个显示.然而点 ...