【EasyExcel】后台开发如何利用EasyExcel优雅的操作Excel

1,727 阅读3分钟

文章目录

引言

EasyExcel是当前性能最佳的Excel导出工具,本篇少侠将带领大家一起在后台开发中优雅的使用EasyExcel。

优雅的读取Excel

后台接口读取文档通常使用MultipartFile类型,通过该类型可以构造出InputStream流。
利用EasyExcel读取Excel需要先构造一个监听器,暖男露飞已经帮你们准备好啦:

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Carson
 * @date 2020/6/4 21:26
 */
public class ExcelReaderListener<T> extends AnalysisEventListener<T> {
    /**
     * 返回的数据集
     */
    private List<T> list = new ArrayList<>(1 << 6);

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     */
    public ExcelReaderListener() {
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    数据
     * @param context Excel读取上下文
     */
    @Override
    public void invoke(T data, AnalysisContext context) {
        System.out.printf("解析到一条数据:{%s}", JSON.toJSONString(data));
        System.out.println();
        list.add(data);
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context Excel读取上下文
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }
}

创建好监听器之后,就需要手动写一个工具类,专门用于读取Excel的,少侠这里准备了两种读取方式:

import com.alibaba.excel.EasyExcel;

import java.io.InputStream;
import java.util.List;

/**
 * @author Carson
 * @date 2020/6/4 21:31
 */
public class ExcelReaderUtil<T> {
    private Class<T> clazz;

    public ExcelReaderUtil(Class<T> clazz) {
        this.clazz = clazz;
    }

    public List<T> readByStream(InputStream inputStream) {
        ExcelReaderListener<T> readerListener = new ExcelReaderListener<>();
        EasyExcel.read(inputStream, clazz, readerListener).sheet().doRead();
        return readerListener.getList();
    }

    public List<T> readByPath(String fileName) {
        ExcelReaderListener<T> readerListener = new ExcelReaderListener<>();
        EasyExcel.read(fileName, clazz, readerListener).sheet().doRead();
        return readerListener.getList();
    }
}

备注:少侠这里的代码用的都是泛型,觉得不想细看的可以直接复制过去使用。

基本读取工具类已经实现完成,然后就是模板类的创建啦,什么是模板类呢,就是根据每个Excel表头有不同的参数表示的类,每个参数用@ExcelProperty注解修饰,注解的括号里的内容就是Excel里的表头

@Data
public class GoodsReaderModel {
    @ExcelProperty("商品SKU")
    public Long skuId;

    @ExcelProperty("活动开始时间")
    public String startTime;

    @ExcelProperty("活动结束时间")
    public String finishTime;
}

然后在接口里进行读取:

    @RequestMapping(value = "/import", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
    @ApiOperation(value = "导入商品信息", httpMethod = "POST", notes = "导入商品信息")
    @ResponseBody
    public List<GoodsReaderModel > importGoodsFromExcel(@RequestParam("excel") MultipartFile multipartFile, HttpServletRequest request) {
        if (multipartFile == null) {
            LOGGER.info("输入的Excel信息为空");
            return null;
        }
        ExcelReaderUtil<GoodsReaderModel> excelReader = new ExcelReaderUtil<>(GoodsReaderModel.class);
        List<GoodsReaderModel> modelList = Lists.newArrayList();
        try {
            InputStream inputStream = multipartFile.getInputStream();
            modelList = excelReader.readByStream(inputStream);
        } catch (IOException e) {
            LOGGER.info("对不起,未找到文件");
            return null;
        }
        //后续数据处理逻辑
    }

优雅的写入Excel

在接口中下载Excel同样也可以优雅,先附上通用格式处理类:

import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteWorkbook;
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.google.common.collect.Lists;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;

import javax.servlet.ServletOutputStream;
import java.util.List;

/**
 * @author Carson
 * @date 2020/6/5 19:39
 */
public class ExcelWriterUtil {

    public WriteWorkbook workbookGenerator(ServletOutputStream outputStream) {
        WriteWorkbook workbook = new WriteWorkbook();
        workbook.setOutputStream(outputStream);
        workbook.setExcelType(ExcelTypeEnum.XLSX);
        workbook.setNeedHead(true);

        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置表头左对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        headWriteCellStyle.setBorderTop(BorderStyle.THIN);
        headWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        headWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        headWriteCellStyle.setBorderRight(BorderStyle.THIN);
        headWriteCellStyle.setFillBackgroundColor(IndexedColors.SKY_BLUE.getIndex());
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //设置内容靠左对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        WriteFont writeFont = new WriteFont();
        writeFont.setFontName("宋体");
        contentWriteCellStyle.setWriteFont(writeFont);
        contentWriteCellStyle.setFillPatternType(FillPatternType.NO_FILL);
        contentWriteCellStyle.setFillBackgroundColor(IndexedColors.SKY_BLUE.getIndex());
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        List<WriteHandler> customWriteHandlerList = Lists.newArrayList();
        customWriteHandlerList.add(horizontalCellStyleStrategy);
        workbook.setCustomWriteHandlerList(customWriteHandlerList);
        return workbook;
    }
}

然后在接口请求里就可以这么写了:

   @RequestMapping(value = "export", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})
    @ApiOperation(value = "数据导出", httpMethod = "GET", notes = "数据导出")
    @ResponseBody
    public void exportData() {
       
              //根据自己实际业务获取数据,注意每行数据是一个List
            List<List<String>> resList = Lists.newArrayList();

        try{
            ServletOutputStream outputStream = response.getOutputStream();
           
            WriteWorkbook workbook = new ExcelWriterUtil().workbookGenerator(outputStream);
    
            ExcelWriter writer = new ExcelWriter(workbook);
            String fileName = new String("data");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            WriteSheet writeSheet = new WriteSheet();
            writeSheet.setSheetName("数据明细");
            writeSheet.setAutoTrim(true);

            writer.write(resList, writeSheet);
            writer.finish();
        } catch (IOException e) {
            LOGGER.error("导出数据异常", e);
        }
    }

优雅的小结

EasyExcel只是个工具类,个人感觉,比起线程池、消息队列等内容重要性低很多,但是开发中能熟练使用也是真香。个人感觉这是我们用过最好用、效率最高的Excel工具类。少侠曾经做过测试,EasyExcel导出百万条 数据只需要60秒左右(目前Excel最多容纳104万条数据),而传统的POI技术则需要数小时,并且内存优化很差,大对象不能及时回收,很容易造成JVM的FULL GC。

点点关注,不会迷路