EasyExcel的学习

2020-04-21  本文已影响0人  盼旺

1.导入

前端VUE代码

<el-upload
        class="upload-demo"
        :action="importUrl"
        ref="ImportUpload"
        :multiple="false"
        :on-change="handleChange"
        :before-upload="beforeUpload"
        :on-remove="handleRemove"
        :on-exceed="handleExceed"
        :onError="uploadError"
        :onSuccess="uploadSuccess"
        :file-list="importFile.fileList"
        accept=".csv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
>
    <el-button slot="trigger" type="success" >上传excel
    </el-button>
    <div slot="tip" class="el-upload__tip">只支持 xls/xlsx 文件,且不超过10M</div>
</el-upload>

后端控制器

/**
 *文件上传的请求实体
 */
@Data
public class ImportCommand {
    private MultipartFile file;
    private 其他数据;
}

@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public ResponseDTO<Integer> importExcel(ImportCommand importCommand) {
    ResponseDTO<Integer> responseDTO;
    try {
        InputStream inputStream = importCommand.getFile().getInputStream();
        //后端处理函数
         responseDTO = excelService.importExcel(inputStream);
    } catch (IOException e) {
        responseDTO = new ResponseDTO<>();
        responseDTO = new ResponseDTO<>();
            responseDTO.setStatus(false);
            responseDTO.setMessage("导入失败");
            e.printStackTrace();
    }
    return responseDTO;
}

后端处理函数

//导入接口函数
@Override
public ResponseDTO<Integer> importByExcel(InputStream  inputStream ) {
        ResponseDTO<Integer> responseDTO = new ResponseDTO<>();
        //开启excel监听器
        BaseExcelReadListener listener;
        //只读第一个sheet
        //List<Object> objects = EasyExcel.read(inputStream, listener).sheet().doReadSync();
        //size = objects.size();
        //responseDTO.setMessage(result.getMessage() + ",共 " + (size - dataBeginRowIndex + 1) + " 条");
        //读取全部sheet
        EasyExcel.read(inputStream, listener).doReadAll();
        //这些更具自己的来
        ImportExcelResult result = listener.getResult();
        responseDTO.setStatus(result.getStatus());
        responseDTO.setMessage(result.getMessage());
        return responseDTO;
}

基本监听器(根据需求修改或不要)

public abstract class BaseExcelReadListener<T> extends AnalysisEventListener<T> {
    //返回结果
    protected ImportExcelResult result = ImportExcelResult.UNKNOWN_ERROR;
    public ImportExcelResult getResult() {
        return result;
    }
    public void setResult(ImportExcelResult result) {
        this.result = result;
    }
    protected void setImportResult(ImportExcelResult importExcelResult) {
        result = importExcelResult;
        log.info("[BaseExcelReadListener]setImportResult: " + result.getMessage());
    }
     /**
     * 保存规则实例数据 - 持久化
     */
    protected void saveData(DataModel dataModel) {
    }

}

其中的返回信息枚举(根据需求修改)

public enum ImportExcelResult {
    SUCCESS(0, true, "导入成功"),
    TEMPLATE_HEAD_ERROR(1, false, "导入失败,模板表头不正确"),
    RULE_ERROR(2, false, "导入失败,规则错误,不是当前规则数据"),
    TEMPLATE_DATA_ERROR(3, false, "导入失败,填写数据错误,可能存在名称或条件重复,或者必填值为空"),
    DATA_DUPLICATION_ERROR(4, false, "导入失败,存在重复数据"),
    FAILED(5, false, "导入失败,请稍后重试"),
    UNKNOWN_ERROR(6, false, "导入失败"),
    CHECKED_ERROR(7, false, "导入失败");

    private Integer value;
    private Boolean status;
    private String message;

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    private ImportExcelResult(Integer value, Boolean status, String message) {
        this.value = value;
        this.status = status;
        this.message = message;
    }

    public static ImportExcelResult getByValue(Integer value) {
        for (ImportExcelResult status : ImportExcelResult.values()) {
            if (status.getValue().equals(value)) {
                return status;
            }
        }
        return null;
    }
}

一个监听器实例

