前端导出Excel的四种方法和后台使用POI导出Excel的两种方法及其优缺点

方法一前端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导出方法,我将会补充上来。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值