All Downloads are FREE. Search and download functionalities are using the official Maven repository.

matrix.boot.common.utils.ExcelUtil Maven / Gradle / Ivy

There is a newer version: 2.1.11
Show newest version
package matrix.boot.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.monitorjbl.xlsx.StreamingReader;
import matrix.boot.common.constants.ExcelConstant;
import matrix.boot.common.converter.ExcelColumnConvert;
import matrix.boot.common.converter.ExcelExportSheetListenerConvert;
import matrix.boot.common.enums.ExcelFormatEnum;
import matrix.boot.common.exception.ServiceException;
import matrix.boot.common.listener.ExcelExportMultiSheetListener;
import matrix.boot.common.listener.ExcelExportSingleSheetListener;
import matrix.boot.common.dto.ExcelColumnDto;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.*;

/**
 * excel导入导出工具
 *
 * @author wangcheng
 * 2020/7/17
 **/
public class ExcelUtil {

    private static final int ROW_ACCESS_WINDOW_SIZE = 200;

    /**
     * 文件路径
     */
    private String filePath;

    private ExcelUtil() {
    }

    private ExcelUtil(String filePath) {
        this.filePath = filePath;
    }

    /**
     * 获取实例
     *
     * @param filePath 文件地址
     * @return 实例
     */
    public static ExcelUtil getInstance(String filePath) {
        return new ExcelUtil(filePath);
    }

    /**
     * 导出Bean单个sheet
     *
     * @param data            数据
     * @param excelFormatEnum excel导入类型
     * @return 文件名
     */
    public  String exportSingleForBean(List data, ExcelFormatEnum excelFormatEnum) {
        return exportMultiForBean(ExcelExportSheetListenerConvert.convert(data), excelFormatEnum);
    }

    /**
     * 导出Bean单个sheet
     *
     * @param listener        数据监听器
     * @param excelFormatEnum excel导入类型
     * @return 文件名
     */
    public  String exportSingleForBean(ExcelExportSingleSheetListener listener, ExcelFormatEnum excelFormatEnum) {
        return exportMultiForBean(ExcelExportSheetListenerConvert.convert(listener), excelFormatEnum);
    }

    /**
     * 导出Map单个sheet
     *
     * @param data            数据
     * @param excelFormatEnum excel导入类型
     * @return 文件名
     */
    public String exportSingleForMap(List> data, ExcelFormatEnum excelFormatEnum) {
        return exportMultiForMap(ExcelExportSheetListenerConvert.convert(data), excelFormatEnum);
    }

    /**
     * 导出Map单个sheet
     *
     * @param listener        数据监听器
     * @param excelFormatEnum excel导入类型
     * @return 文件名
     */
    public String exportSingleForMap(ExcelExportSingleSheetListener> listener, ExcelFormatEnum excelFormatEnum) {
        return exportMultiForMap(ExcelExportSheetListenerConvert.convert(listener), excelFormatEnum);
    }

    /**
     * 导出Bean多个sheet
     *
     * @param listener        数据监听器
     * @param excelFormatEnum excel导入类型
     * @return 文件名
     */
    public  String exportMultiForBean(ExcelExportMultiSheetListener listener, ExcelFormatEnum excelFormatEnum) {
        return exportExcel(listener, excelFormatEnum, true);
    }

    /**
     * 导出Map多个sheet
     *
     * @param listener        数据监听器
     * @param excelFormatEnum excel导入类型
     * @return 文件名
     */
    public String exportMultiForMap(ExcelExportMultiSheetListener> listener, ExcelFormatEnum excelFormatEnum) {
        return exportExcel(listener, excelFormatEnum, false);
    }


