ps: 转载的struts2 + excel(poi)+sheet分页文章,在原有基础上修改了一点点内容。这篇文章主要讲解通过annotation的方式配置导出excle(poi)的方式,比原始方式简单,方便操作。另外,文章汇总涉及到了sheet分页,换句话说可以支持大数据的导出。原文作者亲测测试30W条数据导出时失败(内存溢出),我自己测试时30W可以导出,甚至50W都没问题,可能是内存的限制吧,我想通过增大内存的方式,可以导出更多条数据。 但是不建议一次导出这么多数据,这种方式不是什么好的处理方式。
原文地址:http:/jingyan.baidu.com/article/9158e00071b9e5a25412288d.html--------------------------------------------------分页线--------------------------------------------------
最近开发项目中遇到了很多问题,终于可以在空闲的时候总结一下,今天要汇总的是Excel下载导出等相关问题,主要涉及到问题,如下:
1. 生成Excel
2. 大数据Excel导出(支持多个sheet,亲测可以导出30W数据,再大程序报内存溢出)
3. 下载文件,及中文文件名下载乱码,为空等问题
所需jar包: poi-3.8.jar、poi-ooxml-3.8.jar
方法步骤
步骤一: 添加Excel标题对象
/**
* 用来存储Excel标题的对象,通过该对象可以获取标题和方法的对应关系
*
* @author
*
*/
public class ExcelHeader implements Comparable<ExcelHeader> {
/**
* excel的标题名称
*/
private String title;
/**
* 每一个标题的顺序
*/
private int order;
/**
* 说对应方法名称
*/
private String methodName;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public int compareTo(ExcelHeader o) {
return order > o.order ? 1 : (order < o.order ? -1 : 0);
}
public ExcelHeader(String title, int order, String methodName) {
super();
this.title = title;
this.order = order;
this.methodName = methodName;
}
@Override
public String toString() {
return "ExcelHeader [title=" + title + ", order=" + order
+ ", methodName=" + methodName + "]";
}
}
步骤二:定义annotation类,可以通过该类设置导出相应的属性,标题及排序
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* 用来在对象的get方法上加入的annotation,通过该annotation说明某个属性所对应的标题
* @author Administrator
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelResources {
/**
* 属性的标题名称
* @return
*/
String title();
/**
* 在excel的顺序
* @return
*/
int order() default 9999;
}
步骤三:操作Excel,设置Excel标题样式,sheet名称,sheet每页显示条数等信息(struts2+excel(poi)+sheet分页)
说明: Excel样式部分内容可以自己扩展区,这里我也没有做过的的扩展
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Workbook;
/**
* Excel 操作类
*
* @author
*
*/
@SuppressWarnings("unchecked")
public class ExcelUtil {
private static final String POSITION_TITLE = "title";
private static final String POSITION_BODY = "body";
private static ExcelUtil eu = new ExcelUtil();
private ExcelUtil() {
}
public static ExcelUtil getInstance() {
return eu;
}
/**
* 导出对象到Excel,不是基于模板的,直接新建一个Excel完成导出,基于路径的导出
*
* @param outPath
* 输出路径
* @param objs
* 数据源
* @param clz
* 类
* @param sheetName
* 分sheet导出是sheet的名字 , 如 “sheet” -> sheet1,sheet2...
* @param pageSize
* 每个sheet要显示多少条数据
*/
public void exportObj2Excel(String outPath, List objs, Class clz,
String sheetName, int pageSize) {
Workbook wb = handleObj2Excel(objs, clz, sheetName, pageSize);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outPath);
wb.write(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 导出对象到Excel,不是基于模板的,直接新建一个Excel完成导出,基于路径的导出
*
* @param outPath
* 输出路径
* @param objs
* 数据源
* @param clz
* 类
* @param sheetName
* 分sheet导出是sheet的名字 , 如 “sheet” -> sheet1,sheet2...
* @param pageSize
* 每个sheet要显示多少条数据
*/
public HSSFWorkbook handleObj2Excel(List objs, Class clz, String sheetName,
int pageSize) {
HSSFWorkbook wb = null;
try {
wb = new HSSFWorkbook();
// TODO 获取表头
List<ExcelHeader> headers = getHeaderList(clz);
Collections.sort(headers);
if (null != objs && objs.size() > 0) {
int sheetCount = objs.size() % pageSize == 0 ? objs.size()
/ pageSize : objs.size() / pageSize + 1;
for (int i = 1; i <= sheetCount; i++) {
HSSFSheet sheet = null;
if(!StringUtils.isEmpty(sheetName)) {
sheet = wb.createSheet(sheetName + i);
} else {
sheet = wb.createSheet();
}
HSSFRow row = sheet.createRow(0);
// 写标题
CellStyle titleStyle = setCellStyle(wb, POSITION_TITLE);
for (int m = 0; m < headers.size(); m++) {
HSSFCell cell = row.createCell(m);
cell.setCellStyle(titleStyle);
cell.setCellValue(headers.get(m).getTitle());
sheet.setColumnWidth(m, 5000); // 设置每列的宽度
}
// 写数据
Object obj = null;
CellStyle bodyStyle = setCellStyle(wb, POSITION_BODY);
int begin = (i - 1) * pageSize;
int end = (begin + pageSize) > objs.size() ? objs.size()
: (begin + pageSize);
System.out.println("begin:" + begin + ",end=" + end);
int rowCount = 1;
for (int n = begin; n < end; n++) {
row = sheet.createRow(rowCount);
rowCount++;
obj = objs.get(n);
for (int x = 0; x < headers.size(); x++) {
Cell cell = row.createCell(x);
cell.setCellStyle(bodyStyle);
cell.setCellValue(BeanUtils.getProperty(obj,
getMethodName(headers.get(x))));
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("生成excel失败");
}
return wb;
}
/**
* 根据标题获取相应的方法名称
*
* @param eh
* @return
*/
private String getMethodName(ExcelHeader eh) {
String mn = eh.getMethodName().substring(3);
mn = mn.substring(0, 1).toLowerCase() + mn.substring(1);
return mn;
}
/**
* 获取excel标题列表
*
* @param clz
* @return
*/
private List<ExcelHeader> getHeaderList(Class clz) {
List<ExcelHeader> headers = new ArrayList<ExcelHeader>();
Method[] ms = clz.getDeclaredMethods();
for (Method m : ms) {
String mn = m.getName();
if (mn.startsWith("get")) {
if (m.isAnnotationPresent(ExcelResources.class)) {
ExcelResources er = m.getAnnotation(ExcelResources.class);
headers.add(new ExcelHeader(er.title(), er.order(), mn));
}
}
}
return headers;
}
/**
* 设置单元格样式
*
* @param position
* ["body","title"]
*/
private static CellStyle setCellStyle(Workbook workBook, String position) {
CellStyle cellStyle = workBook.createCellStyle();
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 设置单元格字体
Font headerFont = workBook.createFont(); // 字体
if (POSITION_TITLE.equals(position)) {
headerFont.setFontHeightInPoints((short) 12);
} else {
headerFont.setFontHeightInPoints((short) 10);
}
headerFont.setFontName("宋体");
if (POSITION_TITLE.equals(position))
headerFont.setBoldweight((short) 10);
cellStyle.setFont(headerFont);
cellStyle.setWrapText(true);
cellStyle.setFillBackgroundColor(HSSFCellStyle.THICK_FORWARD_DIAG);
// 设置单元格边框及颜色
cellStyle.setBorderBottom((short) 1);
cellStyle.setBorderLeft((short) 1);
cellStyle.setBorderRight((short) 1);
cellStyle.setBorderTop((short) 1);
cellStyle.setWrapText(true);
cellStyle.setLeftBorderColor(HSSFColor.BLACK.index); // 设置边框颜色
cellStyle.setRightBorderColor(HSSFColor.BLACK.index);
cellStyle.setTopBorderColor(HSSFColor.BLACK.index);
cellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
return cellStyle;
}
}
步骤四:导出对象实体类,实际项目中这个类可以有更多的属性
import java.io.Serializable;
import java.util.Date;
import com.monkey.poi.util.ExcelResources;
public class ProductCard implements Serializable {
private static final long serialVersionUID = -70571478472359104L;
private Integer id;
private String code;
private String codePwd;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@ExcelResources(title = "卡号", order = 1)
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@ExcelResources(title = "密码", order = 2)
public String getCodePwd() {
return codePwd;
}
public void setCodePwd(String codePwd) {
this.codePwd = codePwd;
}
}
步骤五: junit测试
@Test
public void test002() {
List<ProductCard> pcList = new ArrayList<ProductCard>();
for (int i = 0; i < 300000; i++) {
ProductCard p = new ProductCard();
p.setCode(DateUtils.formatDate(DateUtils.DATE_PATTERN_PLAIN,new Date()));
p.setCodePwd("123456" + i);
pcList.add(p);
}
ExcelUtil.getInstance().exportObj2Excel("d:/product-1.xls", pcList,
ProductCard.class, "我的sheet", 10000);
}
注意事项:
- Excel样式部分我是按照我们项目中的所用的格式导出,各位在自己项目中可以自己定义
- Excel可以分开单独显示不同的
- 下载部分请查考下一篇文章
参考资料:
http:/jingyan.baidu.com/article/9158e00071b9e5a25412288d.html