美文网首页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