//一个监听器实例
public class ExcelListener extends BaseDataModelImportListener<Map<Integer, String>> {
    /**
     * 通过 AnalysisContext 对象可以获取当前 sheet、以及当前行等数据
     * data 从第 2 行开始,index 为 1
     */
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        log.info("[ExcelListener]解析到一条数据:" + JSON.toJSONString(data));
        ReadRowHolder readRowHolder = context.readRowHolder();
        ReadSheetHolder readSheetHolder = context.readSheetHolder();
        //总行数
        Integer totalRowNumber = readSheetHolder.getApproximateTotalRowNumber();
        //readRowHolder.getRowIndex() 获取当前行号
        Integer currentRowIndex = readRowHolder.getRowIndex();
        //这里进行数据处理 数据是一行一行读取 所以每次data是一行数据 然后每个单元格的数据用data.get(i)来取出
        if(currentRowIndex<5){
        //(除去表头)
        }
        if(currentRowIndex>=5&&currentRowIndex<55){
            String titleData = data.get(0) != null ? data.get(0).trim() : "";
            String valueData = data.get(1) != null ? data.get(1).trim() : "";
            if(出错){
            //base监听器的函数
                setImportResult(ImportExcelResult.TEMPLATE_HEAD_ERROR);
                return;
            }
        }
        if(currentRowIndex==56){
            System.out.println("不管");
        }
        //三级分类加品牌
        if(currentRowIndex>=58){
        //其他处理函数
            handleListData(data, readRowHolder, totalRowNumber);
        }
    }
    //完成所有行的解析调用 用来数据先转换成模型 然后做持久化
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("[ExcelListener] 解析完成");
        //解析完保存函数
        createAndSaveDataModel();
    }

    /**
     * 解析完保存
     */
    private void createAndSaveDataModel() {
        //模型转换 更具需求是否需要或删除
        DataModel dataModel = dataToDataModel();
        //持久化
        saveData(dataModel);
    }
    //判断是否都为数字 -- 用来调皮
    public boolean isDigit(String strNum) {
        Pattern pattern = Pattern.compile("[0-9]{1,}");
        Matcher matcher = pattern.matcher((CharSequence) strNum);
        return matcher.matches();
    }
    /**
     * 转换成  Model
     */
    private DataModel dataToDataModel() {
        DataModel dataModel = new DataModel();
        return dataModel;
    }
}

@Override参考




2.导出

导出工具

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;

/**
 * EasyExcel 工具类
 */
@Slf4j
public class EasyExcelUtil {

    /**
     * 一次性导出
     * 不使用模型、自定义表头、自动适应宽度
     *
     * @param response
     * @param dataList
     * @param fileName
     * @param writeSheet
     * @throws Exception
     */
    public static void writeExcelOnce(HttpServletResponse response, List<? extends Object> dataList, String fileName, WriteSheet writeSheet) throws Exception {
        ExcelWriter excelWriter = getExcelWriter(response, fileName);
        excelWriter.write(dataList, writeSheet);
        excelWriter.finish();
    }


    /**
     * 获取 ExcelWriter(用于分批写入)
     * 不使用模型类、自定义表头、自动适应宽度
     *
     * @param response
     * @param fileName
     * @throws Exception
     */
    public static ExcelWriter getExcelWriter(HttpServletResponse response, String fileName) throws Exception {
        return EasyExcel.write(getOutputStream(fileName, response))
                .excelType(ExcelTypeEnum.XLSX)
                .build();
    }

    /**
     * 获取通用 WriteSheet
     * 不使用模型类、自定义表头、自动适应宽度
     *
     * @param headList
     * @param sheetName
     */
    public static WriteSheet getCommonWriteSheet(List<List<String>> headList, String sheetName) {
        WriteSheet writeSheet = new WriteSheet();
        writeSheet.setSheetNo(0);
        writeSheet.setSheetName(sheetName);
        writeSheet.setHead(headList);
        if (writeSheet.getCustomWriteHandlerList() == null) {
            writeSheet.setCustomWriteHandlerList(new ArrayList<>());
        }
        // # 表头策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        headWriteCellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
        // 设置字体
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteCellStyle.setWriteFont(headWriteFont);
        // # 内容策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        // 设置内容靠左对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        // 垂直居中
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 自动换行
        contentWriteCellStyle.setWrapped(true);
        contentWriteCellStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        writeSheet.getCustomWriteHandlerList().add(horizontalCellStyleStrategy);
        // 自动适应列宽
        writeSheet.getCustomWriteHandlerList().add(new ColumnWidthStyleStrategy());
        return writeSheet;
    }

    /**
     * 导出通过模型类导出
     * 表头列宽再模型类中通过注解设定
     *
     * @param response
     * @param dataList
     * @param fileName
     * @param sheetName
     * @param clazz
     * @throws Exception
     */
    public static void writeExcelWithModel(HttpServletResponse response, List<? extends Object> dataList, String fileName, String sheetName, Class clazz) throws Exception {
        //表头样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //内容样式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //设置内容靠左对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        EasyExcel.write(getOutputStream(fileName, response), clazz)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(sheetName)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .doWrite(dataList);
    }

