java导出Excel文件的步骤全纪录
一、背景
当前b/s模式已成为应用开发的主流,而在企业办公系统中,常常有客户这样子要求:你要把我们的报表直接用excel打开(电信系统、银行系统)。或者是:我们已经习惯用excel打印。这样在我们实际的开发中,很多时候需要实现导入、导出excel的应用。
最近在java上做了一个excel的导出功能,写了一个通用类,在这里分享分享,该类支持多sheet,且无需手动进行复杂的类型转换,只需提供三个参数即可:
1、filename
excel文件名
2、hasmap<string,list<?>> data
具体的数据,每个list代表一张表的数据,?表示可为任意的自定义对象
3、linkedhashmap<string,string[][]> headers
stirng代表sheet名。每个string[][]代表一个sheet的定义,举个例子如下:
string[][] header = { {"field1","参数1"} ,{"field2","参数2"} ,{"field3","参数3"} }
其中的field1,field2,field3为对象中的属性名,参数1,参数2,参数3为列名,实际上这个指定了列的名称和这个列用到数据对象的哪个属性。
二、怎么用
以一个例子来说明怎么用,假设有两个类a和b定义如下:
public class a{ private string name; private string address; } public class b{ private int id; private double sum; private string cat; }
现在我们通过查询数据库获得了a和b的两个列表:
list<a> dataa = .....;
list<b> datab = .....;
我们将这两个导出到excel中,首先需要定义sheet:
string[][] sheeta = { {"name","姓名"} ,{"address","住址"} } string[][] sheetb = { {"id","id"} ,{"sum","余额"} ,{"cat","猫的名字"} }
然后将数据汇总构造一个excelutil:
string filename = "测试excel"; hashmap<string,list<?>> data = new hashmap<>(); //asheet为表名,后面headers里的key要跟这里一致 data.put("asheet",dataa); data.put("bsheet",datab); linkedhashmap<string,string[][]> headers = new linkedhashmap<>(); headers.put("asheet",sheeta); headers.put("bsheet",sheetb); excelutil excelutil = new excelutil(filename,data,headers); //获取表格对象 hssfworkbook workbook = excelutil.createexcel(); //这里内置了一个写到response的方法(判断浏览器类型设置合适的参数),如果想写到文件也是类似的 workbook.writetoresponse(workbook,request,response);
当然通常数据是通过数据库查询的,这里为了演示方便没有从数据库查找。
三、实现原理
这里简单说明下实现过程,从调用createexcel()这里开始
1、遍历headers创建sheet
public hssfworkbook createexcel() throws exception { try { hssfworkbook workbook = new hssfworkbook(); //遍历headers创建表格 for (string key : headers.keyset()) { this.createsheet(workbook, key, headers.get(key), this.data.get(key)); } return workbook; } catch (exception e) { log.error("创建表格失败:{}", e.getmessage()); throw e; } }
将workbook,sheet名,表头数据,行数据传入cratesheet方法中创建sheet。
2、创建表头
表头也就是一个表格的第一行,通常用来对列进行说明
hssfsheet sheet = workbook.createsheet(sheetname); // 列数 int cellnum = header.length; // 单元行,单元格 hssfrow row; hssfcell cell; // 表头单元格样式 hssfcellstyle columntopstyle = this.getcolumntopstyle(workbook); // 设置表头 row = sheet.createrow(0); for (int i = 0; i < cellnum; i++) { cell = row.createcell(i); cell.setcellstyle(columntopstyle); string str = header[i][1]; cell.setcellvalue(str); // 设置列宽为表头的文字宽度+6个半角符号宽度 sheet.setcolumnwidth(i, (str.getbytes("utf-8").length + 6) * 256); }
3、插入行数据
这里是最重要的部分,首先通过数据的类对象获取它的反射属性field类,然后将属性名和field做一个hash映射,避免循环查找,提高插入速度,接着通过一个switch语句,根据属性类别设值,主要代码如下:
/** * 设置单元格,根据fieldname获取对应的field类,使用反射得到值 * * @param cell 单元格实例 * @param obj 存有属性的对象实例 * @param fieldmap 属性名与field的映射 * @param fieldname 属性名 */ private void setcell(hssfcell cell, object obj, map<string, field> fieldmap, string fieldname) throws exception { //获取该属性的field对象 field field = fieldmap.get(fieldname); //通过反射获取属性的值,由于不能确定该值的类型,用下面的判断语句进行合适的转型 object value = field.get(obj); if (value == null) { cell.setcellvalue(""); } else { switch (field.getgenerictype().gettypename()) { case "java.lang.string": cell.setcellvalue((string) value); break; case "java.lang.integer": case "int": cell.setcellvalue((int) value); break; case "java.lang.double": case "double": cell.setcellvalue((double) value); break; case "java.util.date": cell.setcellvalue(this.dateformat.format((date) value)); break; default: cell.setcellvalue(obj.tostring()); } } }
完整代码可以到github上查看下载,这里就不列出来了。
github地址:点击跳转
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
上一篇: java编程的30个建议
下一篇: java实现微信小程序加密数据解密算法