这个问题困扰我一年多了,其实怎么解决一直有思路,但是又懒得去写。正好最近有空,而且新公司也实现了这个方式。所以顺便整理一下。
首先说一下poi和easypoi。
关于这个生成的excel表头和数据问题,两年前我是用poi做的。当时一个导出对应一大串方法,几十个字段都挨个写,然后for循环遍历数据对象来往格子里set,虽然逻辑很简单但是代码着实麻烦。这也就算了,毕竟就写一次。
但是去年遇到那种往写好了的excel中间插字段,那工作量简直搞人心态。然后寻思狗群友推荐我easyPoi,其中有个实体对象对应excel的模式,虽然可能是我我之前的方法简单点,但是本质上改动较大,而且也不是那么方便,所以就没改。
后来第二版中表头用的数组,数据还是for循环填格子。当时想着反射填充数据,但是又懒得去实现,就一直到现在。
正好到了新公司发现公司的导出就是我想象中的亚子,所以简单讲一下:
这里是把想导出的表格作为一个map传参。map 的key是实体对象中的属性名。value是想要的对应的中文表头。然后处理的时候去遍历value去获取表头。接着遍历数据列表,一层一层每一个属性用反射获取填充。
完整代码如下:
public class ExcelUtil {
/**
* 反射获取数据中指定字段的值
* @param clazz
* @param obj
* @param fieldName
* @return
*/
public static Object getMethodVal(Class<?> clazz, Object obj, String fieldName) {
try {
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1);
Method getMethod = clazz.getMethod(getter);
return getMethod.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 创建表头
* @param workbook
* @param headList
*/
public static void createExcelHead(SXSSFWorkbook workbook, Map<String, String> headList) {
Sheet sheet = workbook.createSheet();
Row headRow = sheet.createRow(0);
int cellNum = 0;
for (Map.Entry<String, String> head : headList.entrySet()) {
XSSFCellStyle style = (XSSFCellStyle) workbook.createCellStyle();
XSSFFont font = (XSSFFont) workbook.createFont();
style.setFont(font);
style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
Cell cell = headRow.createCell(cellNum);
cell.setCellStyle(style);
cell.setCellValue(head.getValue());
cellNum++;
}
}
/**
* 填充数据
* @param workbook
* @param headList
* @param dataList
* @param <T>
*/
public static <T> void appendExcel(SXSSFWorkbook workbook, Map<String, String> headList, List<T> dataList) {
Sheet sheet = workbook.getSheetAt(0);
int lastRowNum = sheet.getLastRowNum() + 1;
for (T t : dataList) {
Row row = sheet.createRow(lastRowNum);
int cellNum = 0;
for (Map.Entry<String, String> head : headList.entrySet()) {
Cell cell = row.createCell(cellNum);
Object methodVal =getMethodVal(t.getClass(), t, head.getKey());
if (methodVal == null) {
methodVal = "";
}
if (methodVal instanceof Integer) {
cell.setCellValue((Integer) methodVal);
} else if (methodVal instanceof Date) {
String dateToStr = DateUtils.dateToStr((Date) methodVal, DateUtils.YYYY_MM_DD_HH_MM_SS);
cell.setCellValue(dateToStr);
} else {
cell.setCellValue(methodVal.toString());
}
cellNum++;
}
lastRowNum++;
}
}
public static <T> void createExcelNoPath(String excelName, Map<String, String> headList, List<T> dataList,
HttpServletResponse response) {
ByteArrayOutputStream baos = null;
try {
//超过1000行将刷新到磁盘
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
//创建表格头
createExcelHead(wb, headList);
//创建数据
appendExcel(wb, headList, dataList);
baos = new ByteArrayOutputStream();
wb.write(baos);
baos.close();
String fileName = excelName + "-" + DateUtils.dateToStr(new Date(), DateUtils.YYYYMMDDHHMMSS) + ".xlsx";
String filepath = "D:\\" + fileName;
File file = new File(filepath);
if (file.exists()) {
file.delete();
}
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray(), 0, baos.toByteArray().length);
fos.flush();
fos.close();
response.setContentType("application/vnd.ms-excel");
response.addHeader("Content-Disposition", "attachment;filename=" +
new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
response.getOutputStream().write(baos.toByteArray());
response.getOutputStream().flush();
response.getOutputStream().close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (baos != null) {
try {
baos.close();
response.getOutputStream().flush();
response.getOutputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
这里的四个参数一个是输出流就不说了,另外三个一个是导出文件的名字,headList是表头和属性的map,dataList是我们真正要填充的数据列表。整个方法就这样。
本篇笔记如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利吧~!
网友评论