首页 > 基础资料 博客日记

教您如何三分钟搞定EasyExcel导入与导出功能

2024-04-04 22:00:05基础资料围观218

本篇文章分享教您如何三分钟搞定EasyExcel导入与导出功能,对你有帮助的话记得收藏一下,看Java资料网收获更多编程知识

文章目录


前言

该文章主要是介绍如何快速实现导入与导出功能

一、EasyExcel是什么?

引用官方的说明:EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。
他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。

二、使用步骤

1.引入库

pom.xml引入jar依赖包:

<!-- EasyExcel -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>2.2.6</version>
</dependency>

2.导入

2.1创建对应excel表格的实体类

@ExcelProperty该注解的value是对应excle表格的列名称,index对应的是excel列的下标

@Data
public class ImportModel {

    /**
     * 树根
     */
    @ExcelProperty(value = "名称", index = 0)
    private String ;

    /**
     * 树根标题
     */
    @ExcelProperty(value = "编码", index = 1)
    private String code;
}

2.2后端接收请求入口

    /**
     * 导入
     */
    @ApiOperation("导入")
    @PostMapping("/importTree")
    public R importTree(@RequestParam("file") MultipartFile file) {
/** 根据自己的业务自行选择在哪处理 */
/** 直接在controllerr处理 */
//        EasyExcel.read(file.getInputStream(), BigTreeImportCommand.class, new ExcelListener(urbanFacilityManageService)).sheet().doRead();
/** 在service实现类处理 */
        Boolean flag = treeService.importTree(file, tenantId);
        return R.ok("导入成功");
    }

