在做一个需求管理的页面时,需求的展现是不限层级树型结构,需求下还可以分拆任务,页面要展现的字段有20多个,而且需求采用通用表单设计,db采用大宽表存储,有一百多个字段。目前数据量不大,第一版采用普通的同步加载数据方式,页面加载速度慢,慢的原因主要是代码逻辑没有做到最优,不如存在重复查询的问题,组织树型结构的时候也存在冗余的查询。加上页面渲染出全部数据,使得整个页面打开速度很慢。

针对以上问题,同事做了第二版优化,主要采用ajax加载页面,滚动条采用代码控制,拖动滚动条的位置计算要显示的数据,然后从数据库取出相应的数据。第二版主要存在问题是每次滚动鼠标都会发起请求加载数据,并且每次请求的数据都会覆盖已经加载的数据,在加载过程中使用遮罩禁止重复滚动加载数据。以上问题使得用户体验很差,所以我临时接手进行了第二次优化。

思路:

1.针对每个项目的需求和任务,在第一次访问的时候,将当前访问的项目的全部需求和任务树型结构组织好并缓存起来,缓存过期时间控制在2-4小时(依数据量和内存大小灵活设置),注意采用indexMap.put(i++, row);的形式,这样方便后期分屏加载。row的定义为Map<String, Object> row ;//Object可存需求和任务,通过key区分。

2.获取查询条件,如果为空,则从数据库取最后一次保存的查询条件,否则保存最新查询条件。

3.通过遍历indexMap,统计满足条件的需求和任务数量。

4.返回框架页面,并发送ajax请求真实数据。

5.对请求分页处理,分页大小控制在一次请求50条,太大页面渲染时间慢,太小又需较多次加载。遍历indexMap,取出满足分页条件和查询条件的数据,返回给客户端。

6.页面滚动到末尾,自动发起ajax加载后面的数据。

通过瀑布流的形式,解决了树型结构的分页问题,不用一次全部取出数据,使用缓存,提高加载速度。通过第三次优化。用户体验得到了较大提升。

注意点:使用原生ajax返回50条数据拼接到原有数据末尾的时候,ie容易内存溢出。

部分关键代码:

/**

判断最后一行是否进入可视区域

obj:有滚动条的容器box

lastRow:最后一行

**/

function see(obj, lastRow){

  if(obj && lastRow){

    var seeHeight = document.documentElement.clientHeight || document.body.clientHeight;//可视高度

    var winScroll = obj.scrollTop;//获取滚动条当前位置

    var lastSee = obj.scrollHeight;//最后一行

    return lastSww< (seeHeight + winScroll)?true:false;

  }else{

    return true;

  }

}

/**

  将ajax数据拼接到页面末尾

**/

function append(parent, text){

  if(typeof text ==='string'){

    var temp = document.createElement('div');

    temp.innerHTML = text;

    var frag = document.createDocumentFragment();

    while(temp.firstChild){

      frag.appendChild(temp.firstChild);

    }

    parent.appendChild(frag);

    delete temp;

    delete frag;

    CollectGarbage();

  }

}

/**

  组织treeIndex

**/

... ...

int i = 0;

for(ProjectDemand mode: items){

  Map<String, Object> row = new HashMap<String, Object>();

  if(attachMap.get(mode.getId())!=null){

    mode.setArrachmetCount(attachMap.get(mode.getId()));

  }

  row.put.("demand", mode);

  indexMap.put(i++, row);

  if(ScrumTaskMap.get(mode.getId())!=null){

    List<Task> tasklist = scrumTaskMap.get(mode.getId());

    for(Task task : tasklist){

      Map<String, object> rowTask  = new HashMap<String, Object>();

      rowTask.put("task", task);

      indexMap.put(i++, rowTask);

    }

  }

}

/**

统计需求和任务数量

**/

private String projectDemandStatistics(Map indexMap, Map<String,String> filter, Map<integer, FormBase> showDemandAll, Map<Integer, Task> showTaskAll ){

  int demandAllCount=0;

  int leafCount=0;

  int taskCount = 0;

  int allCount = indexMap.size();

  FormBase demand = null;

  FormBase tempDemand = null;

  Task task = null;

  Map<String, String>SignMap = SZSEUtils.getItemsSign(indexMap);

  String showDemandFlag = TypeUtils.nullToString(filter.get("showDemandFlag")); 

  Map<Integer, FormBase> iteredDemand = new HashMap();//已遍历需求

  

  for(int i=0; i<allCount;i++){

    Map<String, Object> row = (Map<String,  Object>) indexMap.get(i);

    if(row==null) break;

    if(row.get("demand")!=null){
      demand = (FormBase) row.get("demand");

      iteredDemand.put(demand.getId(), demand);

      if(isShowDemand(filter, demand)){\

        if(showDemandAll!=null) showDemandAll.p;ut(demand.getId(), demand);//在这里记录要显示的需求map,供任务显示与否判断时用

        demandAllCount++;

        if(!"+".equals(signMap.get(demand.getId()+""))){

          leafCount++;

        }

        //拾遗父需求

        tempDemand = demand;

        while(showDemandAll !=null

          && SZSEUtils.isNotEmpty(tempDemand.getNum01())

          && !"0".equals(tempDemand.getNum01())

          &&showDemandAll.get(TypeUtils.nullToInt(tempDemand.getNum01()))==null){

          tempDemand = itereDemand.get(Typeutils.nullToInt(tempDemand.getNum01()));

          showDemandAll.put(tempDemand.getId(), tempDemand);

          demandAllCount++;

          if(!"+".equals(signMap.get(tempDemand.getId()+""))){

            leafCount++;

          }

        }

      }

    }else if("true".equals(showDemandFlag)){//显示任务

      task = (Task) row.get("taskId");

      if(isShowTask(filter, task)){

        int parentID = TypeUtils.nullToInt(task.getStr07());

        if(showDemandAll!=null && showDemandAll.get(parentID)!=null){//如果需求不显示,则任务也不显示

          showTaskAll.put(task.getId9), task);

          taskCount++;

        }

      }

    }

  }

  String countMessage = "共"+ demandAllCount +"个需求,共"+leafCount+"个叶子需求";

  if("true".equals(showDemandFlag)) countMessage +="; 共"+taskCount+"个任务";

  countMessage+=".";

  return countMessage;

}

