java POI excel導出百萬條數據

首先新建一個註解類

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);
    }
}

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

參考:https://blog.csdn.net/name_is_wl/article/details/78138565

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章