java POI excel匯出百萬條資料
阿新 • • 發佈:2019-02-09
首先新建一個註解類
ExportAnnotation.java
package com.shz.demo.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 作者:宋浩志
* @createDate 建立時間:2018年8月20日 上午10:36:58
*/
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention (RetentionPolicy.RUNTIME)
public @interface ExportAnnotation {
int order() default 100;//排序(屬性對應excel的列 的列數)
String method() default "";//屬性對應的get方法
//匯出title
String columnTitle() default "";//屬性對應的excel 的title
//title陣列長度
int length() default 20;//列的個數
}
匯出的實體物件 javaBean
Users.java
package com.shz.demo.model.admin;
import java.util.Date;
import com.shz.demo.annotation.ExportAnnotation;
import com.shz.demo.model.global.PageQuery;
/**
* @author 宋浩志
*
*/
@ExportAnnotation(length=5)
public class Users {
private Long id;
@ExportAnnotation(order=0,method="getUsername",columnTitle="使用者賬號" )
private String username;
@ExportAnnotation(order=1,method="getNickname",columnTitle="使用者名稱")
private String nickname;
@ExportAnnotation(order=2,method="getPassword",columnTitle="密碼")
private String password;
@ExportAnnotation(order=3,method="getEmail",columnTitle="郵箱")
private String email;
@ExportAnnotation(order=4,method="getGmtCreate",columnTitle="建立時間")
private Date gmtCreate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username == null ? null : username.trim();
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname == null ? null : nickname.trim();
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password == null ? null : password.trim();
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email == null ? null : email.trim();
}
public Date getGmtCreate() {
return gmtCreate;
}
public void setGmtCreate(Date gmtCreate) {
this.gmtCreate = gmtCreate;
}
}
工具類
ExcelUtil.java
package com.shz.demo.util;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.shz.demo.annotation.ExportAnnotation;
import com.shz.demo.model.admin.Users;
/**
* @author 作者:宋浩志
* @createDate 建立時間:2018年8月14日 上午10:33:04
*/
public class ExcelUtil {
private static final Logger logger = LoggerFactory.getLogger(ExcelUtil.class);
// 200rows flush
private final SXSSFWorkbook wbk = new SXSSFWorkbook(200);
// 工作簿 當前sheet
private SXSSFSheet sheet;
// 當前sheet的 當前row
private SXSSFRow row; // 成員變數接收 不用每次都在棧中宣告
// 當前cell
private SXSSFCell cell;
// 標題樣式 初始化 分配一個堆記憶體空間
private final XSSFCellStyle titleStyle = (XSSFCellStyle) this.wbk.createCellStyle();
// cell樣式
private final XSSFCellStyle cellStyle = (XSSFCellStyle) this.wbk.createCellStyle();
// row 樣式
// private final XSSFCellStyle rowStyle = (XSSFCellStyle)
// this.wbk.createCellStyle();
// cell font
// private final Font font = this.wbk.createFont();
//// 使用太耗記憶體
// private XSSFRichTextString xssfRichTextString;
// 接收cellValue 當前cellValue
private Object cellValue;
// 標題[0][] 方法名[1][]
private final String[][] titlesAndMethods = new String[2][];
// 匯出物件的 Class 物件 使用泛型獲取匯出物件的型別 只能獲取父類的泛型的型別 這裡通過構造器初始化
// Class.forName(((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName());
private final Class<?> exportClass;
public ExcelUtil(Class<?> clazz) {
this.exportClass = clazz;
if (clazz == null)
throw new NullPointerException("clazz 不能為空");
this.initTitleAndMethod(this.exportClass);
}
// 初始化 樣式
{
this.initStyle(this.titleStyle, false);
this.initStyle(this.cellStyle, true);
// this.initStyle(rowStyle,true);
}
private int count = 1;
public void exportRowSet(Object rowData) {
if (this.sheet == null) {
throw new NullPointerException("sheet 為空 , 先initSheet");
}
if (this.count % 10000 == 0) {
logger.info("==========" + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "M");
// System.runFinalization();
}
this.row = this.sheet.createRow(count);
// 第一個cell 是序號
/*{
this.cell = this.row.createCell(0);
this.cell.setCellStyle(cellStyle);
this.cell.setCellValue(count);
}*/
for (int i = 0; i < titlesAndMethods[0].length && titlesAndMethods[1][i] != null; i++) {
try {
this.cellValue = this.exportClass.getMethod(this.titlesAndMethods[1][i]).invoke(rowData);
this.cell = this.row.createCell(i);
this.createCellValue(i);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
// logger.error("匯出統計資料 反射獲取值 失敗,column:{}",i,e);
}
}
this.count++;
}
public void writeWbk(OutputStream os) {
try {
this.wbk.write(os);
} catch (IOException e) {
//
} finally {
try {
this.wbk.close();
} catch (IOException e) {
//
}
}
}
public void initSheet(String sheetName) {
this.sheet = this.wbk.createSheet(sheetName);
this.sheet.setDefaultColumnWidth((short) 16);
this.row = this.sheet.createRow(0);
this.createRowTitle();
this.count = 1;
}
private void initTitleAndMethod(Class<?> clazz) {
ExportAnnotation exportAnnotation = clazz.getAnnotation(ExportAnnotation.class);
Field[] fields = clazz.getDeclaredFields();
// 初始化 標題[0][0]
{
// 第一個title 序號
int length = exportAnnotation.length();
this.titlesAndMethods[0] = new String[length + 1];
this.titlesAndMethods[1] = new String[length + 1];
//this.titlesAndMethods[0][0] = "序號";
}
int index;
for (Field field : fields) {
exportAnnotation = field.getAnnotation(ExportAnnotation.class);
if (exportAnnotation != null) {
index = exportAnnotation.order();
// 標題
this.titlesAndMethods[0][index] = exportAnnotation.columnTitle();
this.titlesAndMethods[1][index] = exportAnnotation.method();
}
}
}
/**
* 建立標題行
*/
private void createRowTitle() {
String[] titles = titlesAndMethods[0];
for (int i = 0; i < titles.length; i++) {
this.cell = this.row.createCell(i);
this.cell.setCellStyle(this.titleStyle);
// 每次都要例項化一個 如果為final cellValue 全部相同 太耗記憶體
// this.xssfRichTextString = new XSSFRichTextString();
// this.xssfRichTextString.setString(titles[i]);
this.cell.setCellValue(titles[i]);
}
}
private void initStyle(XSSFCellStyle style, boolean isBold) {
// 設定這些樣式SOLID_FOREGROUND
/*
* style.setFillForegroundColor(HSSFColor.WHITE.index);
* style.setFillPattern(FillPatternType.SOLID_FOREGROUND); //邊框
* style.setBorderBottom(BorderStyle.NONE);
* style.setBorderLeft(BorderStyle.NONE);
* style.setBorderRight(BorderStyle.NONE); style.setBorderTop(BorderStyle.NONE);
*/
// 居中
style.setAlignment(HorizontalAlignment.CENTER);
// 生成一個字型
// XSSFFont font = (XSSFFont) this.wbk.createFont();
// font.setColor(HSSFColor.BLACK.index);
// font.setFontHeightInPoints((short) 12);
// font.setBold(isBold);
// style.setFont(font);
}
/**
* 建立 cell
*/
private void createCellValue(int columnIndex) {
this.cell.setCellStyle(this.cellStyle);
// 判斷值的型別後進行強制型別轉換
String textValue = null;
if (this.cellValue instanceof Date) {
Date date = (Date) this.cellValue;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
textValue = sdf.format(date);
} else if (this.cellValue instanceof byte[]) {
Drawing patriarch = this.sheet.createDrawingPatriarch();
// 有圖片時,設定行高為60px;
this.row.setHeightInPoints(60);
// 設定圖片所在列寬度為80px,注意這裡單位的一個換算
this.sheet.setColumnWidth(columnIndex, (short) (35.7 * 80));
// sheet.autoSizeColumn(i);
byte[] bsValue = (byte[]) this.cellValue;
ClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) 6, columnIndex, (short) 6, columnIndex);
anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_DONT_RESIZE);
patriarch.createPicture(anchor, this.wbk.addPicture(bsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));
} else {
// 其它資料型別都當作字串簡單處理
if (this.cellValue != null)
textValue = this.cellValue.toString();
}
// 如果不是圖片資料,就判斷textValue是否全部由數字組成
if (textValue != null) {
if (this.cellValue instanceof Integer) {
// double 強制轉換 會有小數點
this.cell.setCellValue((int) this.cellValue);
} else if (this.cellValue instanceof Number) {
this.cell.setCellValue((double) this.cellValue);
} else {
// 資料量大每次例項化 太耗記憶體
// this.xssfRichTextString = new XSSFRichTextString();
// this.xssfRichTextString.setString(textValue);
// this.font.setColor(new XSSFColor().getIndexed());
// this.xssfRichTextString.applyFont(font);
this.cell.setCellValue(textValue);
}
}
}
public static void main(String[] args) throws Exception {
System.out.println("=========================>>>>>" + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "M");
long start = System.currentTimeMillis();
ExcelUtil exportExcelUtil = new ExcelUtil(Users.class);
exportExcelUtil.initSheet("Sheet");
Users user;
OutputStream os = new BufferedOutputStream(new FileOutputStream(new File("c://1234.xlsx")));
for (int i = 0; i < 1000000; i++) {
user = new Users();
if(i==1) {
user.setUsername("張三");
}else {
user.setUsername("李四");
}
user.setNickname(i + "b");
user.setPassword(i + "c");
user.setEmail(i + "d");
user.setGmtCreate(getCurrentTime());
exportExcelUtil.exportRowSet(user);
}
exportExcelUtil.writeWbk(os);
long end = System.currentTimeMillis();
System.out.println("================================>>" + (end - start) + "ms");
}
public static Date getCurrentTime() throws Exception {
String str = format("yyyy-MM-dd HH:mm:ss", new Date());
Date date = parse("yyyy-MM-dd HH:mm:ss", str);
return date;
}
public static Date parse(String pattern, String str_date) throws ParseException {
DateFormat dateFormat = new SimpleDateFormat(pattern);
return dateFormat.parse(str_date);
}
public static String format(String pattern, Date date) {
DateFormat dateFormat = new SimpleDateFormat(pattern);
return dateFormat.format(date);
}
}