一个通用的Excel导入导出功能

数据的导入功能 在数据库中的操作: 先声明一个方法,引入导入模板的下载,MapPath指的是在派生类中重写时,返回与 Web 服务器上的指定虚拟路径相对应的物理文件路径。 在一个文件中追加文本行,然后关闭该文件。如果指定文件不存在,此方法会创建一个文件,向其中写入指定的行,然后关闭该文件。判断如果有文件,就返回该文件,通过EXCEL打开,反之,则返回模板文件不存在的提示信息。 第二步:excel表格数据上传,先获取要读取的文件;把文件转换为二进制数组;二进制数组转成内存流;利用NPOI把内存流中的数据读 阅读详情

前言

Excel表单导入,是将Excel文件中的数据导入到数据库;而Excel表单导出,是将数据库的数据导出到Excel文件中。
在本文中开发的功能是基于SpringBoot + JPA框架进行开发,而在系统中,数据库表结构又分成了两种情况,一种是单表结构,另一种是存在@OneToMany注解的主外键关联的主辅表结构,所以本次开发目的是可以同时兼容两种情况。
另外,因为不同的数据表对应的Excel表单的数据和格式都不同,但是为每一个数据表定制化开发Excel导入导出,工作重复度高,所以本次开发另一个目的是能够做到所有数据表通用Excel表单导入导出。

起步

SpringBoot和JPA的环境请读者自行准备,在这里引入poi依赖来协助开发,版本选择4.0.1。

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>${poi.version}</version>
</dependency>
 
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>${poi.version}</version>
</dependency>

开始

设计思路
在这里插入图片描述

功能设计

导入和导出功能都能通过传入的服务参数,完成对指定表结构的导入或导出。
如:http://127.0.0.1/excel/{SERVER_NAME}/import (导入)
       http://127.0.0.1/excel/{SERVER_NAME}/export (导出)

一、Excel导出

1、导出目标

可以导出两种形式的Excel文件:
(1)数据模版,用于数据填入后进行Excel导入功能,命名规则为:Excel-‘name’-Template.xlsx(如:Excel-Project-Template.xlsx);
(2)指定时间区间的数据,命名规则为:Excel-‘name’.xlsx(如:Excel-Project.xlsx)。

2、导出格式
将数据表的字段以字段名+‘-’的格式(如:id-),依次插入到表单的首行单元格。如果导出的是指定区间的数据,则会在首行行尾追加’createTime’和‘createBy’两个字段,分别表示数据创建时间和数据创建人(关联关系表结构中,只在主表中追加),再将数据逐行插入。
*注:表头字段的设计(如:id-),是为了方便用户在填入自己需要导入数据的过程中,可以在表头字段后加上自己的注解(如:id-编号),并且不影响Excel表单的数据导入,数据填入过程中,请保留’-'符号。

3、导出结构
单表结构:在Entity字段定义中,不存在@OneToMany注解,在该结构下,只有一张Excel工作簿。
关联关系表结构:在Entity字段定义中,存在@OneToMany注解,在该结构下,需要新建Excel工作薄,再将字段或数据填入新的工作簿中。

二、Excel导入
1、导入规则
将数据表的字段以字段名+‘-’的格式(如:id-),依次插入到表单的首行单元格,再将数据逐行填入字段对应的同列单元格即可。表头字段名后可以加上自己的注解(如:id-编号),不影响表单的正常导入。

*注:为避免用户由于Excel表单格式的问题,数据导入失败,请用户先使用Excel导出功能,导出一份表单模板,再将数据填入模板后进行导入操作,保证数据可正常导入。

*注:若导入的数据为关联关系表结构,则辅表工作簿中的关联字段数据需要和主表工作薄中的主键字段数据保持一致。

2、导入操作
根据@Id注解和@GeneratedValue注解判断主键的类型,对主键做特殊处理,若是自增主键,会将主键置为空,保证数据只做插入操作,不做更新操作;而若是非自增主键,不做处理,数据可以进行插入操作,或者对数据库已经存在该主键的数据进行更新操作。

3、导入反馈
在数据转化后,会将数据逐条存入数据库,而在这个过程中,可能会存在数据的错误或者别的问题导致部分数据的存储失败,但是部分数据的存储失败不会导致整个Excel表单数据存储的失败回滚,而是将存储失败的数据对应的Excel表单单元行和失败原因反馈给用户,如:导入数据总数,成功导入数据总数,失败导入数据总数以及失败导入原因。

服务设计

  • 内部服务设计
    在这里插入图片描述

(1)RIA报表服务抽象接口

/**
 * RIA报表服务抽象接口
 * @author xinyao.zhang
 */
public interface BaseRiaExcelService {
    /**
     * 导入Excel文件数据
     * @param file 文件
     * @return JSONObject
     */
    default JSONObject importExcelData(MultipartFile file){return null;}

