一篇文章教你使用JAVA实现导入导出(EasyExcel)

一篇文章教你使用JAVA实现导入导出(EasyExcel)

1.前言

上一篇文章也已经过了很久了,讲的是java中使用poi针对Excel实现数据的灵活导入导出,我们讲讲上一
篇文章的优缺点
优点:
	1、能够对excel中元素灵活使用(例如上一篇文章提到过的excel的“**名称管理器**”)
	2、由于是针对业务来写的,能保持对业务的的灵活变动,可以针对当前业务的变化,修改
	代码,实现对业务的贴合
	3、等等......
缺点:
	1、需要写的代码太多并且不公共,对于刚入门这个的人不太友好,容易看代码的时候迷失方向
	2、不支持多业务导出【公共方法】万一是多业务导出,方法很容易不支持导出项目报错
方向:所以本篇文章针对上述提出来的点 我带来了这篇使用JAVA中另一个插件(EasyExcel)
实现的更加便捷的导入导出,废话不多说我们直接进入实战,接着往下看

2. 实战

2.1 导入

  1. EasyExcel导入详解
    在这里插入图片描述
    在这里插入图片描述
    fileName可是是你的文件全路径名称也可以是你前端传递过来的InputStream流,然后进行数据持久化操作即可,非常简单

2.2 导出

  1. 引入依赖包
<!--引入EasyExcel依赖包-->
 <dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>easyexcel</artifactId>
   <version>3.3.2</version>
 </dependency> 
  1. 编写辅助常量类
/**
 * 导出Excel的常量类(这个常量类是根据我业务需求编写的,可根据所需业务做调整)
 */
public class ExcelConstant {

    /**
     * 默认生成得sheet名称
     */
    public static final String DEFAULT_SHEET_NAME = "sheet1";
    /**
     * 默认列宽
     */
    public static final Integer DEFAULT_COLUMN_WIDTH = 22;
    /**
     * 查询键 左
     */
    public static final String QUERY_LEFT = "valueLeft";
    /**
     * 查询键 右
     */
    public static final String QUERY_RIGHT = "valueRight";
    /**
     * 数字分隔符
     */
    public static final String NUMBER_FORMAT = "#,##0.00";
    /**
     * 字体
     */
    public static final String FONT_NAME = "宋体";
    /**
     * 内容文字大小
     */
    public static final Short CONTENT_SIZE = 10;
    /**
     * 表格标题大小
     */
    public static final Short MAX_HEIGHT_SIZE = 18;
    /**
     * 表格列大小
     */
    public static final Short MIN_HEIGHT_SIZE = 10;
    /**
     * 查询符号
     */
    public static final String QUERY_PLACEHOLDER  = ":";
    /**
     * 表格首行高度
     */
    public static final Short TABLE_TITLE_HEIGHT  = 24;

}
  1. 编写辅助实体类
/**
 * 导出Exceld的表头数据(这个常量类是根据我业务需求编写的,可根据所需业务做调整)
 */
@Data
public class ExportHeads{


    /**
     * 名称
     */
    private String label;
    /**
     * 子集
     */
    private List<ExportHeads> children = new ArrayList<>();                                                                                                                                                        
}
/**
 * 导出Excel的数据实体类(这个常量类是根据我业务需求编写的,可根据所需业务做调整)
 */
@Data
@Accessors(chain = true)
public class ExportDynamic {
    /**
     * 文件名称
     */
    private String fileName;
    /**
     * 文件全路径
     */
    private String filePath;
    /**
     * 表格标题
     */
    private String tableTitle;
    /**
     * 表格查询条件
     */
    List<Map<String,String>> queryCriteria = new ArrayList<>();
    /**
     * 表头数据
     */
    List<ExportHeads> heads =new ArrayList<>();
    /**
     * 表数据
     */
    List<List<Object>> datas =new ArrayList<>();
}
  1. 公共导出工具类编写
public class BusinessExcelUtil {

    /**
     * @Description: 动态导出excel
     * 
     * @Date: 2024/4/28 11:29
     * @param exportDynamic 参数实体类
     * @return: void
     */
    public static void exportBusinessExcel(ExportDynamic exportDynamic) {
        // 文件名称不能为空
        if (!ObjectUtils.isEmpty(exportDynamic.getFileName())) {
            List<List<String>> head = new ArrayList<>();
            // 设置文件名称和文件路径
            String filePath = exportDynamic.getFilePath();
            String fileName = filePath + File.separator + exportDynamic.getFileName();
            // 设置动态表头
            if (!CollectionUtils.isEmpty(exportDynamic.getHeads())) {
                // 处理查询条件以及表格的标题
                head = formatHead(head(exportDynamic.getHeads()), exportDynamic.getTableTitle(), exportDynamic.getQueryCriteria());
            }
            // 导出excel
            EasyExcel.write(fileName)
                    .head(head)
//                    .relativeHeadRowIndex(1) 表格离上方多少行
                    .registerWriteHandler(new SimpleColumnWidthStyleStrategy(ExcelConstant.DEFAULT_COLUMN_WIDTH))
                    .registerWriteHandler(setterTableHead())
                    .registerWriteHandler(new CustomCellWriteHandler())
                    .sheet(ExcelConstant.DEFAULT_SHEET_NAME)
                    .doWrite(exportDynamic.getDatas());
        }
    }


