在多数项目当中都会使用到将数据查询出来并导出到Excel的功能,若是每个Excel导出功能都需要写一个单独方法的话,会使代码重复率过高,且效率不高。
所以,下面我们使用Apache POI以及java的反射功能来造一个轮子来解决这个问题,即使用一个方法解决Excel导出功能。
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
package com.jtexplorer.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
/**
* @author xuwang
*/
@Slf4j
public class ExcelUtil {
/**
* 导出excel
* @param sheetTitle sheet标题(也会在excel的第一行显示)
* @param nameAndFiledName 字段的标题以及字段对应对象的属性名称,中间用英文':'进行隔开,举例: 姓名:name,列顺序按照list顺序进行显示
* @param list 对象列表
* @return 文件流
*
*/
public static byte[] objectToExcelFile(String sheetTitle, List<String> nameAndFiledName, List list) {
//创建excel表
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet(sheetTitle);
//设置默认行宽
sheet.setDefaultColumnWidth(20);
//表头样式(加粗,水平居中,垂直居中)
HSSFCellStyle cellStyle = wb.createCellStyle();
//水平居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//垂直居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
//设置边框样式
//下边框
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//左边框
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
//上边框
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
//右边框
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
HSSFFont fontStyle = wb.createFont();
fontStyle.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
cellStyle.setFont(fontStyle);
//标题样式(加粗,垂直居中)
HSSFCellStyle cellStyle2 = wb.createCellStyle();
//垂直居中
cellStyle2.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle2.setFont(fontStyle);
//设置边框样式
//下边框
cellStyle2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//左边框
cellStyle2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
//上边框
cellStyle2.setBorderTop(HSSFCellStyle.BORDER_THIN);
//右边框
cellStyle2.setBorderRight(HSSFCellStyle.BORDER_THIN);
//字段样式(垂直居中)
HSSFCellStyle cellStyle3 = wb.createCellStyle();
//垂直居中
cellStyle3.setVerticalAlignment(VerticalAlignment.CENTER);
//设置边框样式
//下边框
cellStyle3.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//左边框
cellStyle3.setBorderLeft(HSSFCellStyle.BORDER_THIN);
//上边框
cellStyle3.setBorderTop(HSSFCellStyle.BORDER_THIN);
//右边框
cellStyle3.setBorderRight(HSSFCellStyle.BORDER_THIN);
//创建表头
HSSFRow row = sheet.createRow(0);
row.setHeightInPoints(20); //行高
HSSFCell cell = row.createCell(0);
cell.setCellValue(sheetTitle);
cell.setCellStyle(cellStyle);
//创建标题
HSSFRow rowTitle = sheet.createRow(1);
rowTitle.setHeightInPoints(20);
HSSFCell hc;
for (int i = 0; i < nameAndFiledName.size(); i++) {
hc = rowTitle.createCell(i);
hc.setCellValue(nameAndFiledName.get(i).split(":")[0]);
hc.setCellStyle(cellStyle2);
}
byte result[] = null;
ByteArrayOutputStream out = null;
try {
//创建表格数据
Field[] fields;
int i = 2;
//循环每行数据
for (Object obj : list) {
fields = obj.getClass().getDeclaredFields();
HSSFRow rowBody = sheet.createRow(i);
rowBody.setHeightInPoints(20);
int n = 0;
//先循环标题,确定显示顺序
for (int j = 0; j < nameAndFiledName.size(); j++) {
//循环对象的属性
for (int m = 0; m < fields.length; m++) {
//对象属性名
String fliedName = fields[m].getName();
// 私有属性必须设置访问权限
fields[m].setAccessible(true);
//获取当前属性的值
Object object = fields[m].get(obj);
//获取需要显示的属性名
String xlsTitle = nameAndFiledName.get(j).split(":")[1];
//判断需要显示的字段
if(xlsTitle.equals(fliedName)) {
hc = rowBody.createCell(n);
//只能输出字符串
if(object != null) {
hc.setCellValue(object.toString());
}else {
hc.setCellValue("");
}
hc.setCellStyle(cellStyle3);
n++;
}
}
}
i++;
}
out = new ByteArrayOutputStream();
wb.write(out);
result = out.toByteArray();
} catch (Exception ex) {
log.info(ex.getMessage());
} finally{
try {
if(null != out){
out.close();
}
} catch (IOException ex) {
log.info(ex.getMessage());
} finally{
try {
wb.close();
} catch (IOException ex) {
log.info(ex.getMessage());
}
}
}
return result;
}
}
附带一个byte[] 生成文件的方法:
/**
* bfile 需要转换成文件的byte数组
* filePath 生成的文件保存路径
* fileName 生成文件后保存的名称如test.pdf,test.xls等
*/
public static void byteToFile(byte[] bfile, String filePath,String fileName) {
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try {
File dir = new File(filePath);
boolean isDir = dir.isDirectory();
// 目录不存在则先建目录
if (!isDir) {
try {
dir.mkdirs();
} catch (Exception e) {
e.printStackTrace();
}
}
file = new File(filePath + File.separator + fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(bfile);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
@Test
public void badTypeReportReport() {
//项目路径
String realPath = System.getProperty("user.dir")+"/target/Main";
// String realPath = request.getRealPath("/");
String fileDir = "/upload/excel/";
String fileName = System.currentTimeMillis()+"badTypeReport.xls";
List lifeCycleDTOList = recordService.eventLifeCycle(new EventLifeCycleQuery(),new RowBounds());
List<String> titleList = new ArrayList<>();
titleList.add("异常事件:strAudiocontent");
titleList.add("岗位名称:cellName");
titleList.add("设备名称:cellDeviceName");
titleList.add("发生时间:HappenTime");
titleList.add("响应时间:ResponseTime");
titleList.add("解除时间:OverTime");
titleList.add("响应时长(秒):eventResponseTime");
titleList.add("解除时长(秒):eventOverTime");
titleList.add("异常总时间(秒):eventTime");
byte[] file = ExportExcelUtil.objectToExcelFile("异常生命周期",titleList,lifeCycleDTOList);
if(file == null){
System.out.println("file is null");
}
System.out.println(realPath);
System.out.println(realPath+fileDir);
FileUtil.byteToFile(file,realPath+fileDir,fileName);
System.out.println("excelPath : "+ fileDir+fileName);
}
excel效果如下:
注意,目前版本导出的字段必须是字符串类型,时间等类型的显示格式未做处理;目前时间复杂度为O(m*n*a),执行效率也需要进行优化。接下来我们会一步步的解决这些问题。
{{ cmt.username }}
{{ cmt.content }}
{{ cmt.commentDate | formatDate('YYYY.MM.DD hh:mm') }}