导出问题处理

问题描述

测试出来一个问题,使用地市的角色,导出数据然后超过了20w的数据,提示报错,我还以为是偶然的问题,然后是发现是普遍的问题,本地环境复现了,然后是,这个功能是三套角色,分别是集团,省份,地市。我用集团,省份角色查了这个地市,导出数据没有问题,然后我就好奇了。

报错问题

java 复制代码
2024-10-22 15:17:05.612 ERROR 38604 --- [ XNIO-1 task-38] c.a.a.c.AssetDetailsQueryLocalController : exception's message:68
2024-10-22 15:18:59.375  INFO 38604 --- [ XNIO-1 task-38] cn.chinaunicom.ams.utils.EasyExcelUtils  : 压缩完成,耗时:5877 ms
2024-10-22 15:18:59.504 ERROR 38604 --- [ XNIO-1 task-38] cn.chinaunicom.core.util.CephUtil        : exception's message:java.io.FileInputStream.open0(Native Method)
2024-10-22 15:18:59.511 ERROR 38604 --- [ XNIO-1 task-38] cn.chinaunicom.core.util.CephUtil        : exception's message:上传文件:对象名export\2024\10\22\资产明细报表_20241022_151557260.xlsx,全路径file/ams/export\2024\10\22\资产明细报表_20241022_151557260.xlsx
2024-10-22 15:18:59.512 ERROR 38604 --- [ XNIO-1 task-38] c.a.a.c.AssetDetailsQueryLocalController : exception's message:cn.chinaunicom.core.util.CephUtil.uploadExportFile(CephUtil.java:191)

代码描述

