上一篇文章介绍了Bootstrap Table的基本知识点和应用,本文针对上一篇文章中未解决的文件导出问题进行分析,同时介绍BootStrap Table的扩展功能,当行表格数据修改。

1.Bootstrap Bable 全部数据导出分析

在表格导出数据中,发现设置了分页参数,导出的数据仅为表格加载的分页参数数据,于是,针对这样的情况,通过设置分页参数的值,使表格可以加载更多的数据,可达到导出所有数据的功能需求。然而,在实际的实验中,发现此方案存在以下问题:

  • 表格一次加载一千条数据时,网页响应速度太慢,加载数据等待时间严重过长。(一分钟左右)
  • Bootsrtap Table 的文件导出是纯前端的js导出模式,它的数据源只能为表格中的数据集合

分析产生上述问题的原因,不难发现,html页面在渲染的时候,一次渲染过多的节点,网页性能必然降低。而通过去分析table-export.js中的导出源码,发现导出文件是以表格为数据源,导出多数据时,必然需要表格加载更多的数据,所以这样的循环,导致导出功能在实际项目中,导出特别耗时,应用不理想。要解决这样的问题,目前可采用如下两种方法:

  • 修改table-export.js中的导出模块源码,当ajax从后台请求到数据成功后,不在渲染数据到Bootstrap Table中去,而是直接作为数据源提供给导出模块。(目前这样的方案,感觉编写js函数需要的逻辑比较复杂)
  • 前端调用java程序中,成熟的导出文件功能,利用java程序处理文件导出。

本次测试文件导出时,采用了java后台程序处理的方案。具体操作如下:

  • 前端界面仿造Bootstrap Table的js函数,编写一个导出所有文件的按钮
  • 利用java程序,调用SXSSFWorkbook组件,导出指定数据到Excel表中

构建导出按钮

构建导出按钮,修改bootstrap-table.js中的定义事项,加入一个showExportAll参数,定义展示样式即可模拟一个导出按钮,重要实现代码如下:

    //wanling add exportAll button 2017-8-7
if (this.options.showExportAll) {
html.push(sprintf('<button class="btn' +
sprintf(' btn-%s', this.options.buttonsClass) +
sprintf(' btn-%s', this.options.iconSize) +
'" type="button" name="exportAll" aria-label="exportAll" title="%s">',
this.options.formatExportAll()),
sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.exportAll),
'</button>');
}

最终实现效果如下:

java调用SXSSFWorkbook组件导出文件

SXSSFWorkbook官网介绍 http://poi.apache.org/apidocs/org/apache/poi/xssf/streaming/SXSSFWorkbook.html。它是专门用来处理大量数据写入 Excel2007的工具。通过在java后台获取到数据后,传入数据,展示列等信息到SXSSFWorkbook中,即可完成数据写入到excel并以文件流的方式输出。核心调用代码如下:

 @Override
