package com.ruoyi.file.service.impl; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.extra.servlet.ServletUtil; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.file.constants.FileProjectConstants; import com.ruoyi.file.entity.AttachmentInfo; import com.ruoyi.file.properties.FilePathProperties; import com.ruoyi.file.service.AttachmentInfoService; import com.ruoyi.file.service.AttachmentService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.UUID; import static cn.hutool.core.io.FileTypeUtil.getType; /** * @email 1603559716@qq.com * @author: zf * @date: 2023/7/24 * @time: 13:54 */ @Service public class AttachmentServiceImpl implements AttachmentService { @Autowired private AttachmentInfoService attachmentInfoService; private final Logger logger = LoggerFactory.getLogger(this.getClass()); /** * 错误信息格式 */ private static final String ERROR_FORMATTER = "{}:{}"; @Resource private FilePathProperties filePathProperties; @Override public AttachmentInfo findByKey(String key) { if (StringUtils.isBlank(key)){ throw new ServiceException("文件标识为空", HttpStatus.ERROR); } return attachmentInfoService.findByKey(key); } @Override public AttachmentInfo findById(Long id) { if (id == null){ throw new ServiceException("文件主键为空"); } return attachmentInfoService.findById(id); } @Override public List findByIds(List ids) { if (CollectionUtils.isEmpty(ids)){ throw new ServiceException("文件主键为空"); } return attachmentInfoService.findByIds(ids); } @Override public List findByBusinessId(Long businessId) { if (businessId == null){ throw new ServiceException("业务主键为空"); } return attachmentInfoService.findByBusinessId(businessId); } @Override public void delete(Long id) { if (id == null){ throw new ServiceException("文件主键为空"); } attachmentInfoService.delete(id); } @Override public Object saveFileToPath(MultipartFile file, String module, int type) { //获取对应模块路径 String path; //获取对应模块根路径 String dcPath; path = filePathProperties.getModule().get(module); dcPath = filePathProperties.getDcPath(); String originalFilename = file.getOriginalFilename(); if (StringUtils.isEmpty(originalFilename)) { logger.error(ERROR_FORMATTER,module, "文件不存在"); throw new ServiceException("文件不存在"); } if (StringUtils.isEmpty(path)) { logger.error(ERROR_FORMATTER, module, "文件路径不存在"); throw new ServiceException("文件路径不存在"); } assert originalFilename != null; LocalDateTime now = LocalDateTime.now(); File newFile = null; try { //文件标识 UUID 如4d6873609b144945935ae84442711fd6 String key = ""; String suffix = ""; if (originalFilename.contains(".mp3")) { key = originalFilename; suffix = ""; } else { key = UUID.randomUUID().toString().replace("-", ""); //文件后缀 包含. suffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(); } path = path.replace("/", File.separator); //文件模块路径 如 2021/base/build/0421 String modulePath = now.getYear() + path + now.format(DateTimeFormatter.ofPattern("MMdd")); //文件路径 如 2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String newFilePath = modulePath + File.separator + key + suffix; //文件绝对路径 如 /home/img/2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String localPath = dcPath + newFilePath; //文件访问路径 如 /upload/2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String url = filePathProperties.getUrlRootPath() + newFilePath.replace(File.separator, "/"); newFile = new File(localPath); if (!newFile.exists() && !newFile.mkdirs()) { logger.error(ERROR_FORMATTER, newFilePath, "文件上传失败"); throw new ServiceException("文件上传失败"); } file.transferTo(newFile); //创建文件信息 AttachmentInfo attachmentInfo = new AttachmentInfo(); attachmentInfo.setDelFlag(0); attachmentInfo.setFileKey(key); attachmentInfo.setFileSuffix(suffix); attachmentInfo.setFilePath(localPath); attachmentInfo.setFileUrl(url); attachmentInfo.setFileName(file.getOriginalFilename()); attachmentInfo.setFileSize(file.getSize()); attachmentInfo.setModule(module); attachmentInfo.setFileType(getType(suffix)); attachmentInfo.setCreateBy(SecurityUtils.getUsername()); attachmentInfo.setUpdateBy(SecurityUtils.getUsername()); attachmentInfo.setUpdateTime(new Date()); attachmentInfo.setCreateTime(new Date()); AttachmentInfo attachment = attachmentInfoService.saveOne(attachmentInfo); switch (type) { case FileProjectConstants.ReturnType.URL: return url; case FileProjectConstants.ReturnType.KEY: return key; case FileProjectConstants.ReturnType.DETAIL: return attachment; default: return null; } } catch (IOException e) { if (newFile != null && newFile.exists()) { newFile.delete(); } logger.error(ERROR_FORMATTER, "文件上传失败"); throw new ServiceException("文件上传失败"); } } @Override public Object saveBatchFileToPath(MultipartFile[] fileList, String module) { //获取对应模块路径 String path; //获取对应模块根路径 String dcPath; path = filePathProperties.getModule().get(module); dcPath = filePathProperties.getDcPath(); List attachmentInfoList = new ArrayList<>(); for (MultipartFile file : fileList) { String originalFilename = file.getOriginalFilename(); if (StringUtils.isEmpty(originalFilename)) { logger.error(ERROR_FORMATTER,module, "文件不存在"); throw new ServiceException("文件不存在"); } if (StringUtils.isEmpty(path)) { logger.error(ERROR_FORMATTER, module, "文件路径不存在"); throw new ServiceException("文件路径不存在"); } assert originalFilename != null; LocalDateTime now = LocalDateTime.now(); File newFile = null; try { //文件标识 UUID 如4d6873609b144945935ae84442711fd6 String key = ""; String suffix = ""; if (originalFilename.contains(".mp3")) { key = originalFilename; suffix = ""; } else { key = UUID.randomUUID().toString().replace("-", ""); //文件后缀 包含. suffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(); } path = path.replace("/", File.separator); //文件模块路径 如 2021/base/build/0421 String modulePath = now.getYear() + path + now.format(DateTimeFormatter.ofPattern("MMdd")); //文件路径 如 2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String newFilePath = modulePath + File.separator + key + suffix; //文件绝对路径 如 /home/img/2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String localPath = dcPath + newFilePath; //文件访问路径 如 /upload/2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String url = filePathProperties.getUrlRootPath() + newFilePath.replace(File.separator, "/"); newFile = new File(localPath); if (!newFile.exists() && !newFile.mkdirs()) { logger.error(ERROR_FORMATTER, newFilePath, "文件上传失败"); throw new ServiceException("文件上传失败"); } //上传文件 file.transferTo(newFile); //创建文件信息 AttachmentInfo attachmentInfo = new AttachmentInfo(); attachmentInfo.setDelFlag(0); attachmentInfo.setFileKey(key); attachmentInfo.setFileSuffix(suffix); attachmentInfo.setFilePath(localPath); attachmentInfo.setFileUrl(url); attachmentInfo.setFileName(file.getOriginalFilename()); attachmentInfo.setFileSize(file.getSize()); attachmentInfo.setModule(module); attachmentInfo.setFileType(getType(suffix)); attachmentInfo.setCreateBy(SecurityUtils.getUsername()); attachmentInfo.setUpdateBy(SecurityUtils.getUsername()); attachmentInfo.setUpdateTime(new Date()); attachmentInfo.setCreateTime(new Date()); attachmentInfoList.add(attachmentInfo); } catch (IOException e) { if (newFile != null && newFile.exists()) { newFile.delete(); } logger.error(ERROR_FORMATTER, "文件上传失败", e.getMessage()); throw new ServiceException("文件上传失败"); } } List detailList = attachmentInfoService.saveBatchAttachment(attachmentInfoList); return detailList; } @Override public Object saveBatchFileToPath(MultipartFile[] fileList, String module,Long businessId) { //获取对应模块路径 String path; //获取对应模块根路径 String dcPath; path = filePathProperties.getModule().get(module); dcPath = filePathProperties.getDcPath(); List attachmentInfoList = new ArrayList<>(); for (MultipartFile file : fileList) { String originalFilename = file.getOriginalFilename(); if (StringUtils.isEmpty(originalFilename)) { logger.error(ERROR_FORMATTER,module, "文件不存在"); throw new ServiceException("文件不存在"); } if (StringUtils.isEmpty(path)) { logger.error(ERROR_FORMATTER, module, "文件路径不存在"); throw new ServiceException("文件路径不存在"); } assert originalFilename != null; LocalDateTime now = LocalDateTime.now(); File newFile = null; try { //文件标识 UUID 如4d6873609b144945935ae84442711fd6 String key = ""; String suffix = ""; if (originalFilename.contains(".mp3")) { key = originalFilename; suffix = ""; } else { key = UUID.randomUUID().toString().replace("-", ""); //文件后缀 包含. suffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(); } path = path.replace("/", File.separator); //文件模块路径 如 2021/base/build/0421 String modulePath = now.getYear() + path + now.format(DateTimeFormatter.ofPattern("MMdd")); //文件路径 如 2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String newFilePath = modulePath + File.separator + key + suffix; //文件绝对路径 如 /home/img/2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String localPath = dcPath + newFilePath; //文件访问路径 如 /upload/2021/base/build/0421/4d6873609b144945935ae84442711fd6.后缀 String url = filePathProperties.getUrlRootPath() + newFilePath.replace(File.separator, "/"); newFile = new File(localPath); if (!newFile.exists() && !newFile.mkdirs()) { logger.error(ERROR_FORMATTER, newFilePath, "文件上传失败"); throw new ServiceException("文件上传失败"); } //上传文件 file.transferTo(newFile); //创建文件信息 AttachmentInfo attachmentInfo = new AttachmentInfo(); attachmentInfo.setDelFlag(0); attachmentInfo.setFileKey(key); attachmentInfo.setFileSuffix(suffix); attachmentInfo.setFilePath(localPath); attachmentInfo.setFileUrl(url); attachmentInfo.setBusinessId(businessId); attachmentInfo.setFileName(file.getOriginalFilename()); attachmentInfo.setFileSize(file.getSize()); attachmentInfo.setModule(module); attachmentInfo.setFileType(getType(suffix)); attachmentInfo.setCreateBy(SecurityUtils.getUsername()); attachmentInfo.setUpdateBy(SecurityUtils.getUsername()); attachmentInfo.setUpdateTime(new Date()); attachmentInfo.setCreateTime(new Date()); attachmentInfoList.add(attachmentInfo); } catch (IOException e) { if (newFile != null && newFile.exists()) { newFile.delete(); } logger.error(ERROR_FORMATTER, "文件上传失败", e.getMessage()); throw new ServiceException("文件上传失败"); } } List detailList = attachmentInfoService.saveBatchAttachment(attachmentInfoList); return detailList; } @Override public void downloadForStream(HttpServletResponse response, String key) { AttachmentInfo byKey = findByKey(key); File file; try { response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(byKey.getFileName(), StandardCharsets.UTF_8.name())); response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); file = new File(byKey.getFilePath()); if (!file.exists()) { logger.error(ERROR_FORMATTER, key, "文件不存在"); throw new ServiceException("文件不存在"); } OutputStream outputStream = response.getOutputStream(); FileInputStream inputStream = new FileInputStream(file); IoUtil.copy(inputStream, outputStream); outputStream.close(); } catch (IOException e) { logger.error(e.getMessage()); throw new ServiceException("文件下载异常"); } } @Override public void downloadById(HttpServletResponse response, HttpServletRequest request, Long id) { Assert.isTrue(id == null, "文件key未知异常"); AttachmentInfo byId = findById(id); downloadByEntity(response, request, byId); } public void downloadByEntity(HttpServletResponse response, HttpServletRequest request, AttachmentInfo attachmentInfo) { if (ObjectUtils.isNotNull(attachmentInfo)) { String type = attachmentInfo.getFileType(); if (StringUtils.isBlank(type)) { type = "application/octet-stream"; } type = type + ";charset=utf-8"; String fileName = attachmentInfo.getFileName(); response.setContentType("multipart/form-data;charset=utf-8"); ServletUtil.setHeader(response, "Access-Control-Expose-Headers", "Content-Disposition"); //本地文件下载 File file = FileUtil.file(attachmentInfo.getFilePath()); if (!FileUtil.exist(file)) { throw new ServiceException(attachmentInfo.getFileKey() + "文件不存在"); } InputStream is = null; try { is = IoUtil.toStream(file); ServletUtil.write(response, is, type, fileName); } catch (Exception e) { throw new ServiceException("文件下载异常"); } finally { IoUtil.close(is); } } else { throw new ServiceException("文件不存在"); } } @Override public void updateBatchById(List attachmentInfo) { boolean saveBatch = attachmentInfoService.updateBatchById(attachmentInfo); if (!saveBatch) throw new ServiceException("文件批量保存失败"); } }