上一篇文章介紹了Bootstrap Table的基本知識點和應用,本文針對上一篇文章中未解決的文件導出問題進行分析,同時介紹BootStrap Table的擴展功能,當行表格數據修改。 1.Bootstrap Bable 全部數據導出分析 在表格導出數據中,發現設置了分頁參數,導出的數據僅為表格載入 ...
上一篇文章介紹了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參數,定義展示樣式即可模擬一個導出按鈕,重要實現代碼如下:
1 //wanling add exportAll button 2017-8-7 2 if (this.options.showExportAll) { 3 html.push(sprintf('<button class="btn' + 4 sprintf(' btn-%s', this.options.buttonsClass) + 5 sprintf(' btn-%s', this.options.iconSize) + 6 '" type="button" name="exportAll" aria-label="exportAll" title="%s">', 7 this.options.formatExportAll()), 8 sprintf('<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.exportAll), 9 '</button>'); 10 }
最終實現效果如下:
java調用SXSSFWorkbook組件導出文件
SXSSFWorkbook官網介紹 http://poi.apache.org/apidocs/org/apache/poi/xssf/streaming/SXSSFWorkbook.html。它是專門用來處理大量數據寫入 Excel2007的工具。通過在java後臺獲取到數據後,傳入數據,展示列等信息到SXSSFWorkbook中,即可完成數據寫入到excel並以文件流的方式輸出。核心調用代碼如下:
1 @Override 2 public Map perform(Map inMap) throws BizException, SysException { 3 inMap.put("start", Integer.valueOf(0)); 4 inMap.put("limit", SysconfigHelper.getExportBatchSize()); 5 Map result = overTime.QueryAction(inMap); 6 String exportFileName = "加班信息表"; 7 List resutList = (List) result.get(CommonAttribute.ROWS); 8 List queryResultColumnNames = new ArrayList(Arrays.asList("createByDesc", "overTimeDate", "beginTime", "endTime", "overTimeHour", "checkPersonDesc", "overTimeStatus", "projectNameDesc", "overTimeAddressDesc", "eatMoney", "taxiMoney", "overTimeRemark")); 9 List queryResultColumnFriendlyNames = new ArrayList(Arrays.asList("加班人", "加班日期", "加班開始時間", "加班結束時間", "加班小時", "審核人", "審核狀態", "所屬項目", "加班地點", "加班餐費", "加班車費", "備註")); 10 //List<Double> queryResultColumnWidths = new ArrayList(Arrays.asList(65.00, 40.00, 100.00, 120.00, 65.00, 100.00, 65.00, 100.00)); 11 HttpServletResponse response = (HttpServletResponse) inMap.get("http_response"); 12 try { 13 ExportToExcelHelper.ExportExcel(queryResultColumnNames,queryResultColumnFriendlyNames,resutList,false,exportFileName,response); 14 } catch (IOException e) { 15 e.printStackTrace(); 16 } 17 return null; 18 }
1 protected static void exportExcel(List<Object> columnFriendlyNameList, List<Object> columnList, List<Double> columnWidths, Map inMap, OutputStream outputStream, boolean... hideSEQ) { 2 boolean hideSeq = hideSEQ.length == 1 && hideSEQ[0]; 3 SXSSFWorkbook workbook = new SXSSFWorkbook(5000); 4 Sheet sheet = workbook.createSheet("sheet1"); 5 initCellStyle(workbook); 6 setHeaderLine(sheet, columnFriendlyNameList, hideSeq); 7 setDataLine(sheet, columnList, inMap, hideSeq); 8 setColumnWidth(sheet, columnWidths); 9 outputWorkBook(workbook, outputStream); 10 resetTimeStyleStr(); 11 }
導出數據效果
通過前端自定義的按鈕,調用後臺的導出文件action,即可導出數據到excel文本中。展示效果如下(部分列數據我手動刪除了):
2.bootstrap table 數據行修改
通過調用Bootstrap Table的擴展js(bootstrap-table-editable.js,bootstrap-editable.js)可設置編輯表格行內數據。前端設置編輯表格數據,界面展示效果如下:
對於修改表格內容時的提示框樣式,可修改bootstrap-table-editable.js中的源碼處理noeditFormatter函數,修改樣式參考代碼如下:
1 var _dont_edit_formatter = false; 2 if (column.editable.hasOwnProperty('noeditFormatter')) { 3 var process = column.editable.noeditFormatter(value, row, index); 4 if(!process.hasOwnProperty('class')){ 5 process.class = ''; 6 } 7 if(!process.hasOwnProperty('style')){ 8 process.style = 'color:#000;text-decoration:none;'; 9 } 10 _dont_edit_formatter = ['<a href="javascript:void(0)"', 11 ' data-name="'+process.filed+'"', 12 ' data-pk="' + row[that.options.idField] + '"', 13 ' data-value="' + process.value + '"', 14 ' class="'+process.class+'" style="'+process.style+'"', 15 '>' + process.value + '</a>' 16 ].join(''); 17 } 18 19 if (_dont_edit_formatter === false) { 20 return ['<a href="javascript:void(0)"', 21 ' data-name="' + column.field + '"', 22 ' data-pk="' + row[that.options.idField] + '"', 23 ' data-value="' + result + '"', 24 editableDataMarkup.join(''), 25 '>' + value + '</a>' 26 ].join(''); 27 } else { 28 return _dont_edit_formatter; 29 }
前端頁面調用時,參考代碼如下:
1 loadCharts: function () { 2 var me = this; 3 var tb_departments = me.getCmp("overtimeTable").bootstrapTable({ 4 method: 'post', //請求方式(*) 5 height: MP.Const.dataGridHeight, 6 toolbar: '#checkovertimeinfo_toolbar', //工具按鈕用哪個容器 7 striped: true, //是否顯示行間隔色 8 cache: false, //是否使用緩存,預設為true,所以一般情況下需要設置一下這個屬性(*) 9 pagination: true, //是否顯示分頁(*) 10 sortable: true, //是否啟用排序 11 sortOrder: "asc", //排序方式 12 sidePagination: "server", //分頁方式:client客戶端分頁,server服務端分頁(*) 13 pageNumber: 1, //初始化載入第一頁,預設第一頁 14 pageSize: 20, //每頁的記錄行數(*) 15 pageList: [10, 20, 25, 30], //可供選擇的每頁的行數(*) 16 //search: true, //是否顯示表格搜索,此搜索是客戶端搜索,不會進服務端,所以,個人感覺意義不大 17 strictSearch: true, 18 singleSelect:false, 19 showColumns: true, //是否顯示所有的列 20 showToggle:true, //是否顯示詳細視圖和列表視圖的切換按鈕 21 //showRefresh: false, //是否顯示刷新按鈕 22 minimumCountColumns: 1, //最少允許的列數 23 //clickToSelect: true, //是否啟用點擊選中行 24 cardView: false, //是否顯示詳細視圖 25 detailView: false, //是否顯示父子表 26 showHeader: true, 27 onEditableSave: function (field, row, oldValue, $el) { 28 //單行數據修改後,保存到後臺 29 var param={}; 30 var listUuid=[]; 31 listUuid[0]=row.uuid; 32 param.listUuid=listUuid; 33 param.overTimeStatus=row.overTimeStatus; 34 MP.doAction("sccq-overtime-update", param, function(data) 35 { 36 if(data.success) 37 { 38 MP.Msg.info('審核操作完成'); 39 } 40 me.ajaxGetData(); 41 42 },null, true, true); 43 44 }, 45 columns: [ 46 { 47 title: "全選", 48 field: "select", 49 checkbox: true, 50 align: "left",//水平居中 51 halign: "left",//垂直居中 52 }, { 53 field: "uuid", 54 align: 'center', 55 title: "個人分析", 56 formatter: function (value) { 57 var html = "<a class='easyui-linkbutton l-btn l-btn-small l-btn-plain' name='" + value + "'>" + 58 "<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> "; 59 return html; 60 } 61 }, { 62 align: "left",//水平居中 63 halign: "left",//垂直居中 64 field: "createByDesc", 65 title: "加班人" 66 },{ 67 align: "left", 68 halign: "left", 69 field: "overTimeDate", 70 sortable:true, 71 title: "加班日期", 72 formatter: function (value) { 73 return MP.dateFormatter(value); 74 } 75 }, 76 { 77 align: "left", 78 halign: "left", 79 field: "beginTime", 80 title: "加班開始時間" 81 }, 82 { 83 align: "left", 84 halign: "left", 85 field: "endTime", 86 title: "加班結束時間" 87 }, 88 { 89 align: "left", 90 halign: "left", 91 field: "overTimeHour", 92 sortable:true, 93 title: "加班小時" 94 }, 95 { 96 align: "left", 97 halign: "left", 98 field: "overTimeStatus", 99 title: "審核狀態", 100 editable: { 101 type: 'select', 102 title: "審核狀態", 103 pk: 1, 104 source: [ 105 {value: 2, text: '審核通過'}, 106 {value: 3, text: '駁回'} 107 ], 108 noeditFormatter: function (value,row,index) { 109 var result; 110 if (value == '1' || value == '待審核') { 111 result={filed:"overTimeStatus",value:"待審核",class:"badge bg-orange",style:"padding:5px 10px;"}; 112 } else if (value == '2' || value == '審核通過'){ 113 result={filed:"overTimeStatus",value:"審核通過",class:"badge bg-green",style:"padding:5px 10px;"}; 114 } 115 else if (value == '3' || value == '駁回'){ 116 result={filed:"overTimeStatus",value:"駁回",class:"badge bg-red",style:"padding:5px 10px;"}; 117 } 118 return result; 119 } 120 } 121 }, 122 { 123 align: "left", 124 halign: "left", 125 field: "projectNameDesc", 126 sortable:true, 127 title: "所屬項目" 128 }, 129 { 130 align: "left", 131 halign: "left", 132 field: "overTimeAddressDesc", 133 sortable:true, 134 title: "加班地點" 135 }, 136 { 137 align: "left", 138 halign: "left", 139 field: "eatMoney", 140 sortable:true, 141 title: "加班餐費" 142 }, 143 { 144 align: "left", 145 halign: "left", 146 field: "taxiMoney", 147 sortable:true, 148 title: "加班車費" 149 }, 150 { 151 align: "left", 152 halign: "left", 153 field: "overTimeRemark", 154 title: "備註" 155 } 156 ], 157 onPageChange:function(number, size) 158 { 159 //設置在分頁事件觸發時,傳遞分頁參數給後臺,重新載入數據 160 me.queryBaseParam.limit=size; 161 me.queryBaseParam.start=number; 162 me.ajaxGetData(); 163 }, 164 onSort: function (name, order) { 165 me.queryBaseParam.sort=name; 166 me.queryBaseParam.order=order; 167 me.ajaxGetData(); 168 }, 169 onClickRow: function (row, $elepment, field) { 170 if (field == 'uuid') { 171 //alert("查看頁面"); 172 var params={}; 173 params.createBy=row.createBy; 174 params.createByDesc=row.createByDesc; 175 me.controller.showOvertimeSingleDetail(params); 176 } 177 } 178 }); 179 }, 180 ajaxGetData: function () { 181 //載入後臺數據 182 var me=this; 183 var params=MP.getFormData("searchOverTimeForm_person",this.controller); 184 params.QueryType=1; 185 params.limit= me.queryBaseParam.limit; 186 params.start= me.queryBaseParam.start; 187 params.sort= me.queryBaseParam.sort; 188 params.order= me.queryBaseParam.order; 189 MP.doAction("sccq-overtime-query", params, function (datas) { 190 if (datas.success) { 191 me.getCmp("overtimeTable").bootstrapTable('load', datas); 192 } 193 }, function (datas) { 194 alert("數據載入失敗"); 195 }, true, true); 196 }View Code