public Map perform(Map inMap) throws BizException, SysException {
inMap.put("start", Integer.valueOf(0));
inMap.put("limit", SysconfigHelper.getExportBatchSize());
Map result = overTime.QueryAction(inMap);
String exportFileName = "加班信息表";
List resutList = (List) result.get(CommonAttribute.ROWS);
List queryResultColumnNames = new ArrayList(Arrays.asList("createByDesc", "overTimeDate", "beginTime", "endTime", "overTimeHour", "checkPersonDesc", "overTimeStatus", "projectNameDesc", "overTimeAddressDesc", "eatMoney", "taxiMoney", "overTimeRemark"));
List queryResultColumnFriendlyNames = new ArrayList(Arrays.asList("加班人", "加班日期", "加班开始时间", "加班结束时间", "加班小时", "审核人", "审核状态", "所属项目", "加班地点", "加班餐费", "加班车费", "备注"));
//List<Double> queryResultColumnWidths = new ArrayList(Arrays.asList(65.00, 40.00, 100.00, 120.00, 65.00, 100.00, 65.00, 100.00));
HttpServletResponse response = (HttpServletResponse) inMap.get("http_response");
try {
ExportToExcelHelper.ExportExcel(queryResultColumnNames,queryResultColumnFriendlyNames,resutList,false,exportFileName,response);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
  protected static void exportExcel(List<Object> columnFriendlyNameList, List<Object> columnList, List<Double> columnWidths, Map inMap, OutputStream outputStream, boolean... hideSEQ) {
boolean hideSeq = hideSEQ.length == 1 && hideSEQ[0];
SXSSFWorkbook workbook = new SXSSFWorkbook(5000);
Sheet sheet = workbook.createSheet("sheet1");
initCellStyle(workbook);
setHeaderLine(sheet, columnFriendlyNameList, hideSeq);
setDataLine(sheet, columnList, inMap, hideSeq);
setColumnWidth(sheet, columnWidths);
outputWorkBook(workbook, outputStream);
resetTimeStyleStr();
}

导出数据效果

通过前端自定义的按钮,调用后台的导出文件action,即可导出数据到excel文本中。展示效果如下(部分列数据我手动删除了):

2.bootstrap table 数据行修改

通过调用Bootstrap Table的扩展js(bootstrap-table-editable.js,bootstrap-editable.js)可设置编辑表格行内数据。前端设置编辑表格数据,界面展示效果如下:

对于修改表格内容时的提示框样式,可修改bootstrap-table-editable.js中的源码处理noeditFormatter函数,修改样式参考代码如下:

   var _dont_edit_formatter = false;
if (column.editable.hasOwnProperty('noeditFormatter')) {
var process = column.editable.noeditFormatter(value, row, index);
if(!process.hasOwnProperty('class')){
process.class = '';
}
if(!process.hasOwnProperty('style')){
process.style = 'color:#000;text-decoration:none;';
}
_dont_edit_formatter = ['<a href="javascript:void(0)"',
' data-name="'+process.filed+'"',
' data-pk="' + row[that.options.idField] + '"',
' data-value="' + process.value + '"',
' class="'+process.class+'" style="'+process.style+'"',
'>' + process.value + '</a>'
].join('');
} if (_dont_edit_formatter === false) {
return ['<a href="javascript:void(0)"',
' data-name="' + column.field + '"',
' data-pk="' + row[that.options.idField] + '"',
' data-value="' + result + '"',
editableDataMarkup.join(''),
'>' + value + '</a>'
].join('');
} else {
return _dont_edit_formatter;
}

前端页面调用时,参考代码如下:

  loadCharts: function () {
var me = this;
var tb_departments = me.getCmp("overtimeTable").bootstrapTable({
method: 'post', //请求方式(*)
height: MP.Const.dataGridHeight,
toolbar: '#checkovertimeinfo_toolbar', //工具按钮用哪个容器
striped: true, //是否显示行间隔色
cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
pagination: true, //是否显示分页(*)
sortable: true, //是否启用排序
sortOrder: "asc", //排序方式
sidePagination: "server", //分页方式:client客户端分页,server服务端分页(*)
pageNumber: 1, //初始化加载第一页,默认第一页
pageSize: 20, //每页的记录行数(*)
pageList: [10, 20, 25, 30], //可供选择的每页的行数(*)
//search: true, //是否显示表格搜索,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大
strictSearch: true,
singleSelect:false,
showColumns: true, //是否显示所有的列
showToggle:true, //是否显示详细视图和列表视图的切换按钮
//showRefresh: false, //是否显示刷新按钮
minimumCountColumns: 1, //最少允许的列数
//clickToSelect: true, //是否启用点击选中行
cardView: false, //是否显示详细视图
detailView: false, //是否显示父子表
showHeader: true,
onEditableSave: function (field, row, oldValue, $el) {
//单行数据修改后,保存到后台
var param={};
var listUuid=[];
listUuid[0]=row.uuid;
param.listUuid=listUuid;
param.overTimeStatus=row.overTimeStatus;
MP.doAction("sccq-overtime-update", param, function(data)
{
if(data.success)
{
MP.Msg.info('审核操作完成');
}
me.ajaxGetData(); },null, true, true); },
columns: [
{
title: "全选",
field: "select",
checkbox: true,
align: "left",//水平居中
halign: "left",//垂直居中
}, {
field: "uuid",
align: 'center',
title: "个人分析",
formatter: function (value) {
var html = "<a class='easyui-linkbutton l-btn l-btn-small l-btn-plain' name='" + value + "'>" +
"<span class='l-btn-left l-btn-icon-left'><span class='l-btn-icon icon-search'></span><span class='l-btn-text'>查看</span></span></a>&nbsp;";
return html;
}
}, {
align: "left",//水平居中
halign: "left",//垂直居中
field: "createByDesc",
title: "加班人"
},{
align: "left",
halign: "left",
field: "overTimeDate",
sortable:true,
title: "加班日期",
formatter: function (value) {
return MP.dateFormatter(value);
}
},
{
align: "left",
halign: "left",
field: "beginTime",
title: "加班开始时间"
},
{
align: "left",
halign: "left",
field: "endTime",
title: "加班结束时间"
},
{
align: "left",
halign: "left",
field: "overTimeHour",
sortable:true,
title: "加班小时"
},
{
align: "left",
halign: "left",
field: "overTimeStatus",
title: "审核状态",
editable: {
type: 'select',
title: "审核状态",
pk: 1,
source: [
{value: 2, text: '审核通过'},
{value: 3, text: '驳回'}
],
noeditFormatter: function (value,row,index) {
var result;
if (value == '1' || value == '待审核') {
result={filed:"overTimeStatus",value:"待审核",class:"badge bg-orange",style:"padding:5px 10px;"};
} else if (value == '2' || value == '审核通过'){
result={filed:"overTimeStatus",value:"审核通过",class:"badge bg-green",style:"padding:5px 10px;"};
}
else if (value == '3' || value == '驳回'){
result={filed:"overTimeStatus",value:"驳回",class:"badge bg-red",style:"padding:5px 10px;"};
}
return result;
}
}
},
{
align: "left",
halign: "left",
field: "projectNameDesc",
sortable:true,
title: "所属项目"
},
{
align: "left",
halign: "left",
field: "overTimeAddressDesc",
sortable:true,
title: "加班地点"
},
{
align: "left",
halign: "left",
field: "eatMoney",
sortable:true,
title: "加班餐费"
},
{
align: "left",
halign: "left",
field: "taxiMoney",
sortable:true,
title: "加班车费"
},
{
align: "left",
halign: "left",
field: "overTimeRemark",
title: "备注"
}
],
onPageChange:function(number, size)
{
//设置在分页事件触发时,传递分页参数给后台,重新加载数据
me.queryBaseParam.limit=size;
me.queryBaseParam.start=number;
me.ajaxGetData();
},
onSort: function (name, order) {
me.queryBaseParam.sort=name;
me.queryBaseParam.order=order;
me.ajaxGetData();
},
onClickRow: function (row, $elepment, field) {
if (field == 'uuid') {
//alert("查看页面");
var params={};
params.createBy=row.createBy;
params.createByDesc=row.createByDesc;
me.controller.showOvertimeSingleDetail(params);
}
}
});
},
ajaxGetData: function () {
//加载后台数据
var me=this;
var params=MP.getFormData("searchOverTimeForm_person",this.controller);
params.QueryType=1;
params.limit= me.queryBaseParam.limit;
params.start= me.queryBaseParam.start;
params.sort= me.queryBaseParam.sort;
params.order= me.queryBaseParam.order;
MP.doAction("sccq-overtime-query", params, function (datas) {
if (datas.success) {
me.getCmp("overtimeTable").bootstrapTable('load', datas);
}
}, function (datas) {
alert("数据加载失败");
}, true, true);
}

新的表格展示利器 Bootstrap Table Ⅱ的更多相关文章

  1. 新的表格展示利器 Bootstrap Table

     1.bootstrap table简介及特征 Bootstrap Table是国人开发的一款基于 Bootstrap 的 jQuery 表格插件,通过简单的设置,就可以拥有强大的单选.多选.排序.分 ...

  2. 新的表格展示利器 Bootstrap Table Ⅰ

     1.bootstrap table简介及特征 Bootstrap Table是国人开发的一款基于 Bootstrap 的 jQuery 表格插件,通过简单的设置,就可以拥有强大的单选.多选.排序.分 ...

  3. 【转载】BootStrap表格组件bootstrap table详解

    (转载,来源“脚本之家”,作者不详) 一.Bootstrap Table的引入 关于Bootstrap Table的引入,一般来说还是两种方法: 1.直接下载源码,添加到项目里面来.由于Bootstr ...

  4. Bootstrap Table的例子(转载)

    转载自:http://wenzhixin.net.cn/p/bootstrap-table/docs/examples.html#classes-table 使用的API: data1.json da ...

  5. [转]bootstrap table 动态列数

    原文地址:https://my.oschina.net/u/2356355/blog/1595563 据说bootstrap table非常好用,从入门教程中了解到它的以下主要功能: 由于固定表头意味 ...

  6. Bootstrap Table使用方法详解

    http://www.jb51.net/article/89573.htm bootstrap-table使用总结 bootstrap-table是在bootstrap-table的基础上写出来的,专 ...

  7. JS组件系列——表格组件神器:bootstrap table(二:父子表和行列调序)

    前言:上篇 JS组件系列——表格组件神器:bootstrap table 简单介绍了下Bootstrap Table的基础用法,没想到讨论还挺热烈的.有园友在评论中提到了父子表的用法,今天就结合Boo ...

  8. JS组件系列——Bootstrap Table 表格行拖拽(二:多行拖拽)

    前言:前天刚写了篇JS组件系列——Bootstrap Table 表格行拖拽,今天接到新的需要,需要在之前表格行拖拽的基础上能够同时拖拽选中的多行.博主用了半天时间研究了下,效果是出来了,但是感觉不尽 ...

  9. 使用bootstrap table小记(表格组件)

    前言 新的一年悄然到来,生活依旧.最近一周大热的赵雷风,一首<成都>,一首<理想>再次把民谣展示在国人面前.歌词着实写的不错. 理想,你今年几岁 你总是诱惑着年轻的朋友 你总是 ...

随机推荐

  1. HDFS笔记——技术点汇总

    目录 · 概况 · 原理 · HDFS 架构 · 块 · NameNode · SecondaryNameNode · fsimage与edits合并 · DataNode · 数据读写 · 容错机制 ...

  2. 【JAVASCRIPT】React学习-巧用 props 的 children 属性实现内容填充

    背景 平常写组件,经常遇到需要获取内容放入组件内部的情形. 实现方法 我们有两种实现方式 1. 自定义 props render 的时候通过获取 this.props.content 填充到组件内部 ...

  3. 【D3】cluster layout

    一. 和其他D3类一样,layout 可以链式传递,使用简明的申明添加多种自定义设置. 二.API # d3.layout.cluster() Creates a new cluster layout ...

  4. HDU1027 Ignatius and the Princess II

    Problem Description Now our hero finds the door to the BEelzebub feng5166. He opens the door and fin ...

  5. [IB]PeopleSoft异步详细信息中状态“已完成”但订阅合同状态“新建”问题

    最近遇到一个IB异步程序状态不一致问题,异步详细信息中上面的状态是“DONE”但是订阅合同中还是“新建”状态.在域状态中清除域状态也不管用. 重启app server也不好使.最后执行了appmsgp ...

  6. 数据处理之pandas简单介绍

    Offical Website :http://pandas.pydata.org/ 一:两种基本的数据类型结构 Series 和 DataFrame 先来看一下Series import panda ...

  7. 聪明的质监员[NOIP2011]

    时间限制:1 s   内存限制:128 MB [问题描述] 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n个矿石,从 1 到n逐一编号,每个矿石都有自己的重量wi以及价值vi.检 ...

  8. Spring中使用Map、Set、List、数组、属性集合的注入方法配置文件

    (1)下边的一个Java类包含了所有Map.Set.List.数组.属性集合等这些容器,主要用于演示spring的注入配置: package com.lc.collection; import jav ...

  9. grunt+bower依赖管理

    安装bower(必须安装git) npm install bower -g bower按照插件命令 初始化配置 bower init 生成bower.json //如果有bower.json 直接输入 ...

  10. OpenCV 之 Mat 类

    以前看 OpenCV 的书,或者资料也好,遇到 Mat 类的介绍,一般都是匆匆带过,自以为已经很熟悉了,从来没有深入研究过. 结果前段时间面试了一家公司,被问到两个 Mat 的问题:一是,谈谈对 Ma ...