2.3业务处理

    @Override
    public Boolean importTree(MultipartFile file) {

        try {
            /** 处理数据的监听器,有参构造,根据自己的业务决定 */
            TreeExcelListener excelListener = new TreeExcelListener(importService,tenantId);

            // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
            //EasyExcel.read(文件流,对应的Model实体类,监听器).sheet(那张sheet表,可以使用下标或者使用sheet名字).head(表头对应的实体类).headRowNumber(表头占几行).registerReadListener(处理数据的监听器类).doRead()
            EasyExcel.read(file.getInputStream(), ImportModel.class, excelListener).sheet(0).head(ImportModel.class).headRowNumber(1).doRead();
            return true;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

2.4监听器处理数据


import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.ieds.back.interfaces.sys.web.command.BigTreeImportModel;

/**
 * @Author: ChenFB
 * @CreateTime: 2023-04-23 17:18
 * @Description: 导入监听器
 */
public class ImportListener extends AnalysisEventListener<BigTreeImportModel> {


    private ImportService importService;

    private String tenantId;

    /** 有参构造,建议将serverjie接口以参数的方式参进来,方便数据入库处理,这个参数自行界定 */
    public ImportListener(ImportService importService, String tenantId) {
        this.importService = importService;
        this.tenantId = tenantId;
    }

    /** 读取每一行数据都会进入该方法,数据处理与校验可以在该方法进行处理 */
    @Override
    public void invoke(BigTreeImportModel data, AnalysisContext context) {

    }

    /** 所有数据读取完毕后,最终会执行这个方法,所以建议数据处理完后,批量在该方法进行入库处理 */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {

    }
}

3.导出

3.1创建导出格式生成对应的excel表格的实体类,这个可以看2.1

3.2后端接收请求入口

    /**
     * 导出
     */
    @ApiOperation("导出")
    @GetMapping("/exportTree")
    public void exportTree(HttpServletResponse response, @RequestParam("tenantId") String tenantId) {
        treeService.exportTree(response,tenantId);
    }

3.3业务处理

@Override
    public void exportTree(HttpServletResponse response, String tenantId) {
        ExcelWriter writer = null;
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //设置响应内容类型
            response.setCharacterEncoding("utf-8");//编码
            // 设置文件名, ps:把字符串中所有的'+'替换成'%20',在URL中%20代表空格
            String fileName = URLEncoder.encode("文件名,根据业务决定", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");//设置响应头
            response.setHeader("fileName", fileName + ".xlsx");//设置响应头
            /** 导出的数据集合 */
            List<ExportModel> modelList = new ArrayList<>();
            /** registerWriteHandler(合并行数,那些列需要合并) */
            writer = EasyExcel.write(response.getOutputStream(), BigTreeImportModel.class).registerWriteHandler(new MergeStrategy(modelList.size(), 0, 1, 2, 7, 8, 10, 11)).build();//获取写出流
            WriteSheet sheet = EasyExcel.writerSheet("sheet名称,自行决定").build();//创建表格,设置表格页名称
            writer.write(modelList, sheet);//读出

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (null != writer) {
                writer.finish();//关闭流
            }
        }
    }

4.合并工具类



import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.commons.collections.map.HashedMap;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.*;

/**
 * @Author: ChenFB
 * @CreateTime: 2023-04-20 10:56
 * @Description: Excel单元格合并工具类
 */
public class MergeStrategy extends AbstractMergeStrategy {

    // 合并的列编号,从0开始,指定的index或自己按字段顺序数
    private Set<Integer> mergeCellIndex = new HashSet<>();

    // 数据集大小,用于区别结束行位置
    private Integer maxRow = 0;

    // 禁止无参声明
    private MergeStrategy() {
    }

    public MergeStrategy(Integer maxRow, int... mergeCellIndex) {
        Arrays.stream(mergeCellIndex).forEach(item -> {
            this.mergeCellIndex.add(item);
        });
        this.maxRow = maxRow;
    }

    // 记录上一次合并的信息
    private Map<Integer, MergeRange> lastRow = new HashedMap();

    // 每行每列都会进入,绝对不要在这写循环
    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        int currentCellIndex = cell.getColumnIndex();
        // 判断该行是否需要合并
        if (mergeCellIndex.contains(currentCellIndex)) {
            String currentCellValue = cell.getStringCellValue();
            int currentRowIndex = cell.getRowIndex();
            if (!lastRow.containsKey(currentCellIndex)) {
                // 记录首行起始位置
                lastRow.put(currentCellIndex, new MergeRange(currentCellValue, currentRowIndex, currentRowIndex, currentCellIndex, currentCellIndex));
                return;
            }
            //有上行这列的值了,拿来对比.
            MergeRange mergeRange = lastRow.get(currentCellIndex);
            if (!(mergeRange.lastValue != null && mergeRange.lastValue.equals(currentCellValue))) {
                // 结束的位置触发下合并.
                // 同行同列不能合并,会抛异常
                if (mergeRange.startRow != mergeRange.endRow || mergeRange.startCell != mergeRange.endCell) {
                    sheet.addMergedRegionUnsafe(new CellRangeAddress(mergeRange.startRow, mergeRange.endRow, mergeRange.startCell, mergeRange.endCell));
                }
                // 更新当前列起始位置
                lastRow.put(currentCellIndex, new MergeRange(currentCellValue, currentRowIndex, currentRowIndex, currentCellIndex, currentCellIndex));
            }
            // 合并行 + 1
            mergeRange.endRow += 1;
            // 结束的位置触发下最后一次没完成的合并
            if (relativeRowIndex.equals(maxRow - 1)) {
                MergeRange lastMergeRange = lastRow.get(currentCellIndex);
                // 同行同列不能合并,会抛异常
                if (lastMergeRange.startRow != lastMergeRange.endRow || lastMergeRange.startCell != lastMergeRange.endCell) {
                    sheet.addMergedRegionUnsafe(new CellRangeAddress(lastMergeRange.startRow-1, lastMergeRange.endRow, lastMergeRange.startCell, lastMergeRange.endCell));
                }
            }
        }
    }
}

class MergeRange {
    public int startRow;
    public int endRow;
    public int startCell;
    public int endCell;
    public String lastValue;

    public MergeRange(String lastValue, int startRow, int endRow, int startCell, int endCell) {
        this.startRow = startRow;
        this.endRow = endRow;
        this.startCell = startCell;
        this.endCell = endCell;
        this.lastValue = lastValue;
    }
}

总结

以上就是使用EasyExcel时限导入与导出功能的实现步骤,鄙人才疏学浅,本文章仅供参考,有不对之处,还望各位大佬提醒与指教.


文章来源:https://blog.csdn.net/qq_35222186/article/details/130325056
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云