java 导入数据和数据验证处理方案

导入数据

导入1万条数据 java 不会内存溢出

使用阿里easyExcel, 批次读入数据,

以下只供参考部分工具类没有

controller
复制代码
/**
 * 上传excel 保存数据
 *   对接系统字段配置表 判断是否已填
 *   上传错误后返回错误信息和生成一个错误数据的excel用于重新处理后倒入
 *
 *   可开启第一行为表达式不导入
 * @param files  上传的文件
 * @return 成功的公用返回
 * @throws Exception 异常
 */
@ApiOperationSupport(order = 500)
@ApiOperation(value = "thirdeti_上传excel数据保存",notes = "上传数据")
@PostMapping(value = "thirdexa_upload_excel"  , consumes = MediaType.MULTIPART_FORM_DATA_VALUE,  headers = "content-type=multipart/form-data" )
public RSuccess thirdexa_upload_excel(
        @ApiParam(name="files",value = "上传的sql文件",required = true)@RequestPart("files")   MultipartFile[] files) throws Exception{
    VoSimpManaMuser currUser=this.getCurUserInfo_throws();


    String callReturnStr=mudiFeignMfile.uploadFiles_busn_str(files, EnumFileSerPath.temp.getPath(),
           null ,true, UtilJsonFast.toJSONString(currUser));
    log.info("开始上传文件");
    //调用微服务上传文件
    UtilRFailJson.strCovertToRFail_throw(callReturnStr);
    JSONObject jsonObject= UtilJsonFast.parseObject(callReturnStr);
    String fileName=jsonObject.getString("firstFileReName");
    log.info("文件上传完成");

    /**
     *   excel数据和服务端匹配 是通过 阿里EasyExcel注释
     *   vo 里面 类 注释 @ExcelProperty(index =1) excel 表示导入绑定excel第几个字段
     */
    String excelFilePath= UtilFileManaPath.getUpByEnumAddPath(EnumFileSerPath.temp,currUser.getTreeauthIdOrg().toString(),fileName);
    // 这里默认读取第一个sheet  ExcelUploadSecmodThirdexa 导入数据处理
    ExcelUploadSecmodThirdexa excelUploadSecmodThirdexa=new ExcelUploadSecmodThirdexa(currUser,serviceSecmodThirdexa,mudiFeignMfile);
    // 可改成2 如果第二行是表达式 或者是复杂表头的这边要设置
    Integer loadBeg=1;
    String eMsg="";
    try {
        EasyExcel.read(excelFilePath, VoSecmodThirdexa.class, excelUploadSecmodThirdexa).sheet().headRowNumber(loadBeg).doRead();
    }catch (ExcelCommonException e) {
        eMsg="导入的excel文件的格式不对,请检查";
        UtilRunTrace.excepCallerLogError(eMsg,e);
        throw new ExceptionCustom(new Error(VarBaseError.e0_inp,new String[]{eMsg}));
    }catch (ExcelAnalysisException e){
        eMsg="数据填写格式有误,请检查";
        UtilRunTrace.excepCallerLogError(eMsg,e);
        throw new ExceptionCustom(new Error(VarBaseError.e0_inp,new String[]{eMsg}));
    }catch (Exception e){
        eMsg="excel文件内容错误,请检查";
        UtilRunTrace.excepCallerLogError(eMsg,e);
        throw new ExceptionCustom(new Error(VarBaseError.e0_inp,new String[]{eMsg}));
    }
    // 返回不能导入的excel信息提供下载地址
    String[] importErrorSet=ExcelUploadSecmodThirdexa.importErrorSet.get();
    RSuccess re=new RSuccess();
    re.setRsda(importErrorSet);
    return re;
}
AnalysisEventListener 上传处理
复制代码
package com.fircom.secmod.help.excelUpload;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.common.base.enums.EnumFileType;
import com.common.base.var.VarTime;
import com.common.buscomm.enums.EnumFileSerPath;
import com.common.buscomm.excep.ExceptionCustom;
import com.common.buscomm.ini.varLoad.VarLoadSysStaticCache;
import com.common.buscomm.util.excep.UtilRFailJson;
import com.common.buscomm.vo.error.Error;
import com.common.buscomm.vo.muser.VoSimpManaMuser;
import com.common.ini.util.UtilFileManaPath;
import com.common.inimvc.help.var.VarJdUrl;
import com.common.mvc.help.util.excel.UtilExcelMvc;
import com.fircom.secmod.help.feign.MudiFeignMfile;
import com.fircom.secmod.service.ServiceSecmodThirdexa;
import com.fircom.secmod.vo.VoSecmodThirdexa;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * 上传处理类
 */
@Slf4j
public class ExcelUploadSecmodThirdexa extends AnalysisEventListener<VoSecmodThirdexa> {


    public ExcelUploadSecmodThirdexa(VoSimpManaMuser voSimpManaMuser, ServiceSecmodThirdexa serviceSecmodThirdexa,
    MudiFeignMfile mudiFeignMfile) {
        this.voSimpManaMuser = voSimpManaMuser;
        this.serviceSecmodThirdexa = serviceSecmodThirdexa;
        this.mudiFeignMfile=mudiFeignMfile;
    }

    /**
     * 操作用户
     */
    private VoSimpManaMuser  voSimpManaMuser;

    private ServiceSecmodThirdexa  serviceSecmodThirdexa;

