package com.fjhx.file.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fjhx.file.entity.*; import com.fjhx.file.mapper.FileInfoMapper; import com.fjhx.file.service.FileInfoService; import com.obs.services.ObsClient; import com.obs.services.model.PostSignatureRequest; import com.obs.services.model.PostSignatureResponse; import com.ruoyi.common.constant.BaseSourceConstant; import com.ruoyi.common.core.domain.BaseIdPo; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.wrapper.IWrapper; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.File; import java.util.*; import java.util.stream.Collectors; /** *

* 文件表 服务实现类 *

* * @author zlj * @since 2023-03-14 */ @Service public class FileInfoServiceImpl extends ServiceImpl implements FileInfoService { @Value("${obs.ak}") private String ak; @Value("${obs.sk}") private String sk; @Value("${obs.endPoint}") private String endPoint; @Value("${obs.url}") private String url; @Value("${obs.bucketName}") private String bucketName; @Value("${spring.profiles.active}") private String active; @Value("${ruoyi.name}") private String name; @Override public SingVo getSing(SingDto dto) { String fileName = dto.getFileName(); if (fileName.length() > 100) { throw new ServiceException("文件名过长,请缩短后重试!!!"); } SingVo singVo = new SingVo(); // 文件后缀名 String suffix = FileUtil.getSuffix(dto.getFileName()); // 文件路径 String objectKey = new StringJoiner("/") .add(name) .add(active) .add(DateUtil.format(new Date(), "yyyy/MM/dd")) .add(IdUtil.fastSimpleUUID() + (ObjectUtil.isEmpty(suffix) ? "" : "." + suffix)) .toString(); ObsClient obsClient = null; try { // 获取oss链接客户端 obsClient = getObsClient(); // 指定签名有效期为10秒 long currentTimeMillis = System.currentTimeMillis() + 1000 * 10; // 获取签名 PostSignatureRequest request = new PostSignatureRequest(currentTimeMillis, bucketName, objectKey); PostSignatureResponse temporarySignature = obsClient.createPostSignature(request); // 封装签名 Map body = new LinkedHashMap<>(); body.put("policy", temporarySignature.getPolicy()); body.put("AccessKeyId", ak); body.put("signature", temporarySignature.getSignature()); body.put("key", objectKey); singVo.setUploadBody(body); } catch (Exception e) { throw new ServiceException("获取签名失败"); } finally { IoUtil.close(obsClient); } // 保存文件 FileInfo fileInfo = new FileInfo(); fileInfo.setFileUrl(objectKey); fileInfo.setFileName(dto.getFileName()); save(fileInfo); // 封装文件信息 singVo.setUploadUrl("https://" + bucketName + "." + endPoint); singVo.setId(fileInfo.getId()); singVo.setFileName(dto.getFileName()); singVo.setFileUrl(url + objectKey); return singVo; } @DS(BaseSourceConstant.BASE) @Override public Map> getList(FileInfoSelectDto dto) { if (ObjectUtil.isEmpty(dto.getBusinessIdList())) { return new HashMap<>(); } IWrapper wrapper = IWrapper.getWrapper(); wrapper.in("fi", FileInfo::getBusinessId, dto.getBusinessIdList()); wrapper.eq("fi", FileInfo::getBusinessType, dto.getFileType()); List list = this.baseMapper.getList(wrapper); if (list.size() == 0) { return new HashMap<>(); } return list.stream() .peek(fileInfoVo -> fileInfoVo.setFileUrl(url + fileInfoVo.getFileUrl())) .collect(Collectors.groupingBy(FileInfoVo::getBusinessId)); } /** * @param obsFileList 文件列表 * @param businessId 业务id * @param businessType 业务文件类型 */ @DS(BaseSourceConstant.BASE) @Override public void saveFile(List obsFileList, Long businessId, Integer businessType) { // 切换到从库 if (obsFileList == null || obsFileList.size() == 0) { return; } List fileInfoList = BeanUtil.copyToList(obsFileList, FileInfo.class); for (FileInfo fileInfo : fileInfoList) { fileInfo.setFileUrl(null); fileInfo.setBusinessId(businessId); fileInfo.setBusinessType(businessType); } this.updateBatchById(fileInfoList); } /** * 保存文件--直接插入 * @param obsFileList 文件列表 * @param businessId 业务id * @param businessType 业务文件类型 */ @DS(BaseSourceConstant.BASE) @Override public void saveAllFile(List obsFileList, Long businessId, Integer businessType) { if (obsFileList == null || obsFileList.size() == 0) { return; } List fileInfoList = BeanUtil.copyToList(obsFileList, FileInfo.class); for (FileInfo fileInfo : fileInfoList) { fileInfo.setId(IdWorker.getId()); fileInfo.setBusinessId(businessId); fileInfo.setBusinessType(businessType); } this.saveBatch(fileInfoList); } /** * * @param obsFileList 文件列表 * @param businessId 业务id * @param businessType 业务文件类型 */ @DS(BaseSourceConstant.BASE) @Override public void editFile(List obsFileList, Long businessId, Integer businessType) { if (obsFileList == null || obsFileList.size() == 0) { this.remove(q -> q.eq(FileInfo::getBusinessId, businessId).eq(FileInfo::getBusinessType, businessType)); return; } // 删除不包含在此列表的业务id文件 List obsFileId = obsFileList.stream().map(ObsFile::getId).collect(Collectors.toList()); this.remove(q -> q.notIn(ObjectUtil.isNotEmpty(obsFileId), BaseIdPo::getId, obsFileId) .eq(FileInfo::getBusinessId, businessId).eq(FileInfo::getBusinessType, businessType)); // 更新在此列表的文件 saveFile(obsFileList, businessId, businessType); } /** * !!!必须加上Transactional 更改事务传播行为,否则数据源将被缓存,造成数据源切换失败 * * @param businessId 业务id * @param businessType 业务文件类型 */ @DS(BaseSourceConstant.BASE) @Override public void removeFile(Long businessId, Integer businessType) { this.remove(q -> q .eq(FileInfo::getBusinessId, businessId) .eq(FileInfo::getBusinessType, businessType)); } /** * !!!必须加上Transactional 更改事务传播行为,否则数据源将被缓存,造成数据源切换失败 * * @param businessId 业务id */ @DS(BaseSourceConstant.BASE) @Override public void removeFile(Long businessId) { this.remove(q -> q.eq(FileInfo::getBusinessId, businessId)); } /** * 交换业务ID * @param oldBusinessId 旧业务id * @param newBusinessId 新业务id */ @DS(BaseSourceConstant.BASE) @Override @Transactional(rollbackFor = Exception.class) public void exchangeBusinessId(Long oldBusinessId, Long newBusinessId) { List oldFile = this.list(Wrappers.query().lambda().select(FileInfo::getId).eq(FileInfo::getBusinessId,oldBusinessId)); List newFile = this.list(Wrappers.query().lambda().select(FileInfo::getId).eq(FileInfo::getBusinessId,newBusinessId)); if(CollectionUtils.isNotEmpty(oldFile)){ List ids = oldFile.stream().map(FileInfo::getId).collect(Collectors.toList()); this.update(Wrappers.update().lambda().set(FileInfo::getBusinessId,newBusinessId).in(FileInfo::getId,ids)); } if(CollectionUtils.isNotEmpty(newFile)){ List ids = newFile.stream().map(FileInfo::getId).collect(Collectors.toList()); this.update(Wrappers.update().lambda().set(FileInfo::getBusinessId,oldBusinessId).in(FileInfo::getId,ids)); } } /** * 获取oss链接客户端 */ private ObsClient getObsClient() { return new ObsClient(ak, sk, endPoint); } /** * 判断文件是否已经绑定业务 是将文件复制一份并保存 * * @param fileList 文件列表 * @param businessId 业务id * @param businessType 业务文件类型 */ @DS(BaseSourceConstant.BASE) @Override public void copyFileAndSave(List fileList, Long businessId, Integer businessType) { if (ObjectUtils.isEmpty(fileList)) { return; } List fids = fileList.stream().map(ObsFile::getId).collect(Collectors.toList()); Map fileInfoMap = this.mapKEntity(FileInfo::getId, q -> q.in(FileInfo::getId, fids)); List newFileInfo = new ArrayList<>(); for (ObsFile obsFile : fileList) { FileInfo fileInfo = fileInfoMap.get(obsFile.getId()); if (ObjectUtils.isEmpty(fileInfo)) { continue; } //如果文件已经有业务id了 且业务id不是当前业务id 就将文件复制一份 if (ObjectUtils.isNotEmpty(fileInfo.getBusinessId()) && !businessId.equals(fileInfo.getBusinessId())) { long id = IdWorker.getId(); fileInfo.setId(id); obsFile.setId(id); newFileInfo.add(fileInfo); } } this.saveBatch(newFileInfo); saveFile(fileList, businessId, businessType); } }