0
点赞
收藏
分享

微信扫一扫

自定义POI的excel工具类-xls-xlsx

北邮郭大宝 2022-03-24 阅读 76

自定义POI的excel工具类-xls-xlsx

jdk版本

java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

在这里插入图片描述

maven版本

Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: D:\_frame\apache-maven-3.6.3\bin\..
Java version: 1.8.0_151, vendor: Oracle Corporation, runtime: D:\_language\jdk1.8.0_151_64\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

在这里插入图片描述

pom

<springboot.version>2.0.9.RELEASE</springboot.version>
<springframework.version>5.0.13.RELEASE</springframework.version>
<poi.varsion>3.17</poi.varsion>
<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-web</artifactId>
     <version>${springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.8.1</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.60</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>${poi.varsion}</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>${poi.varsion}</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>QLExpress</artifactId>
    <version>3.2.3</version>
</dependency>

工具代码

package ***.utils;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * Excel 简单工具类
 *
 * @author z.y.l
 * @version v1.0
 */
public class ExcelKit {
    private static final Logger log = LoggerFactory.getLogger(ExcelKit.class);

    public static void exportExcel03(HttpServletResponse response,Consumer<PoiBean> consumer) throws Exception {
        log.info("poi导出工具类,生成03版excel-start");
        PoiBean poiBean = generate(new HSSFWorkbook(),consumer);
        export(response,poiBean);
        log.info("poi导出工具类,生成03版excel-end");
    }
    public static void exportExcel07(HttpServletResponse response,Consumer<PoiBean> consumer) throws Exception {
        log.info("poi导出工具类,生成07版excel-start");
        PoiBean poiBean = generate(new XSSFWorkbook(),consumer);
        export(response,poiBean);
        log.info("poi导出工具类,生成07版excel-start");
    }
    public static void fail(HttpServletResponse response,String message) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=UTF-8");
        Map<String, Object> map = new HashMap<>(4);
        map.put("code",-1);
        map.put("message",message);
        PrintWriter writer = response.getWriter();
        writer.append(JSONObject.toJSONString(map));
        writer.flush();
        IOUtils.closeQuietly(writer);
    }
    private static void export(HttpServletResponse response, PoiBean poiBean) throws IOException {
        String name = URLEncoder.encode(poiBean.getFileName(),"UTF-8") + (poiBean.varIs03 ? ".xls":".xlsx");
        log.debug("生成结束,开始下载:{}",name);
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename="+ name);
        log.debug("生成结束,开始写入流");
        poiBean.workbook.write(response.getOutputStream());
        response.getOutputStream().flush();
        IOUtils.closeQuietly(response.getOutputStream());
    }
    private static PoiBean generate(Workbook workbook, Consumer<PoiBean> consumer){
        PoiBean poiBean = new PoiBean(System.currentTimeMillis());
        poiBean.workbook = workbook;
        log.debug("{},开始生成,sheet个数:{}",poiBean.time,poiBean.workbook.getNumberOfSheets());
        if(poiBean.workbook.getNumberOfSheets() <= 0){
            poiBean.sheet = poiBean.workbook.createSheet("sheet1");
            poiBean.row = poiBean.sheet.createRow(0);
            poiBean.cell = poiBean.row.createCell(0);
            log.debug("{},开始生成,创建sheet1",poiBean.time);
        }else {
            poiBean.row = poiBean.sheet.getRow(0);
            poiBean.cell = poiBean.row.getCell(0);
        }
        poiBean.varIs03 = workbook instanceof HSSFWorkbook;
        log.debug("{},开始生成>>>lambda,是否03版:{}",poiBean.time,poiBean.varIs03);
        consumer.accept(poiBean);
        log.debug("{},结束生成>>>lambda",poiBean.time);
        return poiBean;
    }

    public static class PoiBean{
        private final long time;
        /** 设置 文件名称 不含后缀 */
        String fileName;
        /** 文件格式 是否03版 xls */
        boolean varIs03;
        /** excel工作表对象 */
        Workbook workbook;
        /** excel工作表sheet页对象 */
        Sheet sheet;
        Row row;
        Cell cell;
        CellStyle cellStyle;
        /** 07版 xssf BUG 设置 setDefaultColumnStyle默认cellStyle 无效,需要单独处理 */
        List<CellStyle> styleList;
        PoiBean(long time){ this.time = time; }
        public PoiBean setFileName(String fileName) { this.fileName = fileName;return this; }
        public String getFileName() { return StringUtils.isEmpty(fileName)?"文件导出"+System.currentTimeMillis():fileName; }

        /** 创建 字体, 单元格 赋值使用 */
        public Font initNewFont(Consumer<FontBean> consumer){
            log.debug("{},创建新字体>>>lambda",time);
            Font font = workbook.createFont();
            FontBean bean = new FontBean(font);
            consumer.accept(bean);
            log.debug("{},创建新字体<<<lambda",time);
            return font;
        }
        /** 创建 单元格样式, 单元格 赋值使用 */
        public CellStyle initNewStyle(Consumer<StyleBean> consumer){
            log.debug("{},创建新样式>>>lambda",time);
            CellStyle style = workbook.createCellStyle();
            StyleBean bean = new StyleBean(style,workbook);
            consumer.accept(bean);
            log.debug("{},创建新样式<<<lambda",time);
            return style;
        }
        /** 设置 当前单元格样式 */
        public PoiBean nowCellStyle(Consumer<StyleBean> consumer){
            log.debug("{},设置当前样式>>>lambda",time);
            consumer.accept(new StyleBean(cell.getCellStyle(),workbook));
            log.debug("{},设置当前样式<<<lambda",time);
            return this;
        }
        /** 创建单元格样式,并赋值当前单元格 */
        public PoiBean newCellStyle(Consumer<StyleBean> consumer){
            log.debug("{},设置新样式>>>lambda",time);
            cellStyle = workbook.createCellStyle();
            consumer.accept(new StyleBean(cellStyle,workbook));
            log.debug("{},设置新样式<<<lambda",time);
            return this;
        }
        /** 设置 Workbook Sheet */
        public void init(BiConsumer<Workbook,Sheet> consumer){
            log.debug("{},设置 workbook sheet >>>lambda",time);
            consumer.accept(workbook, sheet);
            log.debug("{},设置 workbook sheet <<<lambda",time);
        }
        public PoiBean columnsWidth(Integer... widths){
            if (widths != null && widths.length > 0) {
                for (int i = 0,l = widths.length; i < l; i++) {
                    if( null == widths[i]){ continue; }
                    sheet.setColumnWidth(i,Math.max(0,widths[i])*256);
                }
            }
            return this;
        }
        /** 根据 列下标 批量 设置单元格 样式,需要格式化 内容的列 formatMap,需要设置公共样式的所有列 columns,consumer 可以自定义 样式 */
        public PoiBean columnsFormat(Map<String, int[]> formatMap, int[] columns, Consumer<StyleBean> consumer){
            if( null == formatMap || null == columns || null == consumer ){ return this; }
            Map<Integer, String> map = new TreeMap<>();
            formatMap.forEach((k,vs)->{ for (int v : vs) { map.put(v,k); } });
            CellStyle cs = workbook.createCellStyle();
            // 设置公共样式
            log.debug("{},批量设置 公共样式 >>>lambda,{}",time,formatMap.keySet());
            consumer.accept(new StyleBean(cs,workbook));
            log.debug("{},批量设置 格式化+公共样式 >>>,{}",time,map);
            styleList = new ArrayList<>(columns.length);
            CellStyle cellStyle;
            for (int column : columns) {
                cellStyle = workbook.createCellStyle();
                cellStyle.cloneStyleFrom(cs);
                if(map.containsKey(column)){
                    cellStyle.setDataFormat(workbook.createDataFormat().getFormat(map.get(column)));
                }
                sheet.setDefaultColumnStyle(column,cellStyle);
                styleList.add(cellStyle);
            }
            log.debug("{},批量设置 格式化+公共样式 <<<",time);
            return this;
        }
        /** 设置 Sheet 名称 */
        public PoiBean sheetName(String name){
            log.debug("{},修改sheet名 <<< {}",time,name);
            workbook.setSheetName(workbook.getActiveSheetIndex(),name);
            return this;
        }

        /** 合并单元格,赋值,rowMerge 合并行数 cellMerge 合并列数 */
        public PoiBean merge(int rowMerge,int cellMerge){
            int r = row.getRowNum(),c = cell.getColumnIndex();
            log.debug("{},合并单元格,行:{}+{},列:{}+{}",time,r,rowMerge,c,cellMerge);
            sheet.addMergedRegion(new CellRangeAddress(r,r + rowMerge,c,c + cellMerge));
            return this;
        }
        /** 批量设置 内容,ditto true 样式跟随 this.cellStyle; false 使用默认样式 */
        public void vs(boolean ditto,String... values){
            vls(ditto,values);
        }
        /** 批量设置 内容,ditto true 样式跟随 this.cellStyle; false 使用默认样式 */
        public void vls(boolean ditto,String[] values){
            if( null == values || values.length <= 0 ){ return; }
            for (String val : values) {
                cellNext().thisVal(ditto,val);
            }
        }
        public PoiBean val(int cellIndex, String val){
            cell(cellIndex);
            return thisVal(val);
        }
        public PoiBean val(int rowIndex,int cellIndex,String val){ row(rowIndex);return val(cellIndex,val); }
        public PoiBean index(int rowIndex,int cellIndex){ row(rowIndex);cell(cellIndex);return this; }
        /** 当前单元格赋值 */
        public PoiBean thisVal(String val){
            cell.setCellType(CellType.STRING);
            cell.setCellValue(( null == val || val.length() <= 0 ) ? "": val);
            return this;
        }
        public void thisVal(boolean ditto, String val){
            cell.setCellType(CellType.STRING);
            cell.setCellValue(( null == val || val.length() <= 0 ) ? "": val);
            ditto(ditto);
        }
        /** ditto true 样式跟随 this.cellStyle; false 使用默认样式 */
        private void ditto(boolean ditto){
            if(ditto && null != cellStyle){
                cell.setCellStyle(cellStyle);
            }else if (!ditto && !varIs03 && null != styleList){
                // 解决 07版 单元格 默认格式 赋值后丢失问题
                int index = cell.getColumnIndex();
                if(styleList.size() > index){
                    cell.setCellStyle(styleList.get(index));
                }
            }
        }

        private void sheet(int index){
            log.debug("{},sheet : {}",time,index);
            if(null == (sheet = workbook.getSheetAt(index))){ sheet = workbook.createSheet(); }
        }
        private void row(int index){
            log.debug("{},row : {}",time,index);
            index = Math.max(0,index);
            if(null == (row = sheet.getRow(index))){ row = sheet.createRow(index); }
        }
        private void cell(int index){
            log.debug("{},cell : {}",time,index);
            index = Math.max(0,index);
            if(null == (cell = row.getCell(index))){ cell = row.createCell(index); }
        }
        public PoiBean sheetNext(){ sheet(workbook.getActiveSheetIndex() + 1); return this; }
        public PoiBean rowNext(){ row(sheet.getLastRowNum() + 1); return this; }
        public PoiBean rowNext(int skip){ row(sheet.getLastRowNum() + skip); return this; }
        public PoiBean cellNext(){ cell(row.getLastCellNum()); return this; }
        public PoiBean cellNext(int skip){ cell(row.getLastCellNum() + skip); return this; }
    }
    public static class FontBean{
        private final Font font;
        FontBean(Font font){ this.font = font; }
        /** 颜色,默认 HSSFColor.AUTOMATIC;XSSF IndexedColors.BLACK */
        public FontBean color(IndexedColors val){ font.setColor(val.getIndex()); return this; }
        /** 斜体,默认 false */
        public FontBean italic(boolean val){ font.setItalic(val); return this; }
        /** 字体名称,默认 HSSF Arial;XSSF Calibri */
        public FontBean fontName(String val){ font.setFontName(val); return this; }
        /** 下划线,默认 HSSF NONE;XSSF NONE */
        public FontBean underline(FontUnderline val){ font.setUnderline(val.getByteValue()); return this; }
        /** 下划线,默认 false */
        public FontBean bold(boolean val){ font.setBold(val); return this; }
        /** 删除线,默认 false */
        public FontBean strikeout(boolean val){ font.setStrikeout(val); return this; }
        /** 字体大小-字号,默认  11 */
        public FontBean fontHeight(int val){ font.setFontHeightInPoints((short)val); return this; }
        /** 普通 NONE 0、超级 SUPER 1、下标 SUB 2 */
        public FontBean typeOffset(int val){ font.setTypeOffset((short) val); return this; }
        /** 字符集,ANSI 0、DEFAULT 1、SYMBOL 2 */
        public FontBean charSet(int val){ font.setCharSet(val); return this; }
    }
    public static class StyleBean{
        private final CellStyle style;
        private DataFormat format;
        private final Workbook workbook;
        StyleBean(CellStyle style,Workbook workbook){ this.style = style; this.workbook = workbook; }
        /** 单元格-字体 */
        public StyleBean font(Font font){ style.setFont(font);return this; }
        /** 单元格-锁定,默认 false */
        public StyleBean locked(boolean val){ style.setLocked(val);return this; }
        /** 单元格-隐藏,默认 false */
        public StyleBean hidden(boolean val){ style.setHidden(val);return this; }
        /** 单元格-值 格式化,默认 TEXT、@,如果没有 就会追加,最大可创建 250-164=86个 */
        public StyleBean dataFormat(String val){
            if( null == format ){ this.format = workbook.createDataFormat(); }
            style.setDataFormat(format.getFormat(val));
            return this;
        }
        /** 单元格-水平对齐类型 */
        public StyleBean alignment(HorizontalAlignment val){ style.setAlignment(val);return this; }
        /** 单元格-垂直对齐类型 */
        public StyleBean vertical(VerticalAlignment val){ style.setVerticalAlignment(val);return this; }
        /** 单元格-边框 批量设置 顶、底、左、右 */
        public StyleBean border(BorderStyle val,Border... borders){
            if( null != val && null != borders ){
                for (Border border : borders) {
                    if( null == border ){ continue; }
                    switch (border){
                        case TOP: style.setBorderTop(val); break;
                        case BOTTOM: style.setBorderBottom(val); break;
                        case LEFT: style.setBorderLeft(val); break;
                        case RIGHT: style.setBorderRight(val); break;
                        default: break;
                    }
                }
            }
            return this;
        }
        /** 单元格-边框 批量 色 顶、底、左、右 */
        public StyleBean borderColor(IndexedColors val,Border... borders){
            if( null != val && null != borders ){
                for (Border border : borders) {
                    if( null == border ){ continue; }
                    switch (border){
                        case TOP: style.setTopBorderColor(val.getIndex()); break;
                        case BOTTOM: style.setBottomBorderColor(val.getIndex()); break;
                        case LEFT: style.setLeftBorderColor(val.getIndex()); break;
                        case RIGHT: style.setRightBorderColor(val.getIndex()); break;
                        default: break;
                    }
                }
            }
            return this;
        }
        /** 单元格-自动换行 */
        public StyleBean wrap(boolean val){ style.setWrapText(val);return this; }
        /** 单元格-列宽 true,则按比例初始化。false,则使用 colModel指定的宽 */
        public StyleBean shrinkToFit(boolean val){ style.setShrinkToFit(val);return this; }
        /** 单元格-旋转 */
        public StyleBean rotation(short val){ style.setRotation(val);return this; }
        /** 单元格-缩进 */
        public StyleBean indention(short val){ style.setIndention(val);return this; }
        /** 单元格-填充模式 */
        public StyleBean fillPattern(FillPatternType val){ style.setFillPattern(val);return this; }
        /** 单元格-前景色 */
        public StyleBean fillFore(short val){ style.setFillForegroundColor(val);return this; }
        /** 单元格-背景色 */
        public StyleBean fillBackground(short val){ style.setFillBackgroundColor(val);return this; }
    }
    public enum Border {
        /**顶*/TOP, /**右*/RIGHT, /**底*/BOTTOM, /**左*/LEFT
    }
}

