美文网首页Java 杂谈
阿里的easyexcel使用 web下载 设置样式

阿里的easyexcel使用 web下载 设置样式

作者: eye33 | 来源:发表于2019-06-20 10:06 被阅读3次

alibaba开发的快速、简单避免OOM的java处理Excel工具

文档:https://github.com/alibaba/easyexcel
在查阅了网上的各种实现方法结合poi的使用经验,综合研究测试后,封装一套方法,与各位探讨学习.
遗憾的是没有弄出冻结窗格的方法,poi中的方法如下,如有哪位可以实现easyexcel冻结的方法,望分享.

XSSFSheet sheet= workbook.createSheet(sheetName);
sheet.createFreezePane(0,1);

以下是service层的下载执行:设置表头,表内容,样式

/**
     * 下载信息
     * @param hm
     */
    private void downInfo(HashMap hm) {
        String[] hearArr = new String[] {"身份证号","金额","信息","状态","生日","性别","照片","创建时间"};
        String[] orderArr = new String[] {"CERT_NO","AMOUNT","INFO","STATUS","BIRTHDAY","GENDER","HASPHOTO","CREATETIME"};
        List<String> orderList = Arrays.asList(orderArr);
        //4000对应Excel列宽的值15.5
        Integer[] widthArr = new Integer[] {5200,1600,5200,1600,2900,1600,1600,5500};
        
        Sheet sheet = new Sheet(1);//第1张sheet
        sheet.setHead(ExcelUtil.createHead(hearArr));
        sheet.setSheetName("sheet1");
        //sheet.setAutoWidth(true);//默认的自动列宽,非自适应
        sheet.setColumnWidthMap(ExcelUtil.setColunmWidth(widthArr));
        
        Map<Integer,CellStyleEnum> styleMap = new HashMap();
        styleMap.put(-1, CellStyleEnum.DEFAULT_HEAD);
        styleMap.put(1, CellStyleEnum.AMOUNT_FORMAT);
        
        List<HashMap<String, Object>> resultList = service.queryInfo(hm);
        ExcelUtil.downExcel(response,"测试信息" + Tool.getNowStr(),sheet,ExcelUtil.createData(resultList,orderList),styleMap);
    }

以下是CellStyleEnum类,直观的绑定样式名称和样式方法,便于自定义各种样式

/**
 * 单元格样式类
 * @author Administrator
 *
 */
public enum CellStyleEnum{
    //暂定以下几种格式,如有需要再扩充
    DEFAULT_HEAD("默认标题行样式","defaultHeadLineStyle"),
    NORMAL("四周细边框", "normalStyle"),
    AMOUNT_FORMAT("金额数字类型0.00", "amountFormat"),
    INTEGER_FORMAT("整数数字类型0","integerFormat"),
    RED_FONT("红色字体","redFont");
    
    // 成员变量
    private String name;
    private String methodName;

    /**
     * 构造方法
     * @param name 名称
     * @param methodName ExcelUtil.ExcelStyleHandler对应的方法名
     */
    private CellStyleEnum(String name, String methodName) {
        this.name = name;
        this.methodName = methodName;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }


}

以下是ExcelUtil类,封装了excel下载所需功能

import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.event.WriteHandler;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.ExcelBuilderImpl;

/**
 * 基于alibaba的easyexcel的Excel工具类
 * 优点:相对于poi,极大的减小内存消耗,并避免oom问题
 * 文档:https://github.com/alibaba/easyexcel
 * @author Administrator
 *
 */
@SuppressWarnings({"unchecked","unused"})
public class ExcelUtil {
    
    private static Logger logger = Logger.getLogger(ExcelUtil.class);
    
    
    /**
     * 每个单元格在写入前,都会调用本处理器
     * 线程安全的单例模式
     * @author Administrator
     *
     */
    private static class ExcelStyleHandler implements WriteHandler{
        Cell cellObj = null;
        Workbook workbook = null;
        CellStyle cellStyle = null;
        DataFormat dataFormat = null;
        org.apache.poi.ss.usermodel.Font font = null;
        
        /**
         * key-列号/行号 ,>=0:列号, -1:单标题行第一行,其他特殊类型可以按需设定
         * value-设置样式的方法名,详见CellStyleEnum类的设置
         */
        Map<Integer,CellStyleEnum> styleMap = null;
        private static ExcelStyleHandler instance;
        /** 私有化构造器 */
        private ExcelStyleHandler() {}
        /** 获取单例 */
        public static ExcelStyleHandler getInstance() {
            if(null == instance) {
                synchronized(ExcelStyleHandler.class) {
                    if(null == instance) {
                        instance= new ExcelStyleHandler();
                    }
                }
            }
            return instance;
        }
        