    /**
     * 设置表格策略
     *
     * @return 表格策略
     */
    private static HorizontalCellStyleStrategy setterTableHead() {
        // 设置样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 背景设置为颜色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteCellStyle.setWriteFont(headWriteFont);
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short) 12);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }


    /**
     * @Description: 处理表格标题和查询条件
     * 
     * @Date: 2024/4/28 16:29
     * @Param heads: 表头数据
     * @Param title: 表头内容
     * @Param queryCriteria: 查询条件
     * @return: java.util.List<java.util.List < java.lang.String>>
     */
    private static List<List<String>> formatHead(List<List<String>> heads, String title, List<Map<String, String>> queryCriteria) {
        List<List<String>> datas = new ArrayList<>();
        if (!CollectionUtils.isEmpty(heads)) {
            // 取出数据长度
            int size = heads.size() / 2;
            String value;
            for (int i = 0; i < heads.size(); i++) {
                heads.get(i).add(0, title);
                // 查询条件
                if (!CollectionUtils.isEmpty(queryCriteria)) {
                    //遍历赋值查询条件
                    for (int j = 0; j < queryCriteria.size(); j++) {
                        if (i <= size) {
                            value = queryCriteria.get(j).get(ExcelConstant.QUERY_LEFT);
                            heads.get(i).add(j + 1, value);
                        } else {
                            value = ObjectUtils.isEmpty(queryCriteria.get(j).get(ExcelConstant.QUERY_RIGHT))
                                    ? queryCriteria.get(j).get(ExcelConstant.QUERY_LEFT)
                                    : queryCriteria.get(j).get(ExcelConstant.QUERY_RIGHT);
                            heads.get(i).add(j + 1, value);
                        }
                    }


                }
            }
            datas.addAll(heads);
        }
        return datas;
    }

    /**
     * 处理表格表头数据
     *
     * @param heads 表头数据
     * @return 结果
     */
    private static List<List<String>> head(List<ExportHeads> heads) {
        List<List<String>> list = ListUtils.newArrayList();
        // 新增一级到数组
        for (ExportHeads head : heads) {
            List<String> datas = new ArrayList<>();
            datas.add(head.getLabel());
            // 判断子集
            recursion(list, datas, head.getChildren(), null);
        }
        // 先将一级新增倒数组
        return list;
    }

    /**
     * 递归处理数据
     *
     * @param list  需要新增的数组
     * @param heads 当前数据
     */
    private static void recursion(List<List<String>> lists, List<String> list, List<ExportHeads> children, ExportHeads heads) {
        if (!CollectionUtils.isEmpty(children)) {
            for (ExportHeads child : children) {
                List<String> listOne = new ArrayList<>();
                listOne.addAll(list);
                listOne.add(child.getLabel());
                recursion(lists, listOne, child.getChildren(), heads);
            }
        } else {
            lists.add(list);
        }
    }
 }
  1. EasyExcel拦截器编写
/**
 * EasyExcel导出拦截器
 */
@Slf4j
public class CustomCellWriteHandler extends HorizontalCellStyleStrategy implements CellWriteHandler, RowWriteHandler {


    private static Integer INDEX;


    @Override
    public void afterRowDispose(RowWriteHandlerContext context) {
        WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder();
        // 拿取数据判断查询条件有多少
        List<String> list = writeSheetHolder.getHead().get(0);
        // 拿取查询的数据的长度
        INDEX = (int) list.stream().filter(item -> item.contains(ExcelConstant.QUERY_PLACEHOLDER)).count();
    }

    @Override
    public void afterCellDispose(CellWriteHandlerContext context) {
        Cell cell = context.getCell();
        Row row = context.getRow();
        // 这里可以对cell进行任何操作
        log.info("第{}行,第{}列写入完成。", cell.getRowIndex(), cell.getColumnIndex());
        if (BooleanUtils.isTrue(context.getHead())) {
            setHeadCellStyle(cell, null, cell.getRowIndex());
            //设置表格第一行的高度
            if (cell.getRowIndex() == 0 && cell.getColumnIndex() == 0) {
                row.setHeightInPoints(ExcelConstant.TABLE_TITLE_HEIGHT);
            }
        } else {
            // 处理内容格式
            setContentCellStyle(cell, null, cell.getRowIndex());
        }
        context.getFirstCellData().setWriteCellStyle(null);
    }

