方法一前端JS导出
//特别提醒,该方法中的allDatas其实是json
$scope.export = function () {
alert("Successfully!");
//搜索条件内容获取
const fromSONo = $("#fromSONo").val();
const toSONo = $("#toSONo").val();
const fromCostSubNo = $("#fromCostSubNo").val();
const toCostSubNo = $("#toCostSubNo").val();
const fldsalesuserid = $("#fldsalesuserid").val();
const fldamincharge = $("#fldamincharge").val();
/*var brandName = $("#searchBrandName").val();*/
/*if ($("#brandName").val()==""||$("#brandName").val()==null){brandName = ""}*/
//获取当前日期和时间
var now = new Date();
var year = now.getFullYear(); //得到年份
var month = now.getMonth();//得到月份
var date = now.getDate();//得到日期
/*var day = now.getDay();//得到周几*/
var hour = now.getHours();//得到小时
var minu = now.getMinutes();//得到分钟
var sec = now.getSeconds();//得到秒
var MS = now.getMilliseconds();//获取毫秒
/*var week;*/
month = month + 1;
if (month < 10) month = "0" + month;
if (date < 10) date = "0" + date;
if (hour < 10) hour = "0" + hour;
if (minu < 10) minu = "0" + minu;
if (sec < 10) sec = "0" + sec;
if (MS < 100) MS = "0" + MS;
/*var arr_week = new Array("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六");*/
/*week = arr_week[day];*/
var time = "";
time = date + "/" + month + "/" + year + " " + hour + ":" + minu + ":" + sec;
//设置得到当前日期的函数的执行间隔时间,每1000毫秒刷新一次。
/*var timer = setTimeout("writeCurrentDate()", 1000);*/
//列标题
console.info("date from " + $scope.dateFromStr);
let str =
'<tr><td>' +
'PRINT BY ' +
$scope.fldaddresses +
'</td></tr>' +
'<tr><td colspan="20" style="text-align: center;font-size: 30px"><b>' + biaoti + '</b></td></tr>' +
'<tr><td colspan="20" style="text-align: right;">' + time + '</td></tr>' +
'<tr>' +
'<td>' + 'FROM SALES ORDER NO:' + '</td>' +
'<td>' + fromSONo + '</td>' +
'<td>' + 'TO SALES ORDER NO:' + '</td>' +
'<td>' + toSONo + '</td>' +
'<td>' + 'SALES IN CHARGE:' + '</td>' +
'<td>' + fldsalesuserid + '</td>' +
'</tr>' +
'<tr>' +
'<td>' + 'From COST SUBMISSION CODE:' + '</td>' +
'<td>' + fromCostSubNo + '</td>' +
'<td>' + 'TO COST SUBMISSION CODE:' + '</td>' +
'<td>' + toCostSubNo + '</td>' +
'<td>' + 'AM IN CHARGE NAME:' + '</td>' +
'<td>' + fldamincharge + '</td>' +
'</tr>' +
'<tr><td colspan="20">' + '</td></tr>' +
'<tr>' +
'<td>SO No</td>' +
'<td>ADVERTISER NO.</td>' +
'<td>ADVERTISER / AGENCY</td>' +
'<td>CAMPAIGN NAME</td>' +
'<td>SALES IN CHARGE</td>' +
'<td>AM IN CHARGE NAME</td>' +
'<td>NO OF APPS</td>' +
'<td>PORTAL NAME(VONDER)</td>' +
'<td>PORTAL DESCRIPTION</td>' +
'<td>PORTAL DESCRIPTION 2</td>' +
'<td>SERVICE TYPE</td>' +
'<td>COST SUBMISSION CODE</td>' +
'<td>CURRENCY</td>' +
'<td>EQV. COST</td>' +
'<td>SERVICE FEE%</td>' +
'<td>COST BEFORE SERVICE FEE</td>' +
'<td>SERVICE FEE</td>' +
'<td>BILLING CURRENCY</td>' +
'<td>ORG. CURRENCY BILLING AMOUNT</td>' +
'<td>EQV. BILLING AMOUNT</td>' +
'<td>REMARKS</td>' +
'</tr>';
//循环遍历,每行加入tr标签,每个单元格加td标签
var pono = '';
for (let i = 0; i < $scope.allDatas.length; i++) {
str +=
`<td>${$scope.allDatas[i].fldsono}</td>`
+`<td>${$scope.allDatas[i].fldadvno}</td>`
+`<td>${$scope.allDatas[i].fldadvname}</td>`
+`<td>${$scope.allDatas[i].fldcamorprodname}</td>`
+`<td>${$scope.allDatas[i].fldsalesuserid}</td>`
+`<td>${$scope.allDatas[i].fldamincharge}</td>`
+`<td>${$scope.allDatas[i].fldnoofapp}</td>`
/*+`<td>${$scope.allDatas[i].fldcpaornoncpa}</td>`
+`<td>${$scope.allDatas[i].fldbillingmethod}</td>`*/
+`<td>${$scope.allDatas[i].fldvendorname}</td>`
+`<td>${$scope.allDatas[i].fldportaldes}</td>`
+`<td>${$scope.allDatas[i].fldportaldes2}</td>`
+`<td>${$scope.allDatas[i].fldservicetype}</td>`
+`<td>${$scope.allDatas[i].fldcostsubno}</td>`
+`<td>${$scope.allDatas[i].flddefaultcurrency}</td>`
+`<td>${$scope.allDatas[i].fldeqvcost}</td>`
/*+`<td>${$scope.allDatas[i].fldmediabuybyclient}</td>`*/
+`<td>${$scope.allDatas[i].fldservicefeeb}</td>`
+`<td>${$scope.allDatas[i].fldcostbeforeservicefee}</td>`
+`<td>${$scope.allDatas[i].fldservicefee}</td>`
+`<td>${$scope.allDatas[i].fldcurrency}</td>`
+`<td>${$scope.allDatas[i].fldbillingamount}</td>`
+`<td>${$scope.allDatas[i].fldeqvbillingamount}</td>`
/*+`<td>${$scope.allDatas[i].fldcampaignperiod}</td>`*/
+`<td>${$scope.allDatas[i].fldremarks}</td>`;
/*}*/
str += '</tr>';
}
str+='<tr><td colspan="20" style="text-align: center;">' +'END OF DAOCHU'+ '</td></tr>';
//Worksheet名
let worksheet = 'Report'//这里是导出的Excel表左下角的小表单命名,不是对整个导出Excel表进行命名
let uri = 'data:application/vnd.ms-excel;base64,';
//下载的表格模板数据
let template = `<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">//解决中文乱码
<!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
<x:Name>${worksheet}</x:Name>
<x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
</head><body><table>${str}</table></body>
</html>`;
//下载模板
window.location.href = uri + base64(template)
}
//输出base64编码
function base64(s) {
return window.btoa(unescape(encodeURIComponent(s)))
}
//优点:导出的Excel表可以像前端画table表一样方便,内容是自适应长度,样式也可以跟前端的不一样,完全自定义。
//缺点:IE不能用(检查过后疑似td、tr标签问题)
//本方法存在待优化:1、导出的Excel表没有默认命名;2、导出的Excel表似乎只能是.xlsx后缀,无法更改其他后缀
//如果你找到了方法可以让它在IE上导出,导出Excel表时候增加默认命名,请留言
方法二jquery.table2excel.js导出
/*
*需要引入:jquery.table2excel.js
*
*@$("#tableId"): table的id
*/
$('#btnExport').on('click', function() {
$("#tableId").table2excel({
//需要在前端先画好table表,命名tableID
exclude: ".noExl",
name: "Excel Document Name",
filename: "myFileName",
exclude_img: true,
exclude_links: true,
exclude_inputs: true
});
});
//优点:代码更简洁,后缀名也可以更改
//缺点:导出的Excel表是根据给的table ID进行导出的,不能像方法1那样重新“画图(table)”
方法三,满足IE导出
甲方爸爸硬是要使用IE导出,就连微软都放弃了IE,但我们依旧要满足甲方爸爸的需求,不是?
if(!!window.ActiveXObject || "ActiveXObject" in window) {//判断是否为ie览器
var curTbl = document.getElementById("tableID");//tableID
var oXL = new ActiveXObject("Excel.Application");
//创建AX对象excel
var oWB = oXL.Workbooks.Add();
//获取workbook对象
var xlsheet = oWB.Worksheets(1);
//激活当前sheet
var sel = document.body.createTextRange();
sel.moveToElementText(curTbl);
//把表格中的内容移到TextRange中
sel.select;
//全选TextRange中内容
sel.execCommand("Copy");
//复制TextRange中内容
xlsheet.Paste();
//粘贴到准备导出的EXCEL中
oXL.Visible = true;
//设置excel可见属性
try {
var fname = oXL.Application.GetSaveAsFilename("Excel.xls", "Excel Spreadsheets (*.xls), *.xls");//导出的Excel表命名及后缀
} catch(e) {
print("Nested catch caught " + e);
} finally {
oWB.SaveAs(fname);
oWB.Close(savechanges = false);
//xls.visible = false;
oXL.Quit();
oXL = null;
//结束导出excel进程,退出完成
//window.setInterval("Cleanup();",1);
idTmr = window.setInterval("Cleanup();", 1);
}
}
//优点:它可以在IE上使用,可以改变导出的Excel表名字及后缀
//缺点:该方法是根据table表ID进行导出无法像方法一那样自定义导出的样式内容,导出的Excel表在我这是非自适应的
方法四,导出的Excel表可默认命名后缀名可更改
<html>
<head>
<p style="font-size: 20px;color: red;">使用a标签方式将json导出csv文件</p>
<button onclick='tableToExcel()'>导出</button>
</head>
<body>
<script>
function tableToExcel(){
//要导出的json数据
//const jsonData =allDatas;
const jsonData = [
{
name:'YOU',
phone:'123456',
email:'123456@123456.com'
},
{
name:'ME',
phone:'123456',
email:'123456@123456.com'
}
]
//列标题,逗号隔开,每一个逗号就是隔开一个单元格,导出的是json的内容不包含前端table的第一行数据描述
let str = `姓名,电话,邮箱\n`;
//增加\t为了不让表格显示科学计数法或者其他格式
for(let i = 0 ; i < jsonData.length ; i++ ){
for(let item in jsonData[i]){
str+=`${jsonData[i][item] + '\t'},`;
}
str+='\n';
}
//encodeURIComponent解决中文乱码
let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str);
//通过创建a标签实现
let link = document.createElement("a");
link.href = uri;
//对下载的文件命名
link.download = "导出表.csv";//直接设置导出的表格默认命名和后缀命名
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
</body>
</html>
//优点:可以默认导出文件命名和修改导出文件后缀,有兴趣的同学可以尝试导出其他类型的后缀
//缺点:导出的Excel表后缀如果是csv,内容将无法自适应,同样也不具备方法一的自定义
POI导出Excel
方法一,自定义Excel格式导出
第一步:在POM中增加POI的依赖包
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version3.15</version>
</dependency>
//配置poiJar的操作大同小异,但要注意版本号的一致性,避免版本号冲突
第二步:后台书写
//写入流并在浏览器中提示下载:
//一个Excel表一个sheet演示,POI可以弄一个Excel表多个sheet
//我实习时期曾做过1个Excel表3个sheet
try {
//创建一个Workbook对象
Workbook workbook = new XSSFWorkbook();
//创建表单一个或多个都可以,具体看你自己的需求
Sheet sheet = workbook.createSheet();
//给表单设置名字,索引从0开始,0表示第一个表单,第二个位置是命名Excel表sheet
workbook.setSheetName(0, "表单一");// 表单名
//创建行,注意:所有行的创建方法都是一样的。参数代表创建第几行,创建第一行的参数是0,索引都是0开始
Row headRow = sheet.createRow(0);//创建第一行
//创建单元格,创建方式与创建行的方式一致
Cell headCell = headRow.createCell(0);//创建第一行的第一个单元格
//设置单元格样式
CellStyle headCellStyle = workbook.createCellStyle();//创建单元格样式对象
Font font = workbook.createFont();
font.setBold(true);// 是否加粗设置
font.setFontHeightInPoints((short)14);// 字体大小设置
cellStyle.setFont(font);//选择需要用到的字体格式
cellStyle.setAlignment(HorizontalAlignment.CENTER);// 设置水平居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 设置垂直居中
headCell.setCellStyle(headCellStyle );//把设置好的样式对象给单元格
//给单元格赋值
headCell.setCellValue("赋值");
// 设置列宽
sheet.setColumnWidth(1, headCell.getStringCellValue().getBytes().length * 256);
// 冻结第三列第四行
sheet.createFreezePane(3, 4);
//在第一行合并3个单元格
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 2));
// 合并表头,括号内四个参数分别表示:要合并的开始行索引、结束行索引、开始列索引、结束列索引
headRow.setHeightInPoints((2 * sheet.getDefaultRowHeightInPoints()));// 设置行高度
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + "文件名" + ".xlsx");// 提示下载文件
OutputStream out = new FileOutputStream(file);
workbook.write(out);
out.flush();
out.close();
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDispositionFormData("attachment",StringUtils.newStringIso8859_1(StringUtils.getBytesUtf8(file.getName()))));
return new ResponseEntity<byte[]>(Files.toByteArray(file),headers, HttpStatus.CREATED);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
//优点:相对于JS导出方法一来说,都具备自定义样式,我曾在实习时候用它导出Excel表,表中含有2个表单,但是缺点很明显。
//缺点:相对于前端方法一来说,它代码量大,而且一旦写好,需要微调时候,可能就要更改很多的代码,不过如果已经有前辈写好了的模板样式,直接拿过来用的话,也是挺好的。
方法二,POI按照既定样式导出(前提是已经有一个Excel表模板)
第一步jar包的配置
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version3.15</version>
</dependency>
//配置poiJar的操作大同小异,但要注意版本号的一致性,避免版本号冲突
第二步:后台的书写
//配置模板路径
//我这边是src-main-config-excelTemplate-Excel表
//获取模板文件,并根据业务需求重命名文件名,代码:
String path = ActionUtil.getRequest().getServletContext().getRealPath("/");
// 拿到模板文件
String filePath = path + "excelTemplate\\我的Excel.xlsx";
//导出的Excel表后缀名可更改
FileInputStream tps = new FileInputStream(new File(filePath));
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + "自定义Excel文件名"+ ".xlsx");
OutputStream out = new FileOutputStream(file);
//文件流
XSSFWorkbook workbook = new XSSFWorkbook();
//要看你的模板有多少个sheet再根据自己的导出需要多少个sheet而设置多少个
workbook = new XSSFWorkbook(tps);
// 把我的Excel.xlsx模板,复制到新建的需要导出的Excel
//给导出的Excel表填充数据
Sheet sheet = workbook.getSheetAt(0);
//拿到第一个sheet,注意索引从0开始
Row row_01 = sheet.getRow(1);
//拿到第一行
row_01.getCell(1).setCellValue("赋值");
//给第一行第二个单元格插入值,注意索引从0开始
//所有的数据填充都是这么个操作↑。
//生成Excel文件和输出Excel文件
workbook.write(out);
out.flush();
out.close();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment",StringUtils.newStringIso8859_1(StringUtils.getBytesUtf8(file.getName()))));
return new ResponseEntity<byte[]>(Files.toByteArray(file),headers, HttpStatus.CREATED);
//温馨提示:如果在导出的过程中出现异常,请参考POI自定义导出方法一,对生成Excel导出Excel部分进行重新定义。
//优点:省去了方法一写Excel表样式的麻烦
//缺点:Excel样式将会被固定,但这个缺点是可以接受的,只要自己定义好了就行
作者寄语:
希望各位同学使用这六种方法的任意一种后,发现有方法弥补我提出的缺点后可以分享给我,我将会把弥补缺点的方式填补上去,持续更新。
所有的导出方法都可以相关的框架、插件官网中可寻找;当你需要做导出Excel功能时,最好先了解一下自己的项目前端或后台框架,部分框架自带导出Excel功能,调用更方便。
如果我发现有新的Excel导出方法,我将会补充上来。