        @Override
        public void cell(int i, Cell cell) {
            try {
                cellObj = cell; 
                workbook = cell.getSheet().getWorkbook();
                cellStyle = workbook.createCellStyle();
                dataFormat = workbook.createDataFormat();
                font = workbook.createFont();
                
                int rowIndex = cell.getRowIndex();
                
                //设置标题行格式
                if(rowIndex == 0) {
                    String methodName = styleMap.get(-1).getMethodName();
                    if(methodName != null) {
                        ExcelStyleHandler.class.getDeclaredMethod(methodName).invoke(getInstance());
                    }
                    //defaultHeadLineStyle();
                }
                
                //设置列内容格式
                if(rowIndex > 0) {
                    normalStyle();//设置细线框
                    //设置指定列样式
                    for (Integer key : styleMap.keySet()) {
                        if(key >= 0 && key == i) {//仅设置列的样式
                            ExcelStyleHandler.class.getDeclaredMethod(styleMap.get(key).getMethodName()).invoke(getInstance());
                        }
                    }
                }
                cell.setCellStyle(cellStyle);
            }catch(Exception e){
                throw new RuntimeException(e.getMessage());
            }
        }

        /**
         * 去除成员变量绑定的对象,释放内存
         */
        private void release() {
            cellObj = null;
            workbook = null;
            cellStyle = null;
            dataFormat = null;
            font = null;
        }
        
        /**
         * 金额0.00格式
         * @param cell
         * @param cellStyle
         * @param dataFormat
         */
        private void amountFormat() {
            cellObj.setCellValue(Double.parseDouble(cellObj.getStringCellValue()));
            cellStyle.setDataFormat(dataFormat.getFormat("0.00"));
        }
        
        /**
         * 整数0格式
         * @param cell
         * @param cellStyle
         * @param dataFormat
         */
        private void integerFormat() {
            cellObj.setCellValue(Double.parseDouble(cellObj.getStringCellValue()));
            cellStyle.setDataFormat(dataFormat.getFormat("0"));
        }

        /**
         * 默认标题行样式
         * @param cellStyle
         * @param font
         */
        private void defaultHeadLineStyle() {
            normalStyle();
            middleStyle();
            fillColorStyle(IndexedColors.AQUA.getIndex());
            font.setBold(true);
            font.setFontHeightInPoints((short) 14);
            cellStyle.setFont(font);
        }

        /**
         * 红色字体
         * @param cellStyle
         * @param font
         */
        private void redFont() {
            font.setColor(IndexedColors.RED.getIndex());
            cellStyle.setFont(font);
        }
        
        /**
         * 字体颜色设置
         * @param cellStyle
         * @param font
         */
        private void fontColorStyle(short color) {
            font.setColor(color);
            cellStyle.setFont(font);
        }

        /**
         * 填充色设置
         * @param cellStyle
         * @param color
         */
        private void fillColorStyle(short color) {
            cellStyle.setFillForegroundColor(color);
            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        }

        /**
         * 水平垂直居中
         * @param cellStyle
         */
        private void middleStyle() {
            cellStyle.setAlignment(HorizontalAlignment.CENTER);
            cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        }

        /**
         * 常规-四周细边框
         * @param cellStyle
         */
        private void normalStyle() {
            cellStyle.setBorderBottom(BorderStyle.THIN);
            cellStyle.setBorderLeft(BorderStyle.THIN);
            cellStyle.setBorderRight(BorderStyle.THIN);
            cellStyle.setBorderTop(BorderStyle.THIN);
        }

        @Override
        public void row(int i, Row row) {}

        @Override
        public void sheet(int i, org.apache.poi.ss.usermodel.Sheet sheet) {}
        
    }
    