    /**
     * 导出excel(核心方法)
     *
     * @param listener        数据监听器
     * @param excelFormatEnum excel导入类型
     * @param isBean          是否是实体(非实体为map)
     * @return 文件名
     */
    private  String exportExcel(ExcelExportMultiSheetListener listener, ExcelFormatEnum excelFormatEnum, boolean isBean) {
        AssertUtil.notNullTip(listener, "listener");
        AssertUtil.notNullTip(excelFormatEnum, "excelFormatEnum");
        Workbook book = null;
        FileOutputStream fos = null;
        try {
            book = excelFormatEnum.getClazz().equals(SXSSFWorkbook.class) ? new SXSSFWorkbook(ROW_ACCESS_WINDOW_SIZE) : (Workbook) excelFormatEnum.getClazz().newInstance();
            //创建列类型字典
            Map cellStyleMap = new HashMap<>();
            cellStyleMap.put(ExcelConstant.TITLE_CELL_STYLE_KEY, getTitleCellStyle(book));
            // 数据sheet页
            Set dataSheets = new HashSet<>();
            int count = 0;
            //调用处理数据前操作
            listener.beforeProcessData(book);
            //准备写入数据
            while (true) {
                Map> originData = listener.getData(count++);
                //检查数据是否为空(为空停止获取数据)
                if (originData == null || originData.size() <= 0
                        || originData.values().stream().filter(CollectionUtils::isNotEmpty).count() <= 0) {
                    break;
                }
                //解析数据
                for (String sheetName : originData.keySet()) {
                    List originRows = originData.get(sheetName);
                    if (CollectionUtils.isEmpty(originRows)) {
                        continue;
                    }
                    @SuppressWarnings("unchecked")
                    List> rows = isBean ? ExcelColumnConvert.convertForBean(originRows) : ExcelColumnConvert.convertForMap((List>) originRows);
                    //获取当前sheet
                    Sheet sheet = book.getSheet(sheetName);
                    if (sheet == null) {
                        sheet = book.createSheet(sheetName);
                    }
                    int rowIndex = sheet.getPhysicalNumberOfRows();
                    for (List columns : rows) {
                        //新增标题
                        if (!dataSheets.contains(sheetName) && dataSheets.add(sheetName)) {
                            Row excelRow = sheet.createRow(rowIndex++);
                            //起始列标识
                            int cellIndex = (excelRow.getLastCellNum() < 0 ? 0 : excelRow.getLastCellNum());
                            for (ExcelColumnDto column : columns) {
                                //设置列宽
                                sheet.setColumnWidth(cellIndex, column.getWidth() * 20);
                                Cell cell = excelRow.createCell(cellIndex);
                                //设置标题样式
                                cell.setCellStyle(cellStyleMap.get(ExcelConstant.TITLE_CELL_STYLE_KEY));
                                //设置值
                                cell.setCellValue(column.getName());
                                cellIndex++;
                            }
                        }
                        //新增数据
                        Row excelRow = sheet.createRow(rowIndex++);
                        //起始列标识
                        int cellIndex = (excelRow.getLastCellNum() < 0 ? 0 : excelRow.getLastCellNum());
                        for (ExcelColumnDto column : columns) {
                            Cell cell = excelRow.createCell(cellIndex++);
                            CellStyle cellStyle = cellStyleMap.get(column.getType());
                            if (cellStyle == null) {
                                //创建cellStyle
                                cellStyle = getExportDefaultCellStyle(column, book);
                                cellStyleMap.put(column.getType(), cellStyle);
                            }
                            //设置样式
                            cell.setCellStyle(cellStyle);
                            //如果为空直接放入为空字符串
                            if (column.getValue() == null) {
                                cell.setCellValue("");
                                continue;
                            }
                            //设置值
                            if (Date.class.equals(column.getType())) {
                                cell.setCellValue((Date) column.getValue());
                            } else if (Double.class.equals(column.getType())) {
                                cell.setCellValue((Double) column.getValue());
                            } else if (Boolean.class.equals(column.getType())) {
                                cell.setCellValue((Boolean) column.getValue());
                            } else if (Integer.class.equals(column.getType())) {
                                cell.setCellValue((Integer) column.getValue());
                            } else {
                                cell.setCellValue(String.valueOf(column.getValue()));
                            }
                            //后置单元格处理(处理批注,个性化颜色等等功能)
                            listener.processingData(column, cell);
                        }
                    }
                }
            }
            //写入数据结束
            //调用处理数据后操作
            listener.afterProcessData(book);
            //随机文件名称
            String fileName = RandomUtil.getUUID() + excelFormatEnum.getSuffix();
            fos = new FileOutputStream(new File(filePath, fileName));
            book.write(fos);
            return fileName;
        } catch (Exception e) {
            throw new ServiceException(e);
        } finally {
            BIOStreamUtil.closeStream(fos);
            BIOStreamUtil.closeStream(book);
        }
    }