    /**
     * 导出文件时为 Writer 生成 OutputStream.
     *
     * @param fileName 文件名
     * @param response response
     * @return ""
     */
    private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8");
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf8");
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
            response.setHeader("Pragma", "public");
            response.setHeader("Cache-Control", "no-store");
            response.addHeader("Cache-Control", "max-age=0");
            return response.getOutputStream();
        } catch (IOException e) {
            throw new Exception("导出excel表格失败!", e);
        }
    }

    /**
     * 读取 Excel 不处理表头
     */
    public static List<LinkedHashMap<Integer, String>> readExcel(InputStream in) {
        return EasyExcel.read(new BufferedInputStream(in))
                .sheet()
                .doReadSync();
    }

    /**
     * 缓冲同步 读取 Excel
     */
    public static List<LinkedHashMap<Integer, String>> readExcel(InputStream in,  List<List<String>> headList) {
        return EasyExcel.read(new BufferedInputStream(in))
                .head(headList)
                .sheet()
                .doReadSync();
    }

    /**
     * 通过反射获取
     */
    public static List<List<String>> getHeadList(Class clazz) {
        Field[] declaredFields = clazz.getDeclaredFields();
        TreeMap<Integer, String> treeMap = new TreeMap<>();
        for (Field field : declaredFields) {
            // 获取原来的访问控制权限
            boolean accessFlag = field.isAccessible();
            // 修改访问控制权限
            field.setAccessible(true);
            // 恢复访问控制权限
            field.setAccessible(accessFlag);
            if (field.isAnnotationPresent(ExcelProperty.class)) {
                ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                treeMap.put(annotation.index(), annotation.value()[0]);
            }
        }
        List<List<String>> headList = new ArrayList<>();
        for (Map.Entry<Integer, String> entry : treeMap.entrySet()) {
            List<String> headColumn = new ArrayList<>();
            headColumn.add(entry.getValue());
            headList.add(headColumn);
        }
        return headList;
    }

    /**
     * 将对象转成 List<List<String>>, 属性值 value 的 List
     *
     * @throws IllegalAccessException
     */
    public static List<List<Object>> toListListData(List<?> objects) throws IllegalAccessException {
        List<List<Object>> listListData = new ArrayList<>();
        for (Object object : objects) {
            ArrayList<Object> listData = new ArrayList<>();
            Class clazz = object.getClass();
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                // 获取原来的访问控制权限
                boolean accessFlag = field.isAccessible();
                // 修改访问控制权限
                field.setAccessible(true);
                Object value = null;
                value = field.get(object);
                // 恢复访问控制权限
                field.setAccessible(accessFlag);
                if (null != value && StringUtils.isNotBlank(value.toString())) {
                    //如果是List, 将List转换为json字符串
                    if (value instanceof Integer) {
                        listData.add(value);
                    } else if (value instanceof Long) {
                        listData.add(value);
                    } else if (value instanceof String) {
                        listData.add(value.toString());
                    } else {
                        listData.add(JSON.toJSONString(value));
                    }
                } else {
                    listData.add("-");
                }
            }
            listListData.add(listData);
        }
        return listListData;
    }
}

一行一行写入数据 中间可以处理

public void exportToExcel(ExportReqBody reqBody, HttpServletResponse response) {
        String fileName = reqBody.getName() + "导出数据";//文件名字
        //根据请求体的模型获取需要导出的表头和内容信息 List<String>理解为一行数据
        List<List<String>> headList = getHeadList(reqBody);
        List<List<String>> commentList = getCommentList(reqBody);
        ExcelWriter excelWriter;
        WriteSheet sheet1;
        try {
//            获取 ExcelWriter(用于分批写入)并且把这个excelWriter写入response
            excelWriter = EasyExcelUtil.getExcelWriter(response, fileName);
//            获取通用 WriteSheet 并且把表头数据写入
            sheet1 = EasyExcelUtil.getCommonWriteSheet(headList, "sheet1");
        } catch (Exception e) {
            log.error("[exportToExcel]导出数据失败", e);
            return;
        }
        // 分批导出数据
        int batchSize = 1000;
        int begIndex = 0;
        int total = commentList.size();
        int endIndex = Math.min(total, batchSize);
        while (begIndex < total) {
//            log.info("[exportToExcel]导出数据:处理第" + begIndex + "条 - 第" + endIndex + "条");
            for (int i = begIndex; i < endIndex; i++) {
                List<List<Object>> dataList = new ArrayList<>();
                        List<Object> rowData = new ArrayList<>();
                        //遍历commentList[begIndex]把数据都add进rowData 可以理解为一行
                        for(int i=0;i<commentList.get(begIndex).size();i++)
                        dataList.add(commentList.get(begIndex).get(i));
                        begIndex++;
                excelWriter.write(dataList, sheet1);
            }
            //分批次导出
            begIndex = endIndex;
            endIndex = Math.min((endIndex + batchSize), total);
        }
        excelWriter.finish();
}
sheet1 = EasyExcelUtil.getCommonWriteSheet(headList, "sheet1");执行结果

控制层

@RequestMapping("/exportToExcel")
public void ExportToExcel(ExportReqBody exportReqBody, HttpServletResponse response) {
    exportToExcelService.exportToExcel(exportReqBody, response);
}
上一篇下一篇

猜你喜欢

热点阅读