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);
相关推荐
予枫的编程笔记9 小时前
【Linux进阶篇】Linux后台运行避坑指南:nohup、& 用法及Systemd守护进程实操
linux·进程管理·linux运维·nohup·systemctl·ps命令·kill命令
打工的小王9 小时前
java并发编程(七)ReentrantReadWriteLock
java·开发语言
lang201509289 小时前
Java并发革命:JSR-133深度解析
java·开发语言
禹凕9 小时前
Python编程——进阶知识(面向对象编程OOP)
开发语言·python
abluckyboy9 小时前
基于 Java Socket 实现多人聊天室系统(附完整源码)
java·开发语言
code monkey.9 小时前
【Linux之旅】Linux 进程间通信(IPC)全解析:从管道到共享内存,吃透进程协作核心
linux·c++·ipc
Re.不晚9 小时前
JAVA进阶之路——数据结构之线性表(顺序表、链表)
java·数据结构·链表
毅炼9 小时前
Java 基础常见问题总结(3)
java·开发语言
匆匆那年9679 小时前
llamafactory推理消除模型的随机性
linux·服务器·学习·ubuntu
一晌小贪欢10 小时前
深入理解 Python HTTP 请求:从基础到高级实战指南
开发语言·网络·python·网络协议·http