本文章的excel实现导出多个sheet是在上一篇poi导出的基础上实现的,这么久了,对于上一篇文章的poi也作出过一些优化。
这里我只贴修改了的方法的代码,其余的和上一篇文章的一样。
/**
* 导出excel.在一个页面中单独导出Excel
*
* @param titleColumn 对应bean的属性名
* @param titleName excel要导出的表名
* @param titleSize 列宽
* @param dataList 数据
*/
public void wirteExcel(String titleColumn[], String titleName[], int titleSize[], List<?> dataList) {
long startTime = System.currentTimeMillis();
HttpServletRequest request = ServletActionContext.getRequest();
// 新建文件
OutputStream out = null;
try {
if (fileDir != null) {
deleteExcel(fileDir);
// 有文件路径
out = new FileOutputStream(fileDir);
} else {
// 否则,直接写到输出流中
out = response.getOutputStream();
fileName = fileName + ".xls";
log.info("导出excel,文件为:"+fileName);
response.setContentType("application/x-msdownload");
final String userAgent = request.getHeader("USER-AGENT"); // 获取浏览器的代理
// 下面主要是让文件名适应不同浏览器的编码格式
String finalFileName = null;
if (StringUtils.contains(userAgent, "MSIE")) {
finalFileName = URLEncoder.encode(fileName, "UTF8");
} else if (StringUtils.contains(userAgent, "Mozilla")) {// google,火狐浏览器
finalFileName = new String(fileName.getBytes(), "ISO8859-1");
} else {
finalFileName = URLEncoder.encode(fileName, "UTF8");// 其他浏览器
}
response.setHeader("Content-Disposition", "attachment; filename=\"" + finalFileName + "\"");
}
if(dataList!=null) {
// 求总sheet数量,pageCount为每个sheet中数据的数量,此处我设置的是10000条
int pageCount = 10000;
final int sheetNum = (int) Math.ceil((float) dataList.size() / pageCount);
log.info("excel中sheet数量:"+sheetNum);
for (int n = 1; n <= sheetNum; n++) {
// 添加Worksheet(不添加sheet时生成的xls文件打开时会报错)
String sheetNames = this.sheetName + "_" + n;
final HSSFSheet sheet = workbook.createSheet(sheetNames);
// 写入excel的表头
HSSFRow titleNameRow = sheet.createRow(0);
// 设置样式
HSSFCellStyle titleStyle = workbook.createCellStyle();
titleStyle = (HSSFCellStyle) setFontAndBorder(titleStyle, titleFontType, (short) titleFontSize);
titleStyle = (HSSFCellStyle) setColor(titleStyle, titleBackColor, (short) 10);
titleStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
for (int i = 0; i < titleName.length; i++) {
sheet.setColumnWidth(i, titleSize[i] * 256); // 设置宽度
Cell cell = titleNameRow.createCell(i);
cell.setCellStyle(titleStyle);
cell.setCellValue(titleName[i].toString());
}
// 获取内容设置样式
CellStyle doubleStyle = createCellContent4DoubleStyle(workbook);
CellStyle integerStyle = createCellContent4IntegerStyle(workbook);
CellStyle contentStyle = createCellContentStyle(workbook);
titleStyle = (HSSFCellStyle) setFontAndBorder(titleStyle, contentFontType, (short) contentFontSize);
// 通过反射获取数据并写入到excel中
// 先循环获取每个sheet中数据的下标,取出数据存入useList
if (dataList != null && dataList.size() > 0) {
if (titleColumn.length > 0) {
int list_num_start = pageCount*(n-1); // 开始下标
int list_num_end = (sheetNum == n?(n-1):n)*pageCount+(sheetNum == n?dataList.size()%pageCount:0); // 结束下标
// 将本sheet数据加入到集合中
List<Object> useList = new ArrayList<>();
for (int j = list_num_start; j < list_num_end; j++) {
Object object = dataList.get(j);
useList.add(object);
}
HSSFRow rowTemp = null;
HSSFCell celltemp = null;
// 将集合数据写入到该sheet
int y = 0; // 用于行,迭代器没有下标,所以要自己设置行数
for (Iterator iterator = useList.iterator(); iterator.hasNext();) {
Object obj = (Object) iterator.next();
Class clsss = obj.getClass(); // 获得该对对象的class实例
y = y+1; // 定义行
rowTemp = sheet.createRow(y); // 将数据写入第y行中
// 将数据写入对应列中
int a = 0;
for (int columnIndex = 0; columnIndex < titleColumn.length; columnIndex++) {
String title = titleColumn[columnIndex].toString().trim();
if (!"".equals(title)) { // 字段不为空
// 使首字母大写
String UTitle = Character.toUpperCase(title.charAt(0))
+ title.substring(1, title.length()); // 使其首字母大写;
String methodName = "get" + UTitle;
// 设置要执行的方法
Method method = clsss.getDeclaredMethod(methodName);
// 获取返回类型
Class<?> returnType2 = method.getReturnType();
String returnType = returnType2.getName();
String data = method.invoke(obj) == null ? "" : method.invoke(obj).toString();
int x = a++; // 定义列
celltemp = rowTemp.createCell(x); // 将数据写入行中
if (data != null && !"".equals(data)) {
if ("int".equals(returnType)) {
celltemp.setCellValue(Integer.parseInt(data));
celltemp.setCellStyle(integerStyle);
} else if ("long".equals(returnType)) {
celltemp.setCellValue(Long.parseLong(data));
celltemp.setCellStyle(integerStyle);
} else if ("float".equals(returnType)) {
celltemp.setCellValue(Float.parseFloat(data));
celltemp.setCellStyle(doubleStyle);
} else if ("double".equals(returnType)) {
celltemp.setCellValue(Double.parseDouble(data));
celltemp.setCellStyle(doubleStyle);
} else {
if (data.matches("\\d+") == true) {// 判断能否转成数字
celltemp.setCellValue("'" + data);// 转换成文本形式 避免 0001导出变成1
} else {
celltemp.setCellValue(data);
}
}
}
}
}
}
}
}
}
}
log.info("导出excel");
workbook.write(out);
long endTime = System.currentTimeMillis();
log.info("数据全部导出至excel总耗时:" + (endTime - startTime) + "ms;数据长度:" + dataList.size());
// 当前JVM占用的内存总数(M)
double total = (Runtime.getRuntime().totalMemory()) / (1024.0 * 1024);
log.info("当前JVM占用的内存总数(M):"+ total);
// JVM最大可用内存总数(M)
double max = (Runtime.getRuntime().maxMemory()) / (1024.0 * 1024);
log.info("JVM最大可用内存总数(M):"+ max);
// JVM空闲内存(M)
double free = (Runtime.getRuntime().freeMemory()) / (1024.0 * 1024);
log.info("JVM空闲内存(M):"+ free);
// 可用内存内存(M)
double mayuse=(max - total + free);
log.info("可用内存内存(M):"+ mayuse);
// 已经使用内存(M)
double used=(total-free);
log.info("已经使用内存(M):"+ used);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
之前的代码中设置样式时,每次写入数据时,都去调用了设置样式的方式,poi创建样式的次数是有限制的,一旦超出限制便会报错。
那么就需要像现在写的代码一样,先调用样式方法,将样式先获取出来
然后写入excel时再给已经获取好的样式。
celltemp.setCellStyle(doubleStyle);