    @Override
    protected void setHeadCellStyle(Cell headCell, Head head, Integer relativeRowIndex) {
        Workbook workbook = headCell.getSheet().getWorkbook();
        // 创建表头样式
        CellStyle headCellStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        // 大标题18 小标题12
        if (headCell.getRowIndex() == 0) {
            font.setFontHeightInPoints(ExcelConstant.MAX_HEIGHT_SIZE); // 设置字体大小
            headCellStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中
        } else {
            font.setFontHeightInPoints(ExcelConstant.MIN_HEIGHT_SIZE); // 设置字体大小
            if (headCell.getRowIndex()>0 && headCell.getRowIndex() <= INDEX) {
                // 只有查询条件列一居左 列二居右
                if (headCell.getColumnIndex() == 0) {
                    headCellStyle.setAlignment(HorizontalAlignment.LEFT); // 居左
                } else {
                    headCellStyle.setAlignment(HorizontalAlignment.RIGHT); // 居右
                }
            } else if (headCell.getRowIndex() > INDEX) {
                headCellStyle.setAlignment(HorizontalAlignment.CENTER); // 居中
                // 设置边框
                headCellStyle.setBorderTop(BorderStyle.THIN);
                headCellStyle.setBorderLeft(BorderStyle.THIN);
                headCellStyle.setBorderBottom(BorderStyle.THIN);
                headCellStyle.setBorderRight(BorderStyle.THIN);
            }
        }
        font.setFontName(ExcelConstant.FONT_NAME); // 设置字体
        font.setBold(false); // 加粗
        headCellStyle.setFont(font);
        headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
        // 应用样式
        headCell.setCellStyle(headCellStyle);
    }

    @Override
    protected void setContentCellStyle(Cell headCell, Head head, Integer relativeRowIndex) {
        Workbook workbook = headCell.getSheet().getWorkbook();
        // 创建表头样式
        CellStyle headCellStyle = workbook.createCellStyle();
        Font font = workbook.createFont();

        // 设置边框
        headCellStyle.setBorderTop(BorderStyle.THIN);
        headCellStyle.setBorderLeft(BorderStyle.THIN);
        headCellStyle.setBorderBottom(BorderStyle.THIN);
        headCellStyle.setBorderRight(BorderStyle.THIN);
        DataFormat dataFormat = workbook.createDataFormat();
        headCellStyle.setDataFormat(dataFormat.getFormat(ExcelConstant.NUMBER_FORMAT));
        font.setFontName(ExcelConstant.FONT_NAME); // 设置字体
        font.setFontHeightInPoints(ExcelConstant.CONTENT_SIZE); // 设置字体大小
        headCellStyle.setFont(font);
        headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
        // 应用样式
        headCell.setCellStyle(headCellStyle);
    }


}
  1. 测试数据
    List<ExportHeads> children = new ArrayList<>();
        ExportHeads aa12 = new ExportHeads();
        aa12.setLabel("时");
        ExportHeads aa22 = new ExportHeads();
        aa22.setLabel("分");
        ExportHeads aa1 = new ExportHeads();
        aa1.setLabel("月");
        ExportHeads aa2 = new ExportHeads();
        aa2.setLabel("日");
        aa2.getChildren().add(aa12);
        aa2.getChildren().add(aa22);
        ExportHeads aa = new ExportHeads();
        aa.setLabel("年");
        aa.getChildren().add(aa1);
        aa.getChildren().add(aa2);
        ExportHeads bb = new ExportHeads();
        bb.setLabel("列一");
        children.add(aa);
        children.add(bb);

        List<List<Object>> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            List<Object> data = ListUtils.newArrayList();
            data.add("bb" + i);
            data.add("aa" + i);
            data.add(0.56);
            data.add(new Date());
            list.add(data);
        }
        List<Map<String, String>> listMam = new ArrayList<>();
        Map<String, String> mam1 = new HashMap<>();
        mam1.put("valueLeft", "姓名:张三");
        mam1.put("valueRight", "性别:女");
        listMam.add(mam1);
        // 调用方法测试
        BusinessExcelUtil.exportBusinessExcel(new ExportDynamic()
                .setFileName("这里写你的文件名字")
                .setHeads(children)
                .setTableTitle("这是一个excel")
                .setFilePath("这里写你的文件路径")
                .setQueryCriteria(listMam)
                .setDatas(list));
    }
  1. 效果展示

在这里插入图片描述

  1. 总结

到这里我们就完成了整个导出excel公共方法的所有操作,我们总结一下这一种方法的优缺点,方便小伙伴们对应自己的业务选择不同的方法
1、相同点:都能根据自己的需求处理到每一个每一列的数据及格式
2、不同点:poi处理是写在自己的业务层,难以公共化。而EasyExcel处理是放在拦截器中 方法对应不同的需求处理不同的逻辑
3、优点:
3.1.实现了公共化处理,提供不同的数据映射出不同的Excel
3.2.方便我们针对excel的每一行甚至与每一列的数据或者样式不同处理
3.3.代码的简化,后续我们其他业务如果还需要导出excel直接传入ExportDynamic对象即可实现导出,无需再关注对于excel样式的处理或者数据的处理
4.、缺点: 如果业务需求非常的个性化,基本上就一小部分一样,大多都不一样,这样的情况就比较不推荐使用这种方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值