    private MudiFeignMfile mudiFeignMfile;

    /**
     * 处理到第几条数据
     */
    private Integer  dealDataNum=0;

    /***
     *  导入数据异常信息
     *    线程变量 本线程可全局访问
     *    String[0] 放错误信息
     *    String[1] 放错误的文件链接
     */
    public static ThreadLocal<String[]> importErrorSet = new ThreadLocal<String[]>();




    /**
     * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 5;
    List<VoSecmodThirdexa> list = new ArrayList<VoSecmodThirdexa>();
    /**
     * 全部导入错误的vos
     */
    List<VoSecmodThirdexa> listImportThirdexasError =new ArrayList<VoSecmodThirdexa>();
    /**
     * 全部导入错误信息
     */
    String errMsgAll="";

    @Override
    public void invoke(VoSecmodThirdexa data, AnalysisContext context) {
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        list.add(data);
        if (list.size() >= BATCH_COUNT) {
            saveData();
            list.clear();
        }
    }

    /**
     * 导入数据
     *   正常的数据导入
     *   异常的数据导出
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 导入数据 正常的数据导入
        if (list.size()>0) {
            saveData();
        }
        // 导入数据返回的异常信息赋值给 importErrorSet
        String[] errorData=new String[2];
        if(listImportThirdexasError.size()>0){
            String tempFileAllPath= UtilExcelMvc.getTempFileProPath("fircpro","secmodThirdexaOperVos.xlsx");
            EnumFileSerPath enumFileSerPath=EnumFileSerPath.temp;
            // 生成的文件名
            String fileName="errorOut" + System.currentTimeMillis() + ".xlsx";
            // 生成的文件全路径
            String fileNameAll = UtilFileManaPath.getUpByEnumRunTreeauthAddPath(enumFileSerPath,fileName);
            // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
            EasyExcel.write(fileNameAll, VoSecmodThirdexa.class).withTemplate(tempFileAllPath).sheet().doFill(listImportThirdexasError);

            String uuid=UUID.randomUUID().toString();
            // 文件服务器生成记录
            String  callReturn= mudiFeignMfile.mfile_insert(com.common.ini.util.UtilTreeauthUse.getTreeauthOrgId_use(null,false),
                    voSimpManaMuser.getMuserId(),
                    uuid,
                    "导入返回的错误excel"+"_"+ DateUtil.format(new Date(), VarTime.data_allNumFormat)+".xlsx",
                    fileName,
                    enumFileSerPath.getPath(),
                    EnumFileType.excelType.getContentType()
            );
            UtilRFailJson.strCovertToRFail_throw(callReturn);
            // 错误的文件连接
            errorData[1]= VarJdUrl.downJdFile_mfileBusn+uuid;
        }
        errorData[0]=errMsgAll;
        importErrorSet.set(errorData);

        log.info("所有数据解析完成!");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", list.size());

        for(VoSecmodThirdexa voSecmodThirdexa:list){
            dealDataNum++;
            voSecmodThirdexa.setDataNum(dealDataNum);

            try {
                serviceSecmodThirdexa.saveOrUpdate_thirdexa_byVo(voSecmodThirdexa,voSimpManaMuser);
            } catch (ExceptionCustom exceptionCustom) {
                List<Error> errors= exceptionCustom.getErrors();
                String eMsg=errors.get(0).fillEMsg(VarLoadSysStaticCache.enumLanguage.getCode());
                log.warn(eMsg);
                errMsgAll=errMsgAll+eMsg;

                VoSecmodThirdexa error=new VoSecmodThirdexa();
                BeanUtil.copyProperties(voSecmodThirdexa,error);
                listImportThirdexasError.add(error);
            }
        }
    }

}

数据验证

导入失败的数据再次导出给用户
复制代码
String tempFileAllPath= UtilExcelMvc.getTempFileProPath("fircpro","secmodThirdexaOperVos.xlsx");
EnumFileSerPath enumFileSerPath=EnumFileSerPath.temp;
// 生成的文件名
String fileName="errorOut" + System.currentTimeMillis() + ".xlsx";
// 生成的文件全路径
String fileNameAll = UtilFileManaPath.getUpByEnumRunTreeauthAddPath(enumFileSerPath,fileName);
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileNameAll, VoSecmodThirdexa.class).withTemplate(tempFileAllPath).sheet().doFill(listImportThirdexasError);
相关推荐
带刺的坐椅7 分钟前
Solon Expression Language (SnEL):轻量高效的Java表达式引擎
java·solon·snel·表达式语言
老马啸西风12 分钟前
从零开始手写redis(18)缓存淘汰算法 FIFO 优化
java
444A4E13 分钟前
理解Linux环境:从命令行参数到环境变量
linux·操作系统
阿巴~阿巴~16 分钟前
Linux安全基石:Shell运行原理与权限管理系统解读
linux·服务器
广州山泉婚姻25 分钟前
Python 爬虫简单示例
爬虫·python
Java中文社群25 分钟前
超实用!SpringAI提示词的4种神级用法
java·人工智能·后端
站大爷IP39 分钟前
Python文件读写操作详解:从基础到实战
python
代码or搬砖1 小时前
Spring JDBC配置与讲解
java·数据库·spring
魔芋红茶1 小时前
Spring 源码学习 3:工厂后处理器
java·学习·spring
m0_634865401 小时前
sa-token:我将代替你,Spring Security
java·后端·spring