    /**
     * 导入excel
     *
     * @param fileName        文件名
     * @param excelFormatEnum excel类型
     * @param importCallBack  回调函数
     * @return 处理返回的数据
     */
    public  List importExcel(String fileName, ExcelFormatEnum excelFormatEnum, ExcelImportSingleSheetCallBack importCallBack) {
        return this.importExcel(fileName, excelFormatEnum, null, null, 2000, importCallBack);
    }

    /**
     * 导入excel
     *
     * @param fileName        文件名
     * @param excelFormatEnum excel类型
     * @param sheetName       sheet名称
     * @param batchSize       每批次数量
     * @param importCallBack  回调函数
     * @return 处理返回的数据
     */
    public  List importExcel(String fileName, ExcelFormatEnum excelFormatEnum, String sheetName, Integer batchSize, ExcelImportSingleSheetCallBack importCallBack) {
        return this.importExcel(fileName, excelFormatEnum, sheetName, null, batchSize, importCallBack);
    }

    /**
     * 导入excel
     *
     * @param fileName        文件名
     * @param excelFormatEnum excel类型
     * @param sheetName       sheet名称
     * @param titleRowIndex   标题行Index
     * @param batchSize       每批次数量
     * @param importCallBack  回调函数
     * @return 处理返回的数据
     */
    public  List importExcel(String fileName, ExcelFormatEnum excelFormatEnum, String sheetName, int titleRowIndex, Integer batchSize, ExcelImportSingleSheetCallBack importCallBack) {
        AssertUtil.notNullTip(sheetName, "sheetName");
        Map sheetTitleRowIndexMap = new HashMap() {{
            put(sheetName, titleRowIndex);
        }};
        return this.importExcel(fileName, excelFormatEnum, sheetName, sheetTitleRowIndexMap, batchSize, importCallBack);
    }

