百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

架构师撸轮子~Excel导入导出

toyiye 2024-05-09 18:42 42 浏览 0 评论

产品需求

Excel导入需求说明

  • 支持字段检验:必填、非空、长度限制、数字检验、日期检验等
  • 支持字典翻译:如中文性别转数字、下拉选择中文转代码等
  • 检验失败的单元格,要加批注并能导出提示Excel文件


Excel导出需求说明

  • 支持复杂表头:如跨行跨列、动态标题
  • 生成单元格支持自动计算公式:如求和统计
  • 自动生成下拉选择框:包括下拉单选、下拉多选、级联选择


技术方案

Excel导入流程图

Excel导出流程图

案例展示

1. 导入检验 Excel加批注

2. 导出Excel 自动生成公式

3. 导出Excel 生成单选下拉框

4. 导出Excel 生成级联下拉框

5. 导出Excel 生成多选下拉框

代码集成

1. 添加配置

easy-excel:
  # Excel模板文件
  template-file: excel/template/*.xlsx
  # Excel统计报表SQL配置
  xml-file: excel/xml/*.xml
  # Excel导入导出处理接口
  excel-crud-consumer: com.geline.easyexcel.mybatisplus.config.MyExcelCrudConsumer
  # 清理过期导入Excel异常记录;表参考:sp_excel_file
  expire-delete-sql: delete from sp_excel_file where DATE(created_time) <= DATE(DATE_SUB(NOW(),INTERVAL 7 day))
  # 查询字典数据,支持树形字典;表参考:sp_data_dict
  dict-select-sql: select id, parent_id, code, name, value, level from sp_data_dict where deleted=0 and code=#{code}


2. 导入数据表

CREATE TABLE `sp_excel_file` (
  `id` varchar(32) NOT NULL COMMENT 'id',
  `filename` varchar(200) NOT NULL DEFAULT '' COMMENT '文件名称',
  `bytes` longblob COMMENT '文件流',
  `error_info` text COMMENT '单元格错误信息json',
  `deleted` tinyint DEFAULT '0' COMMENT '删除标识(0:正常,1:删除)',
  `create_by` varchar(120) DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(120) DEFAULT NULL COMMENT '修改人',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) COMMENT='Excel文件表';
CREATE TABLE `sp_data_dict` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
`parent_id` bigint DEFAULT NULL COMMENT '父id',
`code` varchar(80) DEFAULT NULL COMMENT '编码',
`value` varchar(1000) DEFAULT NULL COMMENT '字典项值',
`name` varchar(255) DEFAULT NULL COMMENT '名称',
`sort_num` int DEFAULT NULL COMMENT '排序',
`remark` varchar(200) DEFAULT NULL COMMENT '备注',
`deleted` tinyint DEFAULT '0' COMMENT '删除标识(0:正常,1:删除)',
`create_by` varchar(120) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(120) DEFAULT NULL COMMENT '修改人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`path` varchar(1000) DEFAULT NULL,
`path_name` varchar(1000) DEFAULT NULL,
`level` int DEFAULT '0' COMMENT '层级',
PRIMARY KEY (`id`) USING BTREE
) COMMENT='数据字典(树形结构)';

3. 自定义核心实现类

集成MybatisPlus框架实现类:

@Component
@Slf4j
public class MyExcelCrudConsumer extends MPExcelCrudConsumer {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private ExcelFileDao excelFileDao;
    @Autowired
    private ExcelFileService excelFileService;
    @Autowired
    private ExcelValidFunction validFunction;

    @Override
    public IService getIService(String entityName) {
        return excelFileService;
    }

    @Override
    public void transLabelToKey(Collection entityList) {
        //处理字典翻译
        easyTransService.transBatch(entityList);
    }

    @Override
    public void transKeyToLabel(Collection entityList) {
        //处理字典翻译
        easyTransService.transBatch(entityList);
    }

    @Override
    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    @Override
    public ExcelFileDao getExcelFileDao() {
        return excelFileDao;
    }

    @Override
    public List listData(String entityName, PageQry qry, Class rowClass, boolean currentPage) {
        if (!currentPage) {
            qry.setPageIndex(1);
            qry.setPageSize(50000);
        }
        // 调用业务service分页方法
        IService service = SpringUtil.getBean(StrUtil.lowerFirst(entityName)+"ServiceImpl");
        Page<Object> page = new Page<>(qry.getPageIndex(), qry.getPageSize());
        QueryWrapper wrapper = QueryWrapperUtil.build(qry);
        IPage pageMaps = service.pageMaps(page, wrapper);

        List records = pageMaps.getRecords();
        List rowList = BeanUtil.copyToList(records, rowClass);
        transKeyToLabel(rowList);
        return rowList;
    }

    @Override
    public List handleReportData(List dataList) {
        //处理字典翻译、行政区划翻译
        transKeyToLabel(dataList);
        return dataList;
    }

    @Override
    public ExcelValidFunction getValidFunction() {
        //自定义检验类
        return validFunction;
    }
}

集成JPA框架实现类:

@Component
@Slf4j
public class MyExcelCrudConsumer extends JPAExcelCrudConsumer {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private ExcelFileDao excelFileDao;
    @Autowired
    private ExcelFileRepository repository;
    @Resource
    private TransServiceFactory transServiceFactory;
    @Autowired
    private ExcelValidFunction validFunction;

    @Override
    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    @Override
    public ExcelFileDao getExcelFileDao() {
        return excelFileDao;
    }

    @Override
    public JpaRepository getJpaRepository(String entityName) {
        return repository;
    }

    @Override
    public void transLabelToKey(Collection entityList) {
        //处理字典翻译、行政区划翻译
        entityList.stream().forEach(row -> transServiceFactory.apply(row).labelToKey());
    }

    @Override
    public void transKeyToLabel(Collection entityList) {
        //处理字典翻译、行政区划翻译
        entityList.stream().forEach(row -> transServiceFactory.apply(row).keyToLabel());
    }

    @Override
    public List listData(String entityName, PageQry qry, Class rowClass, boolean currentPage) {
        if (!currentPage) {
            qry.setPageIndex(1);
            qry.setPageSize(50000);
        }
        // 调用业务service分页方法
        Object executor = SpringUtil.getBean(StrUtil.lowerFirst(entityName) + "ServiceImpl");
        PageResponse pageResponse = ReflectUtil.invoke(executor, "findAll", qry);
        List content = pageResponse.getData();
        List rowList = BeanUtil.copyToList(content, rowClass);
        //处理字典翻译、行政区划翻译
        transKeyToLabel(rowList);
        return rowList;
    }

    @Override
    public List handleReportData(List dataList) {
        //处理字典翻译、行政区划翻译
        transKeyToLabel(dataList);
        return dataList;
    }

    @Override
    public ExcelValidFunction getValidFunction() {
        return validFunction;
    }
}

4. 导入检验 失败加批注

@ExcelImport(value = "pipeBuilt")
@Getter
@Setter
public class PipeBuiltImportVO implements Serializable {

    //检验非空且长度<=120
    @ExcelProperty(value = "管廊项目名称", index = 0)
    @ExcelValid(notBlank = true, length = 120)
    private String projectName;

    //检验非null且为整数
    @ExcelProperty(value = "总数", index = 1)
    @ExcelValid(notNull = true, regexEnum = RegexEnum.number)
    private Integer totalNum;

    //检验非null且为小数
    @ExcelProperty(value = "断面截面尺寸", index = 2)
    @ExcelValid(notNull = true, regexEnum = RegexEnum.money)
    private BigDecimal sectionSize;

    //检验非null且保留2位小数
    @ExcelProperty(value = "总长度", index = 3)
    @ExcelValid(notNull = true, regexEnum = RegexEnum.digital_2)
    private BigDecimal totalLength;

    //检验非空且为正确的手机号
    @ExcelProperty(value = "手机号", index = 4)
    @ExcelValid(notBlank = true, regexEnum = RegexEnum.mobile)
    private String phone;

    //检验非空且为正确的邮箱
    @ExcelProperty(value = "邮箱", index = 5)
    @ExcelValid(notBlank = true, regexEnum = RegexEnum.email)
    private String email;
}

核心API

API名称

接口地址

导入Excel

POST:/easyExcel/importExcel/{entity}

检验失败时下载Excel

GET: /easyExcel/downErrorExcel/{entity}?errorId=x

5. 分页查询 导出Excel

@ExcelExportPage(value = "pipeBuilt", title = "管廊", qryClass = PipeBuiltListQry.class)
@Getter
@Setter
public class PipeBuiltExportVO implements Serializable {

    @ExcelProperty(value = "管廊项目名称", index = 0)
    private String projectName;

    //字典代码
    @Schema(description = "投融资模式")
    @TransDict(dictType = "gallery_invest_type", source = "financingModeLabel")
    private String financingMode;

    //生成单选下拉框+字典标签翻译
    @ExcelProperty(value = "投融资模式", index = 1)
    @ExcelDropDown(index = 15, dictName = "投融资模式", dictCode = "gallery_invest_type", type = DropDownType.SELECT)
    @TransDict(dictType = "gallery_invest_type", source = "financingMode")
    private String financingModeLabel;

    //字典代码
    @Schema(description = "管廊类型")
    @TransDict(dictType = "gallery_type", source = "pipeTypeLabel")
    private String pipeType;

    //生成多选下拉框+字典标签翻译
    @ExcelProperty(value = "管廊类型", index = 2)
    @ExcelDropDown(index = 5, dictName = "管廊类型", dictCode = "gallery_type", type = DropDownType.CHECKBOX)
    @TransDict(dictType = "gallery_type", source = "pipeType")
    private String pipeTypeLabel;
}

核心API

API名称

接口地址

下载Excel模板

GET:/easyExcel/exportPageTemplate/{entity}

导出当前页数据

GET:/easyExcel/exportPageExcel/{entity}

参数:?pageIndex=1&pageSize=10¤tPage=true

导出所有数据

GET:/easyExcel/exportPageExcel/townHouse

参数:?pageIndex=1&pageSize=10¤tPage=false

导出当前页勾选项

GET:/easyExcel/exportPageExcel/townHouse

参数:?pageIndex=1&pageSize=10¤tPage=true&ids=11,22

6. 导出Excel (统计报表)

@ExcelExportList(value = "illegalStatistics", title = "全统计")
@Getter
@Setter
public class IllegalStatisticsVO implements Serializable {

    //所属地市
    @ExcelProperty(index = 0)
    private String xzqhdmLabel;
    
    //统计时间
    @ExcelProperty(index = 1)
    private String month;
    
    //治理量(万m2)
    @ExcelProperty(index = 2)
    private BigDecimal byzll;
    
    //其中拆除 (万m2)
    @ExcelProperty(index = 3)
    private BigDecimal byccl;
    
    //治理量(万m2)
    @ExcelProperty(index = 4)
    private BigDecimal dnzll;
    
    //其中拆除 (万m2)
    @ExcelProperty(index = 5)
    private BigDecimal dnccl;
    
    //年治理目标(万m2)
    @ExcelProperty(index = 6)
    private BigDecimal bnzlmb;
    
    //年治理进度,写入自动计算公式
    @ExcelProperty(index = 7, format = "100*E{rowIndex}/F{rowIndex}")
    private String bnzljd;
}

Excel 模板定义-IllegalStatistics.xlsx

Excel 动态查询xml定义

<?xml version="1.0" encoding="UTF-8"?>
<select>
  <!-- 查询传入参数 -->
  <conditions>year,startMonth,endMonth,xzqhdm,curXzqhdm</conditions>
  <!-- 表头动态变量 -->
  <variableMap>{"latestMonth": "{year}年{endMonth}月", "betweenMonth": "{year}年{startMonth}月-{endMonth}月", "zlmbTitle": "{year}年治理目标(万m2)", "zljdTitle": "{year}年治理进度" }</variableMap>
  <!-- 查询SQL:支持变量 ${name} #{name};支持生成动态 where 1=1 [and name=#{name}] -->
  <dynamicSql>
    <![CDATA[
    select s.xzqhdm, s.xzqhdmLabel,
    CONCAT(${year}, '-', ${endMonth}) as month, ROUND(t2.byzll, 2) as byzll,
    ROUND(t2.xzTotal, 2) as xzTotal, ROUND(t2.clTotal, 2) as clTotal,
    from (
    select regionalization as xzqhdm, regionalization_name as xzqhdmLabel,
    trim(TRAILING '0' from regionalization) as city_code
    from sp_ad_code
    where length(trim(TRAILING '0' from regionalization))=4
    ) s
    left join jd_target_reporting t3 on t1.xzqhdm = t3.xzqhdm
    left join sp_ad_code ad on ad.deleted = 0 and ad.regionalization = t1.xzqhdm
    where 1 = 1
    [AND (#{xzqhdm} IS NULL OR t1.xzqhdm LIKE CONCAT(#{xzqhdm},'%'))]
    [AND (#{curXzqhdm} IS NOT NULL OR t1.xzqhdm LIKE CONCAT(#{curXzqhdm},'%'))]
    ]]>
  </dynamicSql>
</select>

Excel 导出数据效果图

核心API

API名称

接口地址

下载Excel模板

GET:easyExcel/exportListTemplate/{reportCode}

导出Excel数据

GET:easyExcel/exportListExcel/{reportCode}?name=xxx

7. 自定义检验单元格数据

@Component
public class MyExcelValidFunction extends ExcelValidFunction {

    @Override
    public List<ExcelError> apply(Integer rowIndex, Object data) {
        //检验属性@ExcelValid
        List<ExcelError> list = ExcelValidUtil.valid(rowIndex, data);

        //检验用户是否拥有此行政区划权限
        Field field = ReflectUtil.getField(data.getClass(), "pathName");
        if(field!=null){
            ExcelProperty property = field.getAnnotation(ExcelProperty.class);
            if(property!=null){
                int colIndex = property.index();
                //...
                list.add(new ExcelError(rowIndex, colIndex, "您无权限导入当前地市数据!"));
            }
        }
        return list;
    }
}

检验效果如下


源码获取

关注作者后私信回复关键词【excel】

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码