java导出excel支持2003、2007及SAX解析

java poi导出excel 工具,支持配置SAX导出模式以及导出excel 2003、excel 2007

首先是一个注解类
package com.wl.farmer.action.annotaion;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Administrator on 2019/9/26.
 */
@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(例子)

package com.wl.farmer.action.model;


import com.wl.farmer.action.annotaion.ExportAnnotation;
import com.wl.farmer.action.util.ExportExcelUtil;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Date;

/**
 * Created by wl
 */
@ExportAnnotation(length = 9)
public class User {

    @ExportAnnotation(order = 1,method = "getId",columnTitle = "用户id")
    private Integer id;

    @ExportAnnotation(order = 2,method = "getUserName",columnTitle = "用户名称")
    private String userName;

    @ExportAnnotation(order = 3,method = "getMobile",columnTitle = "电话号码")
    private String mobile;

    @ExportAnnotation(order = 4,method = "getEmail",columnTitle = "电子邮箱")
    private String email;

    @ExportAnnotation(order = 5,method = "getAge",columnTitle = "年龄")
    private Integer age;

    @ExportAnnotation(order = 5,method = "getCreateTime",columnTitle = "创建时间")
    private Date createTime;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    
}

真正的工具类

package com.wl.farmer.action.util;

import com.wl.farmer.action.annotaion.ExportAnnotation;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by wl
 */
public class ExportExcelUtil{

    private static final Logger logger = LoggerFactory.getLogger(ExportExcelUtil.class);

    private final Workbook wbk;

    private Sheet sheet;

    private Row row;

    private Cell cell;

    private final CellStyle titleStyle;

    private final CellStyle cellStyle;

    private Object cellValue;

    //标题[0][]   方法名[1][]
    private final String[][] titlesAndMethods = new String[2][];

    private final Class exportClass;

    private ExportExcelUtil(Builder builder){
        this.exportClass = builder.targetClass;
        if(builder.isSax){
            this.wbk = new SXSSFWorkbook(builder.rowAccessWindowSize);
        }else if(builder.is2003){
            this.wbk = new HSSFWorkbook();
        }else{
            this.wbk = new XSSFWorkbook();
        }
        this.titleStyle = this.wbk.createCellStyle();
        this.cellStyle = this.wbk.createCellStyle();
        //样式
        this.initStyle(this.titleStyle,false);
        this.initStyle(this.cellStyle,true);
        this.initTitleAndMethod(this.exportClass);

    }


    private int count = 1;

    private static final int MAX_ROW_NUM_2003 = 2000 + 1;

    private static final int MAX_ROW_NUM_2007 = 20000 + 1;

