最近開發專案中遇到了很多問題,終於可以在空閒的時候總結一下,今天要彙總的是Excel下載匯出等相關問題,主要涉及到問題,如下:
1. 生成Excel
2. 大資料Excel匯出(支援多個sheet,親測可以匯出30W資料,再大程式報記憶體溢位)
3. 下載檔案,及中文檔名下載亂碼,為空等問題
工具/原料
poi-3.8.jarpoi-ooxml-3.8.jar
方法/步驟
-
新增Excel標題物件
/**
* 用來儲存Excel標題的物件,透過該物件可以獲取標題和方法的對應關係
*
* @author monkey
*
*/
public class ExcelHeader implements Comparable{
/**
* 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每頁顯示條數等資訊
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 houzhiqing
*
*/
@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 獲取表頭
Listheaders = 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 ListgetHeaderList(Class clz) {
Listheaders = new ArrayList ();
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() {
ListpcList = new ArrayList ();
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);
}END
注意事項
-
Excel樣式部分我是按照我們專案中的所用的格式匯出,各位在自己專案中可以自己定義
-
Excel可以分開單獨顯示不同的
-
下載部分請查考下一篇文章