java树型结构的数据展现设计的更多相关文章

  1. dzzoffice的树型结构用户管理设计

    在DzzOffice1.1的开发中,针对用户使用群体重新设计了,机构.部门.用户管理应用. 传统OA,企业相关程序,一般是设置机构-设置部门-设置职位-添加用户这样的步骤.每个步骤分为不同的管理界面. ...

  2. JSP中的一个树型结构

    看方力勋的javaWeb,采用左右值来表示树型结构(就是俺门的多级分类)表结构 页面代码 <%@ page language="java" import="java ...

  3. 20-Ubuntu-文件和目录命令-查看目录树型结构-tree

    tree 以树状图列出当前目录下的文件目录结构 选项 含义 -d 只显示当前目录的子目录树型结构   显示当前目录的子目录和文件树型结构 例: 1.查看文档目录下的子目录和文件树型结构 2.查看文档目 ...

  4. 分享使用NPOI导出Excel树状结构的数据,如部门用户菜单权限

    大家都知道使用NPOI导出Excel格式数据 很简单,网上一搜,到处都有示例代码. 因为工作的关系,经常会有处理各种数据库数据的场景,其中处理Excel 数据导出,以备客户人员确认数据,场景很常见. ...

  5. Java实现树形结构的数据转Json格式

    在项目中难免会用到树形结构,毕竟这是一种常用的组织架构.楼主这里整理了两个实现的版本,可以直接拿来使用,非常方便. 楼主没有单独建项目,直接在以前的一个Demo上实现的.第一种,看下面代码: pack ...

  6. java实现树型结构样式

    import javax.swing.*; import javax.swing.event.*; import javax.swing.tree.*; public class Root exten ...

  7. java树状结构之二叉树

    参考:http://blog.csdn.net/zhangerqing/article/details/8822476 前面已经提到过树和二叉树的相关概念内容,下面主要来介绍下关于二叉树的创建,遍历, ...

  8. Delphi实现树型结构

    unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...

  9. Delphi实现树型结构具体实例

    unit Unit1;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, ...

随机推荐

  1. 重置网络命令win7

    开始→运行→输入:CMD 点击确定(或按回车键),打开命令提示符窗口. 在命令提示符中输入:netsh winsock reset (按回车键执行命令) 稍后,会有成功的提示:成功地重置Winsock ...

  2. Swift新手教程系列5-函数+selector在swift中的使用方法

    原创blog.转载请注明出处 近期在用swift写代码,尽管遇到一些问题,可是代码量确实减了不少. swfit新手教程系列会随着我使用swfit中的积累,不断地去修正更新 之前的教程 swift单例模 ...

  3. Echarts 如何使用 bmap 的 API

    使用 Echarts 在绘制 Binning on map 的图形时(其实也就是 在地图上绘制热力色块图) 解决因为数据量过大,希望在拖拽加载或者缩放加载的时候,根据可视区域的经纬度范围,来请求相应的 ...

  4. The method getJspApplicationContext(ServletContext) is undefined for the type JspFactory的解决方法

    An error occurred at line: [31] in the generated java file: [/data/tmisnt/work/Catalina/localhost/_/ ...

  5. 【OI】关于快速幂的简单理解

    都知道算某个数的幂需要线性的复杂度,为了优化复杂度,就出现了所谓的快速幂. 快速幂的代码很短,但是要原理需要一点心思. 首先,我们知道, a^b = a^c * a^d (c+d=b) 那么,不就可以 ...

  6. UVA 213 Message Decoding 【模拟】

    题目链接: https://cn.vjudge.net/problem/UVA-213 https://uva.onlinejudge.org/index.php?option=com_onlinej ...

  7. codeforces 940F 带修改的莫队

    F. Machine Learning time limit per test 4 seconds memory limit per test 512 megabytes input standard ...

  8. [转] 本地项目上传github (新项目 / 旧项目)

    前置:安装Git Bash,在github上新建仓库repository 1.右键点击项目所在文件夹,运行: git bash here.在git bash窗口运行命令 git init 把这个目录变 ...

  9. Ubuntu 14.04 台式机锐捷使用:

    1.解压文件:RG_Supplicant_For_Linux_V1.31.zip2.sudo chmod -R 777 rjsupplicant3.进入文件夹(./rjsupplicant.sh -a ...

  10. SQL Server2012 T-SQL基础教程--读书笔记(1-4章)

    SQL Server2012 T-SQL基础教程--读书笔记(1-4章) SqlServer T-SQL 示例数据库:点我 Chapter 01 T-SQL 查询和编程背景 1.3 创建表和定义数据的 ...