    public void exportRowSet(Object rowData) {
        if(this.sheet ==null){
            throw new NullPointerException("sheet 为空 , 先initSheet");
        }

        if(this.wbk instanceof HSSFWorkbook){
            if(this.count % MAX_ROW_NUM_2003 == 0){
                this.initSheet(this.wbk.getSheetName(0) + (this.wbk.getSheetIndex(sheet) + 1));
            }
        }else {
            if(this.count % MAX_ROW_NUM_2007 == 0){
                this.initSheet(this.wbk.getSheetName(0) + (this.wbk.getSheetIndex(sheet) + 1));
            }
        }

        if(this.count % 10000 == 0){
            logger.info("=========="+Runtime.getRuntime().totalMemory()/1024/1024+"M");
            //System.runFinalization();
        }

        this.row = this.sheet.createRow(count);

        for(int i=0;i 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 targetClass;

        /**
         * 导出类型是否是excel 2003
         */
        private boolean is2003 = false;

        /**
         * 是否是Sax方式导入
         */
        private boolean isSax = false;

        private int rowAccessWindowSize = 100;



        public Class getTargetClass() {
            return targetClass;
        }

        private Builder setTargetClass(Class targetClass) {
            this.targetClass = targetClass;
            return this;
        }

        public Builder setIs2003(boolean is2003) {
            this.is2003 = is2003;
            return this;
        }

        public Builder setSax(boolean sax) {
            this.isSax = sax;
            return this;
        }

        public Builder setRowAccessWindowSize(int rowAccessWindowSize) {
            this.rowAccessWindowSize = rowAccessWindowSize;
            return this;
        }

        public static Builder create(Class targetClass){
            if(targetClass == null){
                throw new NullPointerException();
            }
            return new Builder().setTargetClass(targetClass);
        }


        public ExportExcelUtil build(){
            if(this.isSax){
                if(this.is2003){
                    throw new UnsupportedOperationException("excel2003不支持sax解析方式");
                }
            }
            return new ExportExcelUtil(this);
        }
    }

    public String getExcelSuffix(){
        if(this.wbk instanceof HSSFWorkbook){
            return ".xls";
        }
        return ".xlsx";
    }

}


下面贴一下工具使用方法
1.实例化工具类(可以配置SAX解析)

ExportExcelUtil excelUtil = ExportExcelUtil.Builder.create(User.class).setIs2003(false).build();

2.初始化sheet

excelUtil.initSheet("用户列表");

3.填充数据

for(int i = 0; i <1000;i++){
            User user = new User();
            user.setId(i+1);
            user.setAge(18);
            user.setCreateTime(new Date());
            user.setEmail("***@123.com");
            user.setMobile("***");
            user.setUserName("wl");
            excelUtil.exportRowSet(user);
        }

导出excel

excelUtil.writeWbk(new FileOutputStream(new File("user" + excelUtil.getExcelSuffix())));

下面是我的测试代码(导出10万条数据)

public static void main(String[] args) throws FileNotFoundException {
        ExportExcelUtil excelUtil = ExportExcelUtil.Builder.create(User.class).setIs2003(false).setSax(true).setRowAccessWindowSize(50000).build();
        excelUtil.initSheet("用户列表");
        for(int i = 0; i <100000;i++){
            User user = new User();
            user.setId(i+1);
            user.setAge(18);
            user.setCreateTime(new Date());
            user.setEmail("***@123.com");
            user.setMobile("***");
            user.setUserName("wl");
            excelUtil.exportRowSet(user);
        }
        excelUtil.writeWbk(new FileOutputStream(new File("user" + excelUtil.getExcelSuffix())));
    }

打印的内存使用情况如下

Connected to the target VM, address: '127.0.0.1:60590', transport: 'socket'
22:22:38.173 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========245M
22:22:38.282 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========245M
22:22:38.345 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========245M
22:22:38.413 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========245M
22:22:38.475 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========309M
22:22:38.522 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========309M
22:22:38.569 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========309M
22:22:38.647 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========309M
22:22:38.694 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========309M
22:22:38.725 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========309M
Disconnected from the target VM, address: '127.0.0.1:60590', transport: 'socket'

下面我们不采用sax解析

public static void main(String[] args) throws FileNotFoundException {
        ExportExcelUtil excelUtil = ExportExcelUtil.Builder.create(User.class).setIs2003(false).setSax(false).build();
        excelUtil.initSheet("用户列表");
        for(int i = 0; i <100000;i++){
            User user = new User();
            user.setId(i+1);
            user.setAge(18);
            user.setCreateTime(new Date());
            user.setEmail("***@123.com");
            user.setMobile("***");
            user.setUserName("wl");
            excelUtil.exportRowSet(user);
        }
        excelUtil.writeWbk(new FileOutputStream(new File("user" + excelUtil.getExcelSuffix())));
    }
Connected to the target VM, address: '127.0.0.1:60603', transport: 'socket'
22:24:03.762 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========448M
22:24:04.262 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========706M
22:24:04.770 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========716M
22:24:05.130 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========1024M
22:24:06.458 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========1189M
22:24:06.817 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========1317M
22:24:07.130 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========1317M
22:24:08.370 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========1785M
22:24:08.807 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========1790M
22:24:09.104 [main] INFO com.wl.farmer.action.util.ExportExcelUtil - ==========1790M
Disconnected from the target VM, address: '127.0.0.1:60603', transport: 'socket'

可以看到不仅解析缓慢,而且使用内存巨大
导出文件如下
java导出excel支持2003、2007及SAX解析_第1张图片
使用模板
在工具类中加入模板代码

public static class ExportTemplate {

