问题描述
测试出来一个问题,使用地市的角色,导出数据然后超过了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,然后就提示报错了,该说不说这个问题我真的找了好久,因为确实是文件找不到报错的地方。