    /**
     * Excel文件 转List数据
     * @param file
     * @return
     */
    default List excelDataConvert(MultipartFile file){return null;}

    /**
     * 导出Excel文件数据
     * @param flag 0:导出Excel格式 1:导出指定时间区间数据
     * @param beginTime 开始时间
     * @param endTime   结束时间
     * @param response  返回数据
     */
    default void exportExcelData(Integer flag, Long beginTime, Long endTime, HttpServletResponse response){}

    /**
     * 数据构建Excel文件
     * @param flag
     * @param beginTime
     * @param endTime
     */
    default XSSFWorkbook dataToExcel(Integer flag, Long beginTime, Long endTime){return null;}

}

(2)RIA基础服务类

/**
 * RIA基础服务类
 * @author xinyao.zhang
 */
public interface BaseRiaService extends BaseService,BaseRiaExcelService{
}

(3)基础服务接口

/**
 * 基础服务接口
 * @author xinyao.zhang
 */
public interface BaseService<T, ID extends Serializable> {

    /**
     * 查找单个实例
     * @param id 实例ID
     * @return T
     */
    T find(ID id);
}

(4)基础服务逻辑层

/**
 * 基础服务逻辑层
 * @author xinyao.zhang
 */
public class BaseServiceImpl<T, ID extends Serializable> implements BaseService<T, ID> {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    protected Class<T> entityClass = (Class<T>) GenericClassUtils.getSuperClassGenericType(getClass(), 0);

    protected Class<ID> idClass = (Class<ID>) GenericClassUtils.getSuperClassGenericType(getClass(), 1);

    protected BaseJpaRepository<T, ID> baseJpaRepository;

    public BaseServiceImpl(BaseJpaRepository baseJpaRepository){
        this.baseJpaRepository = baseJpaRepository;
    }

    @Override
    public T find(ID id){
        T optional = null;
        //ID类型转换
        if(idClass.isInstance(id)){
            optional = baseJpaRepository.findOne(idClass.cast(id));
        }else{
            switch (idClass.getName()) {
                case "java.lang.String":
                    optional = baseJpaRepository.findOne(idClass.cast(String.valueOf(id)));
                    break;
                case "java.lang.Integer":
                    optional = baseJpaRepository.findOne(idClass.cast(Integer.valueOf(id.toString())));
                    break;
                case "java.lang.Long":
                    optional = baseJpaRepository.findOne(idClass.cast(Long.valueOf(id.toString())));
                    break;
                default:
                    break;
            }
        }
        if(null != optional){
            return optional;
        }
        return null;
    }
}

(5)泛型工具类

/**
 * 泛型工具类
 * @author xinyao.zhang
 */
@SuppressWarnings("rawtypes")
public class GenericClassUtils {

    public static Class getSuperClassGenericType(Class clazz, int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            return null;
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        if (index >= params.length || index < 0) {
            return null;
        }

        if (!(params[index] instanceof Class)) {
            return null;
        }
        return (Class) params[index];
    }
}

(6)RIA基础实现基类

/**
 * RIA基础实现基类
 * @author xinyao.zhang
 * @param <T>
 * @param <ID>
 */
@SuppressWarnings("unchecked")
public abstract class BaseRiaServiceImpl<T, ID> extends BaseServiceImpl implements BaseRiaService {

    private static final Logger logger = LoggerFactory.getLogger(BaseRiaServiceImpl.class);

    private BaseRiaExcel<T,ID> tBaseRiaExcel;

    public BaseRiaServiceImpl(BaseJpaRepository baseJpaRepository) {
        super(baseJpaRepository);
        tBaseRiaExcel = new BaseRiaExcel(entityClass,idClass,baseJpaRepository);
    }
    
    protected BaseRiaExcel baseRiaExcel() {
        return tBaseRiaExcel;
    }
    
    @Override
    public JSONObject importExcelData(MultipartFile file) {
        return tBaseRiaExcel.importExcelData(excelDataConvert(file));
    }

    @Override
    public List excelDataConvert(MultipartFile file) {
        return tBaseRiaExcel.excelDataConvert(file);
    }

    @Override
    public void exportExcelData(Integer flag, Long beginTime, Long endTime, HttpServletResponse response) {
        tBaseRiaExcel.exportExcelData(dataToExcel(flag, beginTime, endTime), flag, response);
    }