    /**
     * 导出单张Sheet的Excel
     * @param response HttpServletResponse
     * @param fileName 文件名
     * @param sheet Sheet
     * @param data Sheet中的内容
     * @param styleMap
     */
    public static void downExcel(HttpServletResponse response,String fileName,Sheet sheet,List<List<Object>> data,Map<Integer,CellStyleEnum> styleMap) {
         try (ServletOutputStream out = response.getOutputStream()){////java7新特性 在try()语句的括号里声明和初始化资源 会对实现了Closeable的接口会自动关闭
             fileName = URLEncoder.encode(fileName, "UTF-8");
             response.setContentType("multipart/form-data");
             response.setCharacterEncoding("utf-8");
             response.setHeader("Content-disposition", "attachment;filename="+fileName+".xlsx");
            
             synchronized (ExcelStyleHandler.getInstance()){//保证并发时的线程安全,数据不被污染
                 ExcelStyleHandler handler = ExcelStyleHandler.getInstance();
                 handler.styleMap = styleMap;
                 ExcelWriter writer = new ExcelWriter(null,out, ExcelTypeEnum.XLSX, true,handler);
                 Workbook workbook = getWorkbook(writer);
                 //要写多个sheet就多次执行write方法(暂时不用,就不做改造)
                 writer.write1(data, sheet);
                 //必须要调用finish(),否则数据不会写入文件
                 writer.finish();
                 out.flush();
                 handler.release();
             }
        } catch (Exception e) {
            throw new RuntimeException("导出excel表格失败!" + e.getMessage());
        }
    }
    
    /**
     * 创建Excel标题行
     * @param arr
     * @return
     */
    public static List<List<String>> createHead(String[] arr){
        List<List<String>> head = new ArrayList();
        List<String> headCol = null;
        for (String colName : arr) {
            headCol = new ArrayList() ;
            headCol.add(colName);
            head.add(headCol);//每加一次,就增加一列标题 
        }
        return head;
    }
    
    /**
     * 创建Excel内容
     * @param list 数据集合
     * @param order map.key的顺序
     * @return
     */
    public static List<List<Object>> createData(List<HashMap<String,Object>> list,List<String> order){
        List<List<Object>> data = new ArrayList();
        List<Object> dataLine = null;
        Iterator<Map.Entry<String, Object>> it = null;
        String key = null;
        Object value = null;
        int size = order.size();
        Entry<String, Object> next = null;
        int index = -1;
        for (HashMap<String,Object> map : list) {
            dataLine = Arrays.asList(new Object[size]);//该方法初始化的集合,可以根据下标添加元素时不报越界的错误
            it = map.entrySet().iterator();
            while(it.hasNext()) {
                next = it.next();
                key = next.getKey();
                value = next.getValue();
                index = order.indexOf(key);
                if(index > -1) {//存在所需的字段,则加入
                    dataLine.set(index, value);
                }
            }
            data.add(dataLine);
        }
        return data;
    }
    
    /**
     * 设置指定列的列宽
     * @param widthArr
     * @return
     */
    public static Map<Integer, Integer> setColunmWidth(Integer[] widthArr){
        Map<Integer, Integer> columnWidthMap = new HashMap();
        for (int i = 0; i < widthArr.length; i++) {
            columnWidthMap.put(i, widthArr[i]);
        }
        return columnWidthMap;
    }
    
    /**
     * 获取Workbook对象
     * @param writer
     * @return
     */
    private static Workbook getWorkbook(ExcelWriter writer) {
        Workbook workbook = null;
        try {
            Class<?> clazz1 = Class.forName("com.alibaba.excel.ExcelWriter");
            Field[] fs = clazz1.getDeclaredFields();
            for (Field field : fs) {
                //要设置属性可达,不然会抛出IllegalAccessException异常
                field.setAccessible(true);
                if ("excelBuilder".equals(field.getName())) {
                    ExcelBuilderImpl excelBuilder = (ExcelBuilderImpl) field.get(writer);
                    Class<?> clazz2 = Class.forName("com.alibaba.excel.write.ExcelBuilderImpl");
                    Field[] fs2 = clazz2.getDeclaredFields();
                    for (Field field2 : fs2) {
                        field2.setAccessible(true);
                        if ("context".equals(field2.getName())) {
                            WriteContext context = (WriteContext) field2.get(excelBuilder);
                            workbook = context.getWorkbook();
                        }
                        break;
                    }
                }
                break;
            }
        } catch (Exception e) {
            throw new RuntimeException("获取Wookbook失败!" + e.getMessage());
        }
        return workbook;
    }
    
    
    
}

相关文章

网友评论

    本文标题:阿里的easyexcel使用 web下载 设置样式

    本文链接:https://www.haomeiwen.com/subject/acxdqctx.html