    /**
     * 导入excel(核心方法)
     *
     * @param fileName              文件名
     * @param excelEnum             excel类型
     * @param sheetName             sheet名称
     * @param sheetTitleRowIndexMap 每个sheet页的标题行Index
     * @param batchSize             每批次数量
     * @param importCallBack        回调函数
     * @return 处理返回的数据
     */
    private  List importExcel(String fileName, ExcelFormatEnum excelEnum, String sheetName,
                                       Map sheetTitleRowIndexMap,
                                       Integer batchSize, ExcelImportSingleSheetCallBack importCallBack) {
        AssertUtil.notNullTip(fileName, "fileName");
        AssertUtil.notNullTip(importCallBack, "callBack");
        Workbook book = null;
        FileInputStream fis = null;
        try {
            File file = new File(filePath, fileName);
            AssertUtil.state(file.exists(), "file not found!");
            if (excelEnum.getClazz().equals(HSSFWorkbook.class)) {
                fis = new FileInputStream(file);
                book = new HSSFWorkbook(fis);
            } else {
                book = StreamingReader.builder().rowCacheSize(ROW_ACCESS_WINDOW_SIZE).open(file);
            }
            //创建sheet页集合
            List sheets = new ArrayList<>();
            if (StringUtil.isEmpty(sheetName)) {
                for (Sheet sheet : book) {
                    sheets.add(sheet);
                }
            } else {
                sheets.add(book.getSheet(sheetName));
            }
            //获取callback上的第一个泛型
            @SuppressWarnings("unchecked")
            Class clazz = (Class) ReflectUtil.getGenericSuperClassTypes(importCallBack.getClass(), 1);
            List params = new ArrayList<>();
            List result = new ArrayList<>();
            for (Sheet sheet : sheets) {
                if (sheet == null) {
                    continue;
                }
                //标题行Index
                Integer titleRowIndex = sheetTitleRowIndexMap == null ? null : sheetTitleRowIndexMap.get(sheet.getSheetName());
                titleRowIndex = titleRowIndex == null ? 0 : titleRowIndex;
                List titles = new ArrayList<>();
                for (Row row : sheet) {
                    if (row.getRowNum() <= titleRowIndex) {
                        if (row.getRowNum() == titleRowIndex) {
                            for (Cell cell : row) {
                                titles.add(cell.getStringCellValue());
                            }
                        }
                        continue;
                    }
                    JSONObject jsonObject = new JSONObject();
                    for (int i = 0; i < titles.size(); i++) {
                        jsonObject.put(titles.get(i), ExcelColumnConvert.convertCellValue(row.getCell(i)));
                    }
                    //add数据
                    params.add(ExcelColumnConvert.convertJsonToGeneric(jsonObject, clazz));
                    //批处理数据
                    if (params.size() >= batchSize) {
                        List processResult = importCallBack.processData(sheet.getSheetName(), params);
                        if (!CollectionUtils.isEmpty(processResult)) {
                            result.addAll(processResult);
                        }
                        params.clear();
                    }
                }
                //批处理数据
                if (!CollectionUtils.isEmpty(params)) {
                    List processResult = importCallBack.processData(sheet.getSheetName(), params);
                    if (!CollectionUtils.isEmpty(processResult)) {
                        result.addAll(processResult);
                    }
                    params.clear();
                }
            }
            return result;
        } catch (Exception e) {
            throw new ServiceException(e);
        } finally {
            BIOStreamUtil.closeStream(book);
            BIOStreamUtil.closeStream(fis);
        }
    }

    /**
     * 获取默认的单元格样式
     *
     * @param column   单元格数据
     * @param workbook 工作簿
     * @return 单元格样式
     */
    public static CellStyle getExportDefaultCellStyle(ExcelColumnDto column, Workbook workbook) {
        CellStyle cellStyle = workbook.createCellStyle();
        if (Date.class.equals(column.getType())) {
            cellStyle.setDataFormat(workbook.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));
        }
        cellStyle.setAlignment(HorizontalAlignment.LEFT);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setWrapText(true);
        return cellStyle;
    }

    /**
     * 获取批注信息
     *
     * @param cell   单元格
     * @param author 作者
     * @param text   批注信息
     * @return 批注信息
     */
    public static Comment getExportDefaultComment(Cell cell, String author, String text) {
        Drawing drawing = cell.getSheet().createDrawingPatriarch();
        Comment comment = drawing.createCellComment(drawing.createAnchor(0, 0, 0, 0, cell.getColumnIndex(), cell.getRowIndex(),
                cell.getColumnIndex() + 3, cell.getRowIndex() + 5));
        if (cell instanceof SXSSFCell || cell instanceof XSSFCell) {
            comment.setString(new XSSFRichTextString(text));
        } else if (cell instanceof HSSFCell) {
            comment.setString(new HSSFRichTextString(text));
        }
        comment.setAuthor(author);
        return comment;
    }

    /**
     * 获取标题单元格样式
     * @param workbook 工作薄
     */
    public static CellStyle getTitleCellStyle(Workbook workbook) {
        //创建标题字体
        Font font = workbook.createFont();
        font.setBold(true);
        //创建默认的CellStyle
        CellStyle commonCellStyle = workbook.createCellStyle();
        commonCellStyle.setAlignment(HorizontalAlignment.CENTER);
        commonCellStyle.setFont(font);
        return commonCellStyle;
    }

    /**
     * 导入回调函数
     *
     * @author WangCheng
     * date 2020/7/26
     */
    public static abstract class ExcelImportSingleSheetCallBack {
        /**
         * 处理数据
         *
         * @param sheetName sheet名
         * @param rows      总行数
         * @return 处理需要返回的值
         */
        public abstract List processData(String sheetName, List rows);

    }
}