        public Result executeExport(ExportCallBackHandler exportCallBackHandler) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                //doSomething
                //回调
                return exportCallBackHandler.processExport(bos);
                //doSomething
            } catch (IOException | RuntimeException e) {
                logger.error(e.getMessage(),e);
                return Result.fail(e.getMessage());
            } finally {
                IOUtils.closeQuietly(bos);

            }
        }

        //回调接口
        public interface ExportCallBackHandler {
            Result processExport(ByteArrayOutputStream bos) throws IOException;
        }
    }

需要引入commons-io包和Result类

package com.wl.farmer.action.model;

import java.io.Serializable;

/**
 * Created by Administrator on 2019/2/20.
 */
public class Result {
    private Integer code;

    private String msg;

    private T body;

    public Integer getCode() {
        return code;
    }

    private void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    private void setMsg(String msg) {
        this.msg = msg;
    }

    public T getBody() {
        return body;
    }

    private void setBody(T body) {
        this.body = body;
    }

    private static class Builder{
        private Integer code;

        private String msg;

        private T body;

        private Builder body(T body){
            this.body = body;
            return this;
        }

        private Builder code(Integer code){
            this.code = code;
            return this;
        }

        private Builder msg(String msg){
            this.msg = msg;
            return this;
        }

        private static   Builder custom(T body){
            return new Builder().body(body);
        }

        private Result build(){
            Result result = new Result<>();
            result.setBody(this.body);
            result.setCode(this.code);
            result.setMsg(this.msg);
            return result;
        }
    }

    public static  Result success(T t ,String msg){
        return Builder.custom(t).code(Code.SUCCESS.CODE).msg(msg).build();
    }

    public static  Result success(T t){
        return success(t, Code.SUCCESS.MSG);
    }

    public static  Result success(){
        return success(null, Code.SUCCESS.MSG);
    }

    public static  Result success(String msg){
        return success(null,msg);
    }

    //==================================================================

    public static  Result fail(T t ,String msg){
        return Builder.custom(t).code(Code.FAILED.CODE).msg(msg).build();
    }

    public static  Result fail(T t){
        return fail(t, Code.FAILED.MSG);
    }

    public static  Result fail(){
        return fail(null, Code.FAILED.MSG);
    }

    public static  Result fail(String msg){
        return fail(null,msg);
    }

    public enum Code implements Serializable{
        SUCCESS("成功"),
        FAILED("失败");
        public final String MSG;
        Code(String msg){
            this.MSG = msg;
        }
        public final Integer CODE = this.ordinal();
    }
}

测试代码

public static void main(String[] args) throws FileNotFoundException {
        ExportExcelUtil excelUtil = ExportExcelUtil.Builder.create(User.class).setIs2003(false).setSax(true).setRowAccessWindowSize(50000).build();
        Result result = new ExportExcelUtil.ExportTemplate().executeExport(new ExportExcelUtil.ExportTemplate.ExportCallBackHandler() {
            @Override
            public Result processExport(ByteArrayOutputStream bos) throws IOException {
                excelUtil.initSheet("用户列表");
                for(int i = 0; i <100000;i++){
                    User user = new User();
                    user.setId(i+1);
                    user.setAge(18);
                    user.setCreateTime(new Date());
                    user.setEmail("***@123.com");
                    user.setMobile("***");
                    user.setUserName("wl");
                    excelUtil.exportRowSet(user);
                }
                excelUtil.writeWbk(bos);
                //处理bos
                IOUtils.copy(new ByteArrayInputStream(bos.toByteArray()),new FileOutputStream("用户列表" + excelUtil.getExcelSuffix()));
                return Result.success();
            }
        });
        System.out.println(result.getMsg());

    }

你可能感兴趣的:(java)