最近一次小需求要求对一个页面的两个报表通过点击一个导出按钮导出到一个excel中,当然,是要求在一个excel中建立多个sheet来保存两个报表的数据,否则全部放置在一个报表中就没有意义了,记录一下,以免下次使用CV大法的使用
讲讲详细的过程
1.页面
如上图,点击导出明细按钮,要将查询条件查询出的两个表中的数据导出到一个excel,分成两个sheet
2.js代码
按钮的点击事件代码如下:
//导出明细按钮
$("#exportDetailButton").on('click',function() {
$.messager.confirm('导出', '确定导出明细数据?', function(r){
if (r){
downloadFile('/reconciliacionCount/exportDetail?' + $.param(exprotParam));
}
});
});
exprotParam是一个js对象,就是查询条件,通过JQuery的param方法把它变成请求参数,downloadFile()方法的代码如下:
//js文件下载
window.downloadFile = function (sUrl) {
var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
var isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
$.ajax({
type: 'get',
dataType : 'json',
url: '/user/isSessionInvalid',
success: function (data) {
if(data.code ==="1"){
//iOS devices do not support downloading. We have to inform user about this.
if (/(iP)/g.test(navigator.userAgent)) {
return false;
}
//If in Chrome or Safari - download via virtual link click
if (isChrome || isSafari) {
//Creating new link node.
var link = document.createElement('a');
link.href = sUrl;
//Dispatching click event.
if (document.createEvent) {
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
link.dispatchEvent(e);
return true;
}
}
window.open(sUrl, '_self');
return true;
}
return false;
},
error: function(){
return false;
}
});
}
这里的ajax请求/user/isSessionInvalid是在判断用户登录是否失效,如果失效,不让其做任何操作,由于我们的架构用到Shiro,大家在使用时,看情况处理,如果不需要做用户登录验证,可以直接用success方法的代码,这里我暂且贴出这个请求的方法
@RequestMapping(value = "/isSessionInvalid")
public @ResponseBody Object isSessionInvalid() {
User shiroUser = (User) SecurityUtils.getSubject().getPrincipal();
return shiroUser != null ? DataPacket.jsonResult(Constants.SUCCESS_MSG)
: DataPacket.errorJsonResult(Constants.FAIL_MSG);
}
2.后台java代码
/**
*
* @param reconciliationRecord 查询条件
* @param areaId 区域id
* @param flag
* @param response
* @return
*/
@RequiresPermissions(AuthConstants.RECONCILIATION_COUNT_EXPORT)
@RequestMapping(value = "/exportDetail", method = RequestMethod.GET, name = "导出对账统计明细记录")
@ResponseBody
public Object exportDetailData(ReconciliationRecord reconciliationRecord, Integer areaId, String flag, HttpServletResponse response) {
LOG.info("开始导出对账统计数据");
// 将文件存到浏览器设置的下载位置
try (OutputStream out = response.getOutputStream()) {
SXSSFWorkbook wb = reconciliationRecordService.exportDetail(reconciliationRecord);
wb.setCompressTempFiles(true);
response.setContentType("application/x-download;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("对账统计明细报表.xlsx", "UTF-8"));
wb.write(out);// 将数据写出去
} catch (RuntimeException ge) {
LOG.error("对账统计明细导出失败{}", ge);
return DataPacket.errorJsonResult("导出失败");
} catch (IOException e) {
LOG.error("对账统计明细导出失败{}", e);
return DataPacket.errorJsonResult("导出失败");
} catch (Exception gge) {
LOG.error("对账统计明细导出失败 {}", gge);
return DataPacket.errorJsonResult("导出失败");
}
return DataPacket.jsonResult("导出成功");
}
除了exportDetail是根据大家自身业务处理,其他都是死代码,直接cv,主要看下这个方法的实现
@Override
public SXSSFWorkbook exportDetail(ReconciliationRecord reconciliationRecord) {
SXSSFWorkbook wb = new SXSSFWorkbook(INT_1000);
// 生成医院账单明细sheet
generateHisBillSheet(wb, reconciliationRecord, "医院账单明细报表");
// 生成渠道账单明细sheet
generateChannelBillSheet(wb, reconciliationRecord, "渠道交易明细报表");
return wb;
}
由于两个生成sheet的方法基本一样,我这里只列举一个方法的实现
private void generateHisBillSheet(SXSSFWorkbook wb, ReconciliationRecord reconciliationRecord, String sheetName) {
List<HisBillRecord> hisBillRecordList = hisBillRecordMapper.selectAllByCondition(reconciliationRecord);
String[][] dataList = getHisBillData(hisBillRecordList);
int[] columnWidth = { COLUMN_WITH_30, COLUMN_WITH_30, COLUMN_WITH_22,
COLUMN_WITH_22, COLUMN_WITH_22,COLUMN_WITH_22 };
String[] columnName = { "医院交易时间", "医院支付金额", "交易流水号",
"医院业务类型", "交易类型", "收费员" };
SXSSFSheet sheet = wb.createSheet(sheetName);
for (int i = 0; i < HIS_COLUMN_NUMBER; i++) {
sheet.setColumnWidth(i, columnWidth[i] * COLUMN_PX);
}
// 创建第0行 也就是标题
SXSSFRow row1 = sheet.createRow(ZERO_ROW);
CellStyle headerStyle = setSheetSomeStyle(wb, row1);
// 创建标题第一列
SXSSFCell cell1 = row1.createCell(ZERO_CELL);
// 合并列标题
sheet.addMergedRegion(new CellRangeAddress(ZERO_ROW, ZERO_ROW, ZERO_CELL, HIS_COLUMN_NUMBER - 1));
// 设置值标题
cell1.setCellValue(sheetName);
cell1.setCellStyle(headerStyle);
// 创建第1行 也就是表头
SXSSFRow row = sheet.createRow(ONE_ROW);
// 设置表头高度
row.setHeightInPoints(TABLE_HIGHT);
// 创建表头的列
for (int i = 0; i < HIS_COLUMN_NUMBER; i++) {
SXSSFCell cell = row.createCell(i);
cell.setCellValue(columnName[i]);
cell.setCellStyle(headerStyle);
}
// 创建单元格,并设置值
for (int i = 0; i < hisBillRecordList.size(); i++) {
row = sheet.createRow(i + TWO_ROW);
SXSSFCell datacell8 = null;
for (int j = 0; j < HIS_COLUMN_NUMBER; j++) {
datacell8 = row.createCell(j);
datacell8.setCellValue(dataList[i][j]);
datacell8.setCellStyle(headerStyle);
}
}
}
private String[][] getHisBillData(List<HisBillRecord> hisBillRecordList) {
int colume = hisBillRecordList.size();
String[][] hisBillRecordListArr = new String[colume][LENGTH_6];
for (int i = 0; i < hisBillRecordList.size(); i++) {
hisBillRecordListArr[i][0] = hisBillRecordList.get(i).getTradeDate();
if(hisBillRecordList.get(i).getFee() != null) {
BigDecimal free = new BigDecimal(hisBillRecordList.get(i).getFee());
free = free.divide(new BigDecimal(INT_100), 2, RoundingMode.HALF_UP);
hisBillRecordListArr[i][1] = free.toString();
}else {
hisBillRecordListArr[i][1] = "0.00";
}
hisBillRecordListArr[i][2] = hisBillRecordList.get(i).getTradeNo();
hisBillRecordListArr[i][3] = hisBillRecordList.get(i).getBusiName();
if("1".equals(hisBillRecordList.get(i).getIncomeType())) {
hisBillRecordListArr[i][4] = "收入";
}else {
hisBillRecordListArr[i][4] = "支出";
}
hisBillRecordListArr[i][5] = hisBillRecordList.get(i).getTollCollector();
}
return hisBillRecordListArr;
}
上面的这个方法主要是对数据做处理,先将数据集合转化成二维数组,再把数据库的数据做处理,比如某个字段1代表支出,2代表收入,金额我们是以分做单位存,转化成元这种处理操作
以上就是详细的操作过程,如果大家有好的方式,也欢迎分享