    @Override
    public XSSFWorkbook dataToExcel(Integer flag, Long beg
通用Excel导入设计 摘要:有时候我们的数据存放在Excel中(特别是对于用户来说更喜欢使用Excel收集一些常用数据),而系统又需要这些数据来处理其他业务,那么此时我们就需要将这些数据导入到数据库中。但是鉴于Excel的样式多种多样,因此每次导入时都必须书写很多重复的代码。很明显对于一个软件开发者做这些重复劳动是一件很无趣的事情。那么怎样来寻中一种通用的方法呢?今天我们就一块看一下如何来解决这个问题。 主要内容 Excel操作组件的选择 总体设计思路 配置文件设计 类设计 编码实现 一点补充 简单的测试 总结 阅读详情

相关推荐

Spring Boot 如何设计一个通用的 Excel 导入导出功能?

以上是我对导出功能的思考和实现思路,因为篇幅的关系,我没有贴出完整的代码,但是相信以上内容已经足够大家作为参考,缺少的内容,比如列宽、颜色字体等设置,请查阅EasyExcel官方文档来实现,主要方式就是根据前端传过来的JSON配置信息,来动态配置EasyExcel的导出文件。,也没有分页查询参数,类似于当前页导出,在也只考虑一层包装类的情况下,没有额外的配置项,上面的已经足够了,要注意的就是代码里面得把分页参数剔除掉。批量保存的数量不能太多,要考虑系统和数据库的性能,比如每次读取500行就执行一次保存。

Mr丶·Zhou博客 3270

硅传CC1310二次开发必备:手把手教你用JTAG解锁被锁定的Flash存储器

本文针对硅传CC1310模块二次开发中常见的Flash锁定问题,提供了从原理剖析到实战操作的完整解决方案。详细介绍了如何使用Uniflash和Flash Programmer 2等工具进行Flash解锁和擦除,并强调了硬件连接稳定性与供电质量的关键作用,帮助开发者彻底解决烧录障碍,为后续应用开发铺平道路。

weixin_29189373的博客 254

手把手教你绕过网易易盾验证码:滑块、点选、语序全攻略

本文深度解析了以网易易盾为代表的现代验证码技术,重点探讨了滑块、点选、语序及空间推理等交互式验证码的工作原理与对抗策略。文章从行为验证和空间推理的核心逻辑出发,剖析了验证码交互的数据流与关键参数,并提供了模拟人类行为轨迹、维护设备指纹等工程实践方法,旨在帮助开发者在合规前提下设计更健壮的自动化流程。

3c4x5z6v7b的博客 704

非华为电脑也能用!华为电脑管家完美安装教程来了

GitHub 上有一个开源项目 ​****​,专门解决“非华为设备无法安装华为电脑管家”的问题。它通过智能模拟 + DLL 劫持技术,绕过官方对硬件型号的检测,让你在联想、戴尔、华硕甚至 DIY 主机上也能流畅使用华为电脑管家!⭐ 项目已获 ​700+ Stars​,社区活跃,持续更新,兼容性优秀!科技不该有围墙。如果你成功在非华为电脑上跑起了 PCManager,欢迎在评论区晒出你的设备型号 + 使用体验!也别忘了把这篇推文分享给同样“眼馋”华为生态的朋友 ~📱 ​关注我们。

程序员朱永胜 4918

不懂就学之挑战成为WorldQuant Brain顾问的第1天

WorldQuant Brain 是由 WorldQuant 公司开发的一个基于人工智能和机器学习的量化研究平台,旨在帮助量化研究员发现和构建有效的投资策略。WorldQuant 是一家全球领先的量化投资公司,专注于利用数据科学、技术和金融工程开发量化交易策略。

Yanbang1的博客 8385

华为项目TR5评审后发现了重大缺陷的应急处理经验

华为TR5评审后发现重大缺陷时,启动分级应急机制:1)缺陷分级:按严重性(致命/严重/一般)评估影响;2)应急响应:跨部门会议制定方案,冻结生产并调配资源;3)根因修复:通过RCA定位问题,设计变更后回归测试;4)变更管理:评审修复影响,调整发布策略;5)持续改进:记录缺陷闭环,优化流程。案例显示,软件闪退问题通过热修复补丁和代码重构解决。关键工具包括Jira、FMEA等,确保缺陷在量产前拦截,降低风险。

从技术实践立足,从项目管理方法论延伸思考 1069

OpenTK简介

OpenTK 因其强大的功能、跨平台特性和灵活性,适用于多种需要图形和计算能力的应用场景,为开发者提供了丰富的可能性和创作空间。

仰望星空的博客 1980

注册GitHub时出现Unable to verify your captcha response.Please visit https://docs.github.com/解决方案(持续更新)

本文主要介绍了注册GitHub时出现Unable to verify your captcha response. Please visit https://docs.github.com/articles/troubleshooting-connectivity-problems/#troubleshooting-the-captcha for troubleshooting information.解决方案,希望能对学习使用GitHub的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 8万+

Ardupilot chibios IO固件,IO与FMU通信,固件下载(3)

目录 文章目录目录摘要 摘要 本节主要记录自己学习IO与FMU通信

陌城烟雨 2801

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

上一篇: SpringBoot整合RocketMQ消息队列demo
下一篇: 关于敏捷的一点收获
IceCaptain
博客等级 码龄10年 12粉丝 19原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值