用java完成将数据导出到Excel中的功能,首先去了解一下有哪些Java ExcelAPI。
Java Aspose Cells
Java Aspose Cells 是一种纯粹的Java授权的Excel API,开发和供应商Aspose发布。这个API的最新版本是8.1.2,发布于2014年7月,是一个丰富而厚重的API(普通Java类和AWT类的组合)设计,可以读、写和操纵电子表格Excel的组件。此API常见用途如下:
- Excel报表,建立动态Excel报表
- 高保真的Excel渲染和打印
- 从Excel电子表格中导入和导出数据
- 生成,编辑,转换和电子表格
JXL
JXL是一款专为Selenium第三方框架,支持基于Web浏览器(数据是Web浏览器自动更新)数据驱动的自动化。然而,它也被用来作为JExcel API的一个共同的支持库,因为它的基本功能是可创建,读取和写入电子表格。基本特征如下:
- 生成Excel文件
- 从工作簿和电子表格导入数据
- 获得行和列的总数
- 注意:JXL只支持xls档案格式,并且不能处理大数据量。
JExcel
JExcel是由Team Dev开发提供纯行货API。利用这一点程序员可以很容易地读取,写入,显示和修改Excel工作簿中的两种格式:.xls和.XLSX。这个API可以很容易地嵌入Java的Swing和AWT。这个API的最新版本是Jexcel-2.6.12,发布于2009年,主要特点如下:
- 自动化Excel应用程序,工作簿,工作表等
- 在Java Swing应用程序作为普通的Swing组件嵌入到工作簿
- 事件侦听器添加到工作簿和电子表格
- 添加事件处理程序来处理的工作簿和电子表格事件的行为
- 添加本地对等开发定制功能
Apache POI
Apache POI是Apache软件基金会提供的100%开源库。大多数中小规模的应用程序开发主要依赖于Apache POI(HSSF+ XSSF)。它支持Excel 库的所有基本功能; 然而,呈现和文本提取是它的主要特点。
这次我用到的是最后一种Apache POI。首先是一个总的方法exportExcel_2007,传入4个主要参数,分别是: sheetName 工作表的名称;dataset 数据源;fieldMap 类的英文属性和Excel中的中文列名的对应关系;sheetSize 每个工作表中记录的最大个数。
代码如下:
/**
* @param sheetName 工作表的名称
* @param dataset 数据源
* @param fieldMap 类的英文属性和Excel中的中文列名的对应关系
* @param sheetSize 每个工作表中记录的最大个数
* @return
* @throws Exception
*/
public <T> Workbook exportExcel_2007(String sheetName, List<T> dataset,
LinkedHashMap<String, String> fieldMap, int sheetSize, List<ModelAttr> modelAttrs) throws Exception {
if(dataset==null || dataset.size()==0) {
throw new RuntimeException("没有任何数据");
}
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
//1.计算一共有多少个工作表
double sheetNum = Math.ceil(dataset.size()/new Integer(sheetSize).doubleValue());
//2.创建相应的工作表,并向其中填充数据
for(int i=0; i<sheetNum; i++){
//如果只有一个工作表的情况
if(1==sheetNum){
Sheet sheet = wb.createSheet(sheetName);
fillSheet(sheet, dataset, fieldMap, 0, dataset.size()-1,modelAttrs);
setColumnBorderAndColor(wb,sheet);
//有多个工作表的情况
}else{
Sheet sheet = wb.createSheet(sheetName+(i+1));
//获取开始索引和结束索引
int firstIndex=i*sheetSize;
int lastIndex=(i+1)*sheetSize-1>dataset.size()-1 ? dataset.size()-1 : (i+1)*sheetSize-1;
//填充工作表
fillSheet(sheet, dataset, fieldMap, firstIndex, lastIndex,modelAttrs);
setColumnBorderAndColor(wb,sheet);
}
}
return wb;
}
将工作表创建出来,就需要对表头和表体进行填充。因为我这里的表头是动态的,因此多传入了一个参数进行相关判断。填充表头和表体的函数是fillSheet。
代码如下:
/**
* @MethodName : fillSheet
* @Description : 向工作表中填充数据
* @param sheet 工作表
* @param list 数据源
* @param fieldMap 中英文字段对应关系的Map
* @param firstIndex 开始索引
* @param lastIndex 结束索引
*/
private <T> void fillSheet(
Sheet sheet,
List<T> list,
LinkedHashMap<String,String> fieldMap,
int firstIndex,
int lastIndex,
List<ModelAttr> modelAttrs
)throws Exception{
//定义存放英文字段名和中文字段名的数组
String[] enFields=new String[fieldMap.size()];
String[] cnFields=new String[fieldMap.size()];
//填充数组
int count=0;
for(Map.Entry<String,String> entry:fieldMap.entrySet()){
enFields[count]=entry.getKey();
cnFields[count]=entry.getValue();
count++;
}
//填充表头
Row firstRow = sheet.createRow(0);
for(int i=0;i<cnFields.length;i++){
firstRow.createCell(i).setCellValue(cnFields[i]);
}
//填充内容
int rowNo=1;
for(int index=firstIndex;index<=lastIndex;index++){
Row row = sheet.createRow(rowNo);
//获取单个对象
Map<String,Object> item= (Map<String, Object>) list.get(index);
for(int i=0;i<enFields.length;i++){
ModelAttrType type = null;
for(ModelAttr modelAttr : modelAttrs){
if(enFields[i].equals(modelAttr.getAttrCode())){
type = modelAttr.getAttrType();
}
}
String value = getFieldValueByNameSequence(enFields[i], item,type);
String fieldValue=value==null ? "" : value;
row.createCell(i).setCellValue(fieldValue);
}
rowNo++;
}
//设置自动列宽
setColumnAutoSize(sheet, 512);
}
首先将表头的数据放入两个数组中,一个是中文表头,一个是英文code,用来匹配表体。然后中文表体填充到新建的firstRow中。
在表头完成后,根据数据源填充表体,因为数据源是一个复杂的mapList,所以需要对填充的value进行提取处理。我这里写了几个方法,其中针对不同类型的数据处理写了一个感知器,感知器的不用类型处理的代码太多,就不贴了。总之能把你想要放的数据取出来就可以,不用写很复杂。
代码如下:
/**
* @MethodName : getFieldValueByNameSequence
* @Description :
* 根据属性名获取属性值
*
* @param fieldNameSequence 简单属性名
* @param o 对象
* @return 属性值
* @throws Exception
*/
private String getFieldValueByNameSequence(String fieldNameSequence, Map<String,Object> o,ModelAttrType type) throws Exception{
String value=null;
return value = getFieldValueByName(fieldNameSequence,o,type);
}
/**
* @MethodName : getFieldValueByName
* @Description : 根据字段名获取字段值
* @param fieldName 字段名
* @param o 对象
* @return 字段值
*/
private String getFieldValueByName(String fieldName, Map<String,Object> o,ModelAttrType type) throws Exception{
Object value=null;
value=getFieldByName(fieldName, o);
String valueStr = insAttrValueAwareProcessor.convertToExcel(type, value);
return valueStr;
}
/**
* @MethodName : getFieldByName
* @Description : 根据字段名获取字段
* @param fieldName 字段名
* @param
* @return 字段
*/
private static Object getFieldByName(String fieldName, Map<String,Object> o){
if(o == null){
return null;
}
return o.get(fieldName);
}
填充完数据后,就需要简单设置一下工作表的样式,具体看实际情况。
代码如下:
/**
* @MethodName : setColumnAutoSize
* @Description : 设置工作表自动列宽和首行加粗
* @param ws
*/
private static void setColumnAutoSize(Sheet ws,int extraWith){
//获取本列的最宽单元格的宽度
for(int i=0;i<ws.getRow(0).getPhysicalNumberOfCells();i++){
int colWith=0;
for(int j=0;j<ws.getLastRowNum();j++){
String content=ws.getRow(j).getCell(i).getStringCellValue();
int cellWith=content.length();
if(colWith<cellWith){
colWith=cellWith;
}
}
//设置单元格的宽度为最宽宽度+额外宽度
ws.setColumnWidth(i, colWith*extraWith);
}
}
/**
* 设置工作表单元格边框和首行背景色
* @param wb
* @param ws
*/
private static void setColumnBorderAndColor(SXSSFWorkbook wb,Sheet ws){
XSSFCellStyle cellBorderStyle = (XSSFCellStyle)wb.createCellStyle();
XSSFCellStyle cellColorStyle = (XSSFCellStyle)wb.createCellStyle();
for(int i=0;i<ws.getPhysicalNumberOfRows();i++){
Row row = ws.getRow(i);
for(int j=0;j<ws.getRow(0).getPhysicalNumberOfCells();j++){
Cell cell = row.getCell(j);
Cell cellFirst = ws.getRow(0).getCell(j);
//给单元格设置边框
cellBorderStyle.setBorderBottom(BorderStyle.THIN);
cellBorderStyle.setBorderTop(BorderStyle.THIN);
cellBorderStyle.setBorderLeft(BorderStyle.THIN);
cellBorderStyle.setBorderRight(BorderStyle.THIN);
//给第一行设置边框和背景
cellColorStyle.setFillForegroundColor(IndexedColors.AQUA.getIndex());
cellColorStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellColorStyle.setBorderBottom(BorderStyle.THIN);
cellColorStyle.setBorderTop(BorderStyle.THIN);
cellColorStyle.setBorderLeft(BorderStyle.THIN);
cellColorStyle.setBorderRight(BorderStyle.THIN);
cell.setCellStyle(cellBorderStyle);
cellFirst.setCellStyle(cellColorStyle);
}
}
}
有想深入了解学习Apache POI的,可以看看这篇教程Apache POI教程。我也对其进行了参考学习。