博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)

DBC 420 0
温馨提示

目前为基础使用版本,未来可以使用从设计模式方面改造一下,当前只要能够使用即可~
需求:我们只需要修改数据库中的数据,即可实现表格的动态导入,不需要如果有一点点的变化都需要去修改代码,经过公司定制化之后,基本可以实现线上的动态Excel导入~

本文章计划完成的功能有:
1.基本数据导入——已完成[aru_50]
2.动态表头校验——已完成[aru_50]
3.动态多种数据校验——已完成[aru_50]
4.真·批量导入——已完成[aru_50]
5.动态导入模版——已完成[aru_50]
6.灵活的错误Excel导出——已完成[aru_50]
7.实现更加个性化的封装,一种热拔插效果(重中之重)——进行中[aru_19]

一、第一版简单的导入实现

实现思路

第一版的简单设计思路

  1. 通过数据库设定正确的表头相关
  2. 从导入文件获取到表头之后和正确的表头进行对比
  3. 根据数据库设定的字段名字,找到对应的实体类中的字段信息,将其转换为正确的 sql 列名。
    1. 通过反射来实现所有字段的映射

总结:通过数据库的调整,可以实现导入的相关配置。

 

最开始的准备工作

1.数据库相关

CREATE TABLE `dynamic_import_excel` (
  `id` int(11) NOT NULL,
  `function_number` int(11) DEFAULT NULL COMMENT '功能编号',
  `function_name` varchar(100) DEFAULT NULL COMMENT '功能名字',
  `field_name` varchar(100) DEFAULT NULL COMMENT '字段名字(中文)',
  `property_name` varchar(100) DEFAULT NULL COMMENT '字段名字(英文)',
  `verify_mode` varchar(100) DEFAULT NULL COMMENT '校验模式(如果使用多个,使用数字逗号隔开,具体校验模式查看:VerifyModeEnum 枚举类)',
  `index_num` int(11) DEFAULT NULL COMMENT '表头排序下标(从0开始)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

小例子

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图

2.实体类 —— DynamicImportExcel

点击查看完整 DynamicImportExcel 内容

关键Mapper

DynamicImportExcelMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.test05.demo.model.DynamicImportExcel;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @author DBC
 * @date 2024/6/3 11:12
 * @network dbc655.top
 */
@Mapper
public interface DynamicImportExcelMapper extends BaseMapper<DynamicImportExcel> {

     Integer saveBatch(@Param("tableName") String tableName,
                       @Param("columns") List<String> columns,
                       @Param("data") List<List<String>> data);
}

DynamicImportExcelMapper.xml

<!--    Integer saveBatch(@Param("tableName") String tableName,-->
<!--    @Param("columns") List<String> columns,-->
<!--    @Param("data") List<List<String>> data);-->
    <select id="saveBatch" resultType="java.lang.Integer">
        INSERT INTO
        ${tableName}
        (
            <foreach collection="columns" item="column" separator=",">
                ${column}
            </foreach>
        )
        VALUES
            <foreach collection="data" item="data" separator=",">
                (
                    <foreach collection="data" item="item" separator=",">
                        #{item}
                    </foreach>
                )
            </foreach>
    </select>

3.核心service

DynamicImportExcelService

点击查看完整 DynamicImportExcelService 内容

4.实现效果 小例子

    @Resource
    private UserMapper userMapper;
    @Resource
    private DynamicImportExcelService dynamicImportExcelService;



    @SneakyThrows
    @RequestMapping("/importExcel")
    public JsonData importExcel(MultipartFile file) throws IOException, ClassNotFoundException {

        dynamicImportExcelService.getJsonData(file, UserDO.class, userMapper);
        return JsonData.buildSuccess();
    }

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图2

导入后效果

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图4
可以看到,基本能够实现我们想要的效果[aru_51]

二、第二版简单实现 —— 增加动态的校验

设计思路
  1. 通过数据库定义的校验规则,选择对应的校验策略类
  2. 判断如果校验失败则加入到错误列表中,方便后续的导出错误列表Excel

总结:使用设计模式——策略模式 ,实现对应的校验相关,本文只举例3个策略类(身份证校验、中文校验、数字校验),可以根据对应的项目编写对应的策略类即可实现公司定制化效果![aru_42]

1.简单的策略工厂 —— DynamicImportFactory

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author DBC
 * @date 2024/5/31 10:43
 * @network dbc655.top
 */
@Component
public class DynamicImportFactory {
    @Autowired
    private Map<String, DynamicImportInterface> dynamicImportInterfaceMap;

    public DynamicImportInterface getMsgStrategy(String type) throws Exception {
        DynamicImportInterface payInterface = dynamicImportInterfaceMap.get(type);
        if(payInterface == null){
            throw new Exception("错误的选项!");
        }
        return payInterface;
    }
}

2.策略接口类 —— DynamicImportInterface

import com.fasterxml.jackson.core.JsonProcessingException;

import java.util.Objects;

/**
 * @author DBC
 * @date 2024/5/31 10:22
 * @network dbc655.top
 */
public interface DynamicImportInterface {
     Boolean check(Object o) throws JsonProcessingException;

}

3.三个简单的策略类 DynamicImportIdCardStrategy、DynamicImportIdChineseStrategy、DynamicImportNumberStrategy

点击查看完整 DynamicImportIdCardStrategy 内容

点击查看完整 DynamicImportIdChineseStrategy 内容

点击查看完整 DynamicImportNumberStrategy 内容

4.一个简单的枚举类 —— VerifyModeEnum

点击查看完整 VerifyModeEnum 内容

5.核心 Service 类

点击查看完整 DynamicImportExcelService 内容
温馨提示

核心Service类发生了很多变化,里面注释已经十分完善![aru_53]

6.小例子,以及最终效果

导入模版

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图6

导入结果

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图8

错误数组

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图10

温馨提示

OK,基本实现了校验的编写,这个动态导入功能写到这里,也已经内容过半了[aru_51]

三、第三版优化,代码小重构,加入重复数据相关校验

温馨提示

之前的配置有点略微复杂,目前将策略类抽离到枚举类中,更加的简洁了,更加利于维护,具体改动如下相关类:VerifyModeEnumDynamicImportFactoryDynamicImportInterface、新增VerifyContext类、删除DynamicImportConstants类、相关策略类

通过以下几种方式进一步优化代码,以提高可读性和可维护性:

  1. 简化枚举的使用:直接在枚举类中封装获取策略和错误信息的方法。
  2. 消除重复的代码:将重复代码提取出来,减少冗余。
  3. 引入策略上下文:使用策略上下文来管理策略的执行,避免直接在循环中调用策略。

总结

  1. VerifyModeEnum枚举中添加获取策略实例和错误信息的方法,简化调用逻辑。
  2. 创建VerifyContext类,封装策略的执行逻辑,避免在循环中直接调用策略,提升代码的可读性和维护性。

通过这些改进,代码的结构更加清晰,职责更加分明,易于扩展和维护。

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图12

改动到的相关类

VerifyModeEnum

点击查看完整内容

DynamicImportExcelService

点击查看完整内容

DynamicImportBaseStrategy

点击查看完整内容

DynamicImportFactory

点击查看完整内容

DynamicImportIdCardStrategy

点击查看完整内容

DynamicImportIdChineseStrategy

点击查看完整内容

DynamicImportInterface

点击查看完整内容

DynamicImportNumberStrategy

点击查看完整内容

DynamicImportRepeatDataStrategy

点击查看完整内容

VerifyContext

点击查看完整内容

代码更加的简洁了,从设计层面上来看,更加的清晰、简洁。

导入一览

导入模版

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图14

导入后的效果

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图16
红框位置即为新增的功能,到此,第三版开发完成,距离第一个正式版本更近一步![aru_44]

四、动态导入模版

点击查看完整内容
解析

通过我们定义好的表头,反过来再导出去。数据库增加一个单行的注释,如下图所示

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图18

导出后的效果

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图20

即可实现动态导入模版,搭配使用基本完成大半此功能![aru_51]

五、灵活的错误Excel导出

关键实现代码

            private void saveErrorData() {
                // 构造一个表头
                List<List<String>> headList = dynamicImportExcels.stream()
                        .map(dynamicImportExcel -> Arrays.asList(dynamicImportExcel.getFunctionName()+" —— 错误数据Excel", dynamicImportExcel.getFieldName()))
                        .collect(Collectors.toList());
                headList.add(Arrays.asList(headList.get(0).get(0), "错误原因"));

                File exportPath = new File(exportPathStr);

                if (!exportPath.exists()) {
                    exportPath.mkdirs();
                }

                String fileName = dynamicImportExcels.get(0).getFunctionName() + "_" + "错误数据" + ".xlsx";
                File file  = new File(exportPathStr + File.separator + fileName);

                 // 导出
                getExcel(dynamicImportExcels.get(0).getFunctionName(), file, headList, cachedErrorDataList);

            }

实现效果

博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图22
博主精品——动态Excel导入(包含动态表头校验、动态多种数据校验、动态导入模版)插图24

至此,基本已经完成了动态导入的代码编写,可以说是v0.9的版本了,接下来需要对代码进行相关的调整,个性化的校验类能够实现热拔插的效果即可完成整个功能[aru_36]

六、计划改造对应的保存和校验位置代码,实现更灵活的封装

温馨提示

“行百里路者半九十”

赠元发弟放言

宋·黄庭坚

亏功一篑,未成丘山。凿井九阶,不次水泽。

行百里者半九十,小狐汔济濡其尾。故曰时乎,时不再来。

终终始始,是谓君子。

因为每个项目的导入一定是非常的个性化的,比如说根据什么字段进行覆盖?根据什么情况进行删除?是否可以做更新操作?等等等。。。[aru_110]

发表评论 取消回复
表情 图片 链接 代码

分享