测试代码

其中使用了自己的工具类DateFormatEnum


import ***.enums.DateFormatEnum;
import ***.utils.ExcelKit;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static ***.utils.ExcelKit.Border;
@GetMapping("testExcel")
@ApiOperation(value = "测试导出",notes = "测试导出-[jk-zyl]")
public void testExcel(HttpServletResponse response){
    try {
        // 有内容的列
        int[] columns = {0,1,2};
        // 文本内容 列,批量格式化
        final Map<String, int[]> strFormat = Collections.singletonMap("@", new int[]{0,1});
        //ExcelKit.exportExcel07
        ExcelKit.exportExcel03(response,pb -> {
            // 默认文本 字体
            Font strFont = pb.initNewFont(c -> c.fontHeight(12));
            // 初始化 文件名、sheet名称、文本字体、边框、默认列宽
            pb.setFileName("测试下载"+System.currentTimeMillis()).sheetName("第一页").columnsWidth(14,30,22)
                    .columnsFormat(strFormat,columns,c -> c.font(strFont).border(BorderStyle.THIN, Border.BOTTOM,Border.LEFT,Border.RIGHT))
                    .init((w,s)-> s.setDefaultColumnWidth(17));
            // 标题 字体,粗体、红色、18号
            Font titleFont = pb.initNewFont(c -> c.bold(true).color(IndexedColors.RED).fontHeight(18));
            // 合并单元格,设置标题样式,标题内容
            pb.merge(1,2).newCellStyle(s -> s.font(titleFont)
                    .alignment(HorizontalAlignment.CENTER).vertical(VerticalAlignment.CENTER)
                    .border(BorderStyle.THIN, Border.TOP,Border.LEFT,Border.RIGHT)).thisVal(true,"测试标题---");
            // 列头字体,加粗,14号
            Font headFont = pb.initNewFont(c -> c.fontHeight(14).bold(true));
            // 列头,边框、字体,内容
            pb.rowNext(2).newCellStyle(s -> s.border(BorderStyle.THIN, Border.TOP,Border.BOTTOM,Border.LEFT,Border.RIGHT)
                    .font(headFont).alignment(HorizontalAlignment.CENTER)).vs(true,"序号", "名称", "日期");
            // 数据列
            String format = DateFormatEnum.y_M_d_1.format();
            for (int i = 0; i < 4; i++) {
                pb.rowNext().vs(false,i+"","测试zyl",format);
            }
        });
    } catch (Exception e) {
        logger.error("异常",e);
        try {
            ExcelKit.fail(response,e.getMessage());
        } catch (Exception ex) {
            logger.error("异常",ex);
        }
    }
}

测试

失败的情况,返回报文
在这里插入图片描述
成功导出
在这里插入图片描述

成功导出-07
在这里插入图片描述
成功导出-03
在这里插入图片描述

寄语

工具类当前只是自用,如果觉得方法不全可以自己在添加。代码比较简陋,请手下留情(⊙o⊙)…

举报

相关推荐

0 条评论