java 复制代码
 /**
     * 资产全量报表查询-导出资产全量报表信息 期间查询
     * @param response
     * @param request
     * @param requestBody
     */
    @ResponseBody
    @PostMapping("/exportDetailViewListPeriodName")
    @ApiOperation(value = "资产全量报表查询-导出资产全量报表信息", notes = "资产全量报表查询-导出资产全量报表信息")
    @OperateLog("资产全量报表查询-导出资产全量报表信息")
    @RsaDecrypt(msg = "查询失败", isModuleSign = true, moduleName = "AssetDetailsQueryAllRequestBody")
    public void exportDetailViewListPeriodName(AssetDetailsQueryLocalRequestBody requestBody,HttpServletResponse response, HttpServletRequest request) {
        try {
            //j后台取值 账簿信息
            List<String> bookTypeCodeList = constantAbtOracleService.getBookTypeCodes("1");

            /**
             * 账簿后台获取
             */

            if(bookTypeCodeList.size() == 1){
                requestBody.setBookTypeCode(bookTypeCodeList.get(0));
            }
            String condition = assetDetailsQueryLocalService.queryViewListForExportcondition(requestBody);
            if(StringUtils.isNotBlank(requestBody.getManufacturerName())){
                requestBody.setManufacturerName(URLDecoder.decode(requestBody.getManufacturerName()));
            }
            long start = System.currentTimeMillis();
            int count = 0;
            //批量资产编号
            String[] assetNumberStr = null;
            if (requestBody.getAssetNumbers() != null && !("").equals(requestBody.getAssetNumbers())) {
                assetNumberStr = requestBody.getAssetNumbers().split(",");
            }
            requestBody.setAssetNumberStr(assetNumberStr);

            //批量资产标签号
            String[] tagNumberStr = null;
            if (requestBody.getTagNumbers() != null && !("").equals(requestBody.getTagNumbers())) {
                tagNumberStr = requestBody.getTagNumbers().split(",");
            }
            requestBody.setTagNumberStr(tagNumberStr);


            Date nowTime = new Date();
            // 往数据库存储的路径(不含配置的前缀路径)
            String dbSavePath = "export" + File.separator + new SimpleDateFormat("yyyy").format(nowTime)
                    + File.separator + new SimpleDateFormat("MM").format(nowTime)
                    + File.separator + new SimpleDateFormat("dd").format(nowTime)
                    + File.separator;
            // 临时文件实际保存路径
            String fileSavePath = ExportExcelUtils.getImplementTemplate(request) + dbSavePath;
            // 获取保存路径,没有对应目录的话自行创建
            String savePath = FileUtil.createDir(fileSavePath);
            Date d = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmssSSS");
            String dateNowStr = sdf.format(d);

            AssetExportFile exportFile = new AssetExportFile();
            String fileName="";
            String fileType="";

            String fileNameInfo="";
            fileNameInfo = "资产明细报表_";

            fileName=fileNameInfo+dateNowStr;
            exportFile.setFileName(fileName);

            //导出临时文件的命名
            String filePathFront= savePath + "资产明细报表_" + dateNowStr;
            // 数据库里存的文件路径即上传到云平台的文件命名
            exportFile.setFilePath(filePathFront);
            NowUser nowUser = WebUtil.getNowUser();
            exportFile.setCreatedBy(nowUser.getStaffId());
            Date date = new Date();
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //导出文件记录中新增一条记录
            exportFile.setCreatedDate(sdf1.format(date));
            exportFile.setExportStatus(FlowUtils.EXPORT_START);
            exportFile.setCreateName(nowUser.getStaffName());
            exportFile.setFileCondition(condition);

            final int file1 = exportFileService.insertExportFile(exportFile);
            String exportFileId = exportFile.getId();


//            String endChar = requestBody.getBookTypeCode().substring(3,5);
            String endChar = assetDetailsQueryAllService.getTableNameByBookTypeCode(requestBody.getBookTypeCode());
            String periodName = requestBody.getPeriodName().replace("-","");

            requestBody.setTableName("CAMS_ASSET_DETAIL_" + endChar+"_"+periodName);
            //1、根据查询条件获取集合-erp
            List<AssetDetailsExcel> result=new ArrayList<>();//返回结果
            //开始查询的行数
            long startTime = System.currentTimeMillis();
            try{
                //1、根据查询条件获取集合-erp
                result = assetDetailsQueryLocalService.queryViewListForExportPeriodName(requestBody);
            }
            catch(Exception exception){
                log.error("导出数据异常:" + exception);
            }
            long endTime = System.currentTimeMillis();

            count=result.size();

            if(count>FlowUtils.COUNT_FOR_TYPE){//生成zip格式
                fileName=fileNameInfo+dateNowStr+".zip";
                fileType=FlowUtils.ZIP_TYPE;
                exportFile.setFileType(fileType);
            }else{// 生成xlsx格式
                fileName= fileNameInfo+dateNowStr+".xlsx";
                fileType=FlowUtils.XLSX_TYPE;
                exportFile.setFileType(fileType);
            }
            exportFile.setFileName(fileName);

            // 导出临时文件最终命名和路径
            String finalFilePath = filePathFront + "." + fileType;
            //上传到服务器的实际文件的命名
            String finalFileName = dbSavePath + "资产明细报表_" + dateNowStr + "." + fileType;
            // 数据库里存的文件路径即上传到云平台的文件命名
            exportFile.setFilePath(finalFileName);

            log.error("exception's message:{}", String.valueOf((endTime - startTime) / 1000));
            //一个excel的总数据量
            int oneExcelSize = FlowUtils.ONE_EXCEL_SIZE;
            //需导出的总数据量
            int resultCount = result.size();
            //计算需要导出的excel的个数
            int excelCount = resultCount%oneExcelSize==0?resultCount/oneExcelSize:(resultCount/oneExcelSize +1);
            //声明fileList,大小为excelCount
            final List<File> resultFileList = new ArrayList<>(excelCount);


            EasyExcelUtils easyExcelUtils = new EasyExcelUtils();
            if (excelCount>1){
                // 多个文件,多线程并发写入
                for(int i=0;i<excelCount;i++){
                    resultFileList.add(null);
                }

                for(int i=0;i<excelCount;i++){
                    final int index =i;
                    // 按每个excel的数据量大小来切分查询结果list
                    final List<AssetDetailsExcel> res = resultCount<(index+1)*oneExcelSize?result.subList(index*oneExcelSize,resultCount):result.subList(index*oneExcelSize,(index+1)*oneExcelSize);
                    //文件命名
                    String excelFileName = savePath+"资产明细报表_"+dateNowStr+"-"+String.valueOf(i+1)+".xlsx";
                    File file = new File(excelFileName);
                    resultFileList.set(index,file);
                    EasyExcel.write(excelFileName,AssetDetailsExcel.class).sheet("sheet").doWrite(res);

                }
                // 压缩文件
                final File file = easyExcelUtils.compressFile(resultFileList, true, exportFileId, filePathFront);
            } else {
                EasyExcel.write(finalFilePath,AssetDetailsExcel.class).sheet("sheet").doWrite(result);
            }
            //文件上传到慧企平台 --todo
            CephUtil.uploadExportFile(finalFileName, finalFilePath);
            //文件上传到慧企平台后删除临时文件 todo
            boolean resultTemp = valueSetController.executeFile(finalFilePath);
            // 更新导出文件记录
            exportFile.setId(exportFileId);
            exportFile.setExportStatus(FlowUtils.EXPORT_DONE);
            exportFileService.updateStatusFileNameById(exportFile);

            long end = System.currentTimeMillis();

        } catch (Exception e) {
            log.error("exception's message:{}",e.getStackTrace());
        }
    }


	/**
	 * 本地文件上传到ceph
	 *
	 * @param objName 上传上去的对象名(经测试长度不能超1024)
	 * @param fileAllPath 将要上传的本地文件全路径
	 * @return
	 */
	public static boolean uploadExportFile(String objName, String fileAllPath) throws IOException {
		FileInputStream fis = null;
		try {
			AmazonS3 conn = connCeph();
			File file = new File(fileAllPath);
			int imageSize = 0;
			try {
				fis = new FileInputStream(file);
				imageSize = fis.available();
			} catch (Exception e) {
				log.error("exception's message:{}",e.getStackTrace());
			}
			ObjectMetadata om = new ObjectMetadata();
			om.setContentLength(imageSize);
			conn.putObject(DEFAULT_BUCKET_NAME, objName, fis, om);
			if (ONLINE.equals("true")) {
				fis = new FileInputStream(file);
				AmazonS3 conn2 = connCeph2();
				conn2.putObject(DEFAULT_BUCKET_NAME2, objName, fis, om);
				log.error("exception's message:{}", "上传文件:对象名" + objName + ",全路径" + fileAllPath);
				return true;
			}
		} catch (Exception e) {
			log.error("exception's message:{}", "上传文件:对象名" + objName + ",全路径" + fileAllPath);
		} finally {
			fis.close();
		}
		return false;
	}

问题处理

真的找了好久,想到了一个思路才发现了问题处理,首先,这个报错提示是找不到文件,然后开始倒查。首先,这个功能是,有三套前端,两套后端,然后这也是我后面反应过来的问题,问题是出现在地市的角色上,地市角色使用本功能因为数据量在20w,增加一个条件之后导出了300条数据,直到我一条一条debug,发现提示找不到文件,然后在删除文件之前我去debug,找了具体的问题。

直到发现了这个问题,我才想起来,之前我改了一版,修改的是最大的文件数是从100000变成了300000,然后发现我只改了一个静态变量,只改了一个文件的判断是不是最多条的数量,但是一个excel中的最大条数还是100000,然后就提示报错了,该说不说这个问题我真的找了好久,因为确实是文件找不到报错的地方。

相关推荐
四谎真好看1 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程1 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t1 小时前
ZIP工具类
java·zip
lang201509282 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
pengzhuofan3 小时前
第10章 Maven
java·maven
百锦再3 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说3 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多3 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
百锦再4 小时前
对前后端分离与前后端不分离(通常指服务端渲染)的架构进行全方位的对比分析
java·开发语言·python·架构·eclipse·php·maven
DokiDoki之父4 小时前
Spring—注解开发
java·后端·spring