package com.bcxin.ferry.service; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.crypto.digest.MD5; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bcxin.ferry.common.CommonConstant; import com.bcxin.ferry.common.emus.FerryTaskFileStatusEnum; import com.bcxin.ferry.common.emus.FileTypeEnum; import com.bcxin.ferry.common.emus.SendBoundaryUrlEnum; import com.bcxin.ferry.common.utils.Base64Util; import com.bcxin.ferry.common.utils.DateUtil; import com.bcxin.ferry.common.utils.FileSpiltMergeUtil; import com.bcxin.ferry.common.utils.IdGeneratorSnowflake; import com.bcxin.ferry.configs.BoundaryServerConfig; import com.bcxin.ferry.dao.mapper.FerryTaskFileMapper; import com.bcxin.ferry.dao.mapper.FerryTaskMapper; import com.bcxin.ferry.dtos.FerryFileDto; import com.bcxin.ferry.dtos.response.boundary.BoundaryResult; import com.bcxin.ferry.entity.FerryTaskEntity; import com.bcxin.ferry.entity.FerryTaskFileEntity; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.File; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; /** * 摆渡任务文件表(ferry_task_file)服务实现类 * * @author : linchunpeng * @date : 2024-3-6 */ @Slf4j @Service public class FerryTaskFileService extends ServiceImpl { @Autowired private SendRequestToBoundaryService sendRequestToBoundaryService; @Autowired private FerryTaskMapper ferryTaskMapper; @Autowired private BoundaryServerConfig boundaryServerConfig; @Autowired private IdGeneratorSnowflake snowflake; /** * description:根据摆渡任务id,查询文件列表 * author:linchunpeng * date:2024/3/12 */ public List queryByTaskId(Long taskId) { LambdaQueryChainWrapper lqw = this.lambdaQuery(); lqw.eq(FerryTaskFileEntity::getTaskId, taskId); lqw.orderByAsc(FerryTaskFileEntity::getCreateTime); return lqw.list(); } /** * description:根据摆渡任务id,查询任务文件 * author:linchunpeng * date:2024/3/12 */ public FerryTaskFileEntity queryTaskFileByTaskId(Long taskId) { LambdaQueryChainWrapper lqw = this.lambdaQuery(); lqw.eq(FerryTaskFileEntity::getTaskId, taskId); lqw.eq(FerryTaskFileEntity::getFileType, FileTypeEnum.TASK.getCode()); lqw.orderByDesc(FerryTaskFileEntity::getCreateTime); lqw.last("limit 1"); List list = lqw.list(); return CollectionUtil.isNotEmpty(list) ? list.get(0) : null; } /** * description:根据摆渡任务id,查询明细文件列表(不含任务文件) * author:linchunpeng * date:2024/3/12 */ public List queryDetailFileByTaskId(Long taskId) { LambdaQueryChainWrapper lqw = this.lambdaQuery(); lqw.eq(FerryTaskFileEntity::getTaskId, taskId); lqw.ne(FerryTaskFileEntity::getFileType, FileTypeEnum.TASK.getCode()); lqw.orderByAsc(FerryTaskFileEntity::getCreateTime); return lqw.list(); } /** * description:查询未摆渡完成或失败的文件数; * author:linchunpeng * date:2024/3/13 */ public long countNullFerryResultByTaskId(Long taskId) { LambdaQueryChainWrapper lqw = this.lambdaQuery(); lqw.eq(FerryTaskFileEntity::getTaskId, taskId); lqw.eq(FerryTaskFileEntity::getIsSplit, 0); lqw.in(FerryTaskFileEntity::getFileStatus, 1, 2); return lqw.count(); } /** * description:创建摆渡任务文件 * author:linchunpeng * date:2024/3/12 */ @Transactional public void createFerryTaskFile(FerryTaskEntity ferryTaskEntity, File file) { log.info("初始化文件:{}", file.getAbsolutePath()); String fileName = file.getName(); FerryTaskFileEntity fileEntity = new FerryTaskFileEntity(); fileEntity.setId(snowflake.snowflakeId()); fileEntity.setTaskId(ferryTaskEntity.getId()); fileEntity.setFileName(fileName); //取出后缀名 String suffix = fileName.substring(fileName.lastIndexOf(".")+1); if (fileName.startsWith(CommonConstant.FERRY_TASK_FILE_PREFIX)) { //任务文件 fileEntity.setFileType(FileTypeEnum.TASK.getCode()); } else if (suffix.toUpperCase(Locale.ROOT).equals("SQL")) { //sql脚本 fileEntity.setFileType(FileTypeEnum.SQL.getCode()); } else if (suffix.toUpperCase(Locale.ROOT).equals("TXT")) { //txt文件 fileEntity.setFileType(FileTypeEnum.TXT.getCode()); } else if (this.checkSpecialChar(fileName)) { //特殊字符文件名 fileEntity.setFileType(FileTypeEnum.SPECIAL.getCode()); } else { //普通文件 fileEntity.setFileType(FileTypeEnum.NORMAL.getCode()); } //文件存放位置,从摆渡包名开始 String absolutePath = file.getAbsolutePath(); absolutePath = absolutePath.replaceAll("\\\\", "/"); absolutePath = absolutePath.substring(absolutePath.indexOf("/".concat(ferryTaskEntity.getRequestId()))); fileEntity.setFileUrl(absolutePath); fileEntity.setFileStatus(FerryTaskFileStatusEnum.PULL_COMPLETE.getCode()); fileEntity.setFileSize(new BigDecimal(file.length()).divide(new BigDecimal(1024), 2, RoundingMode.HALF_UP)); if (file.length() > boundaryServerConfig.getMaxFileSize()) { log.info("文件:{},需要拆分", file.getAbsolutePath()); //文件超限,需要拆分 fileEntity.setIsSplit(1); fileEntity.setSplitFileIds(this.createChildrenFileList(ferryTaskEntity, FileSpiltMergeUtil.splitFile(boundaryServerConfig.getMaxFileSize(), file))); log.info("拆分出的文件id为:{}", fileEntity.getSplitFileIds()); } else { log.info("文件:{},不需要拆分", file.getAbsolutePath()); fileEntity.setIsSplit(0); } if (!fileName.startsWith(CommonConstant.FERRY_TASK_FILE_PREFIX)) { //不是任务文件 fileEntity.setFileMd5(MD5.create().digestHex16(file)); } fileEntity.setCreateTime(new Date()); fileEntity.setUpdateTime(new Date()); this.save(fileEntity); log.info("初始化完成,文件:{}", file.getAbsolutePath()); } /** * description:是否包含特殊字符 * author:linchunpeng * date:2024/9/14 */ private boolean checkSpecialChar(String str) { // 正则表达式规则, String regex = ".*[[ `~!@#$%^&*+=|{}':;',\\[\\]<>/?~!@#¥%……&*()——+|{}【】‘;:”“'。,、?]|\\n|\\r|\\t].*"; return str.matches(regex); } /** * description:创建子文件数据库记录 * author:linchunpeng * date:2024/3/12 */ private String createChildrenFileList(FerryTaskEntity ferryTaskEntity, List childrenFilePathList) { StringBuffer splitFileIds = new StringBuffer(); if (CollectionUtil.isNotEmpty(childrenFilePathList)) { for (String path : childrenFilePathList) { File file = new File(path); String fileName = file.getName(); FerryTaskFileEntity fileEntity = new FerryTaskFileEntity(); fileEntity.setId(snowflake.snowflakeId()); fileEntity.setTaskId(ferryTaskEntity.getId()); fileEntity.setFileName(fileName); fileEntity.setFileType(FileTypeEnum.CHILDREN.getCode()); //文件存放位置,从摆渡包名开始 String absolutePath = file.getAbsolutePath(); absolutePath = absolutePath.replaceAll("\\\\", "/"); absolutePath = absolutePath.substring(absolutePath.indexOf("/".concat(ferryTaskEntity.getRequestId()))); fileEntity.setFileUrl(absolutePath); fileEntity.setFileStatus(FerryTaskFileStatusEnum.PULL_COMPLETE.getCode()); fileEntity.setFileSize(new BigDecimal(file.length()).divide(new BigDecimal(1024), 2, RoundingMode.HALF_UP)); fileEntity.setIsSplit(0); fileEntity.setFileMd5(MD5.create().digestHex16(file)); fileEntity.setCreateTime(new Date()); fileEntity.setUpdateTime(new Date()); this.save(fileEntity); splitFileIds.append(fileEntity.getId().toString()).append(","); } } if (splitFileIds.length() == 0) { return null; } return splitFileIds.substring(0, splitFileIds.length() -1); } /** * description:摆渡任务信息文件 * author:linchunpeng * date:2024/3/13 */ @Transactional public void ferryTaskFile(Long taskId) { FerryTaskFileEntity taskFileEntity = this.queryTaskFileByTaskId(taskId); this.ferryFileToBoundary(taskFileEntity, SendBoundaryUrlEnum.SEND_TASK_FILE); } /** * description:摆渡任务明细文件 * author:linchunpeng * date:2024/3/13 */ @Transactional public void ferryDetailFile(Long taskId) { log.info("摆渡任务明细文件"); List ferryTaskFileEntityList = this.queryDetailFileByTaskId(taskId); for (FerryTaskFileEntity taskFileEntity : ferryTaskFileEntityList) { log.info("摆渡明细文件,文件id:{},文件名称:{}", taskFileEntity.getId(), taskFileEntity.getFileName()); this.ferryFileToBoundary(taskFileEntity, SendBoundaryUrlEnum.SEND_DETAIL_FILE); } log.info("摆渡任务明细文件完成"); } /** * description:单个文件摆渡 * author:linchunpeng * date:2024/3/13 */ public void ferryFileToBoundary(FerryTaskFileEntity taskFileEntity, SendBoundaryUrlEnum urlEnum) { FerryTaskEntity ferryTaskEntity = ferryTaskMapper.selectById(taskFileEntity.getTaskId()); FerryFileDto ferryFileDto = new FerryFileDto(); ferryFileDto.setFerryTaskId(taskFileEntity.getTaskId().toString()); ferryFileDto.setRequestId(ferryTaskEntity.getRequestId()); ferryFileDto.setFerry_accept_url(urlEnum.getValue()); ferryFileDto.setFileType(taskFileEntity.getFileType()); ferryFileDto.setFileId(taskFileEntity.getId().toString()); //转成map Map paramMap = BeanUtil.beanToMap(ferryFileDto); if (taskFileEntity.getIsSplit() == 0) { String fileToBase64 = Base64Util.fileToBase64(new File(ferryTaskEntity.getPackageUrl().concat(taskFileEntity.getFileUrl())), taskFileEntity.getFileType() != FileTypeEnum.NORMAL.getCode()); if (taskFileEntity.getFileType() == FileTypeEnum.NORMAL.getCode()) { //普通文件,放img_base64字段 paramMap.put("img_base64", fileToBase64); } else { //其他字段,放拓展字段 List fileBase64List = this.splitStringByLength(fileToBase64, 1000); paramMap.put("paramContentSize", fileBase64List.size()); for (int i = 0; i < fileBase64List.size(); i++) { paramMap.put("paramContent_" + i, fileBase64List.get(i)); } } } BoundaryResult boundaryResult = sendRequestToBoundaryService.send(paramMap); if (boundaryResult != null && "0".equals(boundaryResult.getStatus_code())) { taskFileEntity.setBoundaryTaskId(boundaryResult.getData().get(0).getTask_id()); taskFileEntity.setFileStatus(FerryTaskFileStatusEnum.FERRY_BEGIN.getCode()); } else { taskFileEntity.setFileStatus(FerryTaskFileStatusEnum.FERRY_FAIL.getCode()); taskFileEntity.setFerryResult(boundaryResult != null ? boundaryResult.getMsg() : "接口调用失败"); } taskFileEntity.setRetryCount(taskFileEntity.getRetryCount() == null ? 0 : taskFileEntity.getRetryCount() + 1); this.updateById(taskFileEntity); } private List splitStringByLength(String input, int length) { List result = new ArrayList<>(); int start = 0; while (start < input.length()) { int end = Math.min(start + length, input.length()); result.add(input.substring(start, end)); start += length; } return result; } /** * description:查询大于半小时小时还未摆渡完成的文件 * author:linchunpeng * date:2024/3/20 */ public List queryHalfHourNotCompleteList() { //大于半小时小时还未摆渡完成的文件 Date intervalTime = DateUtil.getBeforeNumMinuteTime(new Date(), 30); LambdaQueryChainWrapper lqw = this.lambdaQuery(); lqw.ne(FerryTaskFileEntity::getFileStatus, FerryTaskFileStatusEnum.FERRY_COMPLETE.getCode()); lqw.lt(FerryTaskFileEntity::getCreateTime, intervalTime); lqw.orderByAsc(FerryTaskFileEntity::getCreateTime); return lqw.list(); } }