package com.product.file.util; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; import com.product.common.lang.StringUtils; import com.product.core.config.Global; import com.product.core.dao.BaseDao; import com.product.core.entity.FieldSetEntity; import com.product.core.exception.BaseException; import com.product.core.spring.context.SpringMVCContextHolder; import com.product.file.config.CmnConst; import com.product.file.config.FileCode; import com.product.file.service.FTPService; import com.product.module.sys.entity.SystemUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @Author cheng * @Date 2022/5/12 15:46 * @Desc 文件操作工具类 */ @Component public class FileUtils { @Autowired BaseDao baseDao; /** * 文件是否存在 * * @param dir * @param fileName * @return */ public boolean fileIsExist(String dir, String fileName) { return fileIsExist(true, dir, fileName); } /** * 删除文件服务器上的文件 * * @param dir * @param fileName * @return */ public boolean deleteFilesServerOnFile(String dir, String fileName) { SystemUser currentUser = SpringMVCContextHolder.getCurrentUser(); if (currentUser == null || StringUtils.isEmpty(currentUser.getToken_info())) { return false; } return FTPService.needUpload2FileServer() && new FTPService().deleteFile(dir, fileName); } /** * 文件是否存在 * * @param isServer 是否文件服务器 * @param dir * @param fileName * @return */ public boolean fileIsExist(boolean isServer, String dir, String fileName) { if (isServer && FTPService.needUpload2FileServer()) { FTPService ftpService = new FTPService(); return ftpService.fileIsExist(dir, fileName); } else { return new File(Global.getSystemConfig("local.dir", "") + "/" + dir + "/" + fileName).isFile(); } } /** * 根据文件记录表uuid 获取文件的字节 * * @param uuid * @return * @throws BaseException */ public byte[] getFileByte(String uuid) throws BaseException { File file = getFile(uuid, false); if (file == null || !file.isFile()) { return null; } byte[] bytes = cn.hutool.core.io.FileUtil.readBytes(file); file.delete(); return bytes; } /** * 获取文件 (文件使用完后请立即删除避免占用服务器磁盘空间) * * @param isUploadServer 是否上传在文件服务器 * @param dir 存储路径一般为 附件表 attachment_url 字段(不含服务器文件存储文件夹) * @param fileName 文件名称 * @param isEncrypt 是否加密文件 * @return 返回文件 当开启FTP时 第一次尝试在文件服务器上获取文件 获取不到再到应用部署服务器对应路径获取文件 * @throws BaseException 找不到文件抛出文件路径错误 */ public File getFile(boolean isUploadServer, String dir, String fileName, boolean isEncrypt) throws BaseException { if (StringUtils.isAnyEmpty(dir, fileName)) { return null; } String path = dir + File.separator + fileName; String random = RandomUtil.randomString(5); if (isUploadServer && FTPService.needUpload2FileServer()) { if (!fileIsExist(dir, fileName)) { return null; } File file = new File(Global.getSystemConfig("temp.dir", "") + "/" + "temp_down_file_" + fileName + "_" + random); if (file.isFile()) { file.delete(); } try { file.getParentFile().mkdirs(); file.createNewFile(); OutputStream out = new FileOutputStream(file); FTPService ftpService = new FTPService(); if (ftpService.downloadFile(path, out)) { if (isEncrypt) { String encryptPath = file.getParent() + "/" + "decode_file_temp_" + fileName + "_" + random; out.flush(); out.close(); FileUtil.copyFile(file, encryptPath, -1); file.delete(); file = new File(encryptPath); } else { out.flush(); out.close(); } if (file.isFile()) { return file; } } else { if (file.exists()) { file.delete(); } } } catch (Exception e) { throw new BaseException(FileCode.GET_FILE_FAIL.getValue(), FileCode.GET_FILE_FAIL.getText() + (StringUtils.isEmpty(e.getMessage()) ? "" : "," + e.getMessage())); } } //本地服务器获取文件 File file = new File(Global.getSystemConfig("local.dir", "") + File.separator + path); if (file.isFile()) { file = FileUtil.copyFile(file, Global.getSystemConfig("temp.dir", "") + File.separator + "download_file_temp_" + RandomUtil.randomString(5) + "_" + file.getName(), isEncrypt ? -1 : 0); } if (file.isFile()) { return file; } throw new BaseException(FileCode.INVALID_FILE_PATH); } /** * 根据文件记录表uuid 获取文件 (文件使用完后请立即删除避免占用服务器磁盘空间) * * @param uuid * @return * @throws BaseException */ public File getFile(String uuid) throws BaseException { return getFile(uuid, false); } /** * 获取文件 (文件使用完后请立即删除避免占用服务器磁盘空间) * 传入参数可参考 public File getFile(String uuid, boolean onlineViewFile) throws BaseException * * @param dir 文件存储文件夹 (attachment_url) * @param fileName 文件名称(attachment_title) * @param onlineViewFile 是否在线预览 * @param uploadSign 文件是否上传在文件服务器 * @return * @throws BaseException 找不到文件会抛出错误 */ public File getFile(String dir, String fileName, boolean onlineViewFile, boolean uploadSign) throws BaseException { String path = dir + File.separator + (onlineViewFile ? CmnConst.TRANSFER_DIR_NAME : "") + File.separator + fileName; if (uploadSign) { //服务器上获取文件 FTPService ftpService = new FTPService(); File file = new File(Global.getSystemConfig("temp.dir", "") + "/" + "temp_down_file_" + fileName + "_" + RandomUtil.randomString(5)); if (file.isFile()) { file.delete(); } try { file.getParentFile().mkdirs(); file.createNewFile(); OutputStream out = new FileOutputStream(file); if (ftpService.downloadFile(path, out)) { out.flush(); out.close(); return file; } else { out.flush(); out.close(); if (file.exists()) { file.delete(); } } throw new BaseException(FileCode.GET_FILE_FAIL); } catch (Exception e) { throw new BaseException(FileCode.GET_FILE_FAIL.getValue(), FileCode.GET_FILE_FAIL.getText() + (StringUtils.isEmpty(e.getMessage()) ? "" : "," + e.getMessage())); } } else { //本地服务器获取文件 File file = new File(Global.getSystemConfig("local.dir", "") + File.separator + path); if (file.isFile()) { File tempFile = new File(Global.getSystemConfig("temp.dir", "") + File.separator + "download_file_temp_" + RandomUtil.randomString(5) + "_" + file.getName()); FileUtil.copyFile(file, tempFile.getPath()); return tempFile; } else { throw new BaseException(FileCode.GET_FILE_FAIL); } } } /** * 获取文件 (文件使用完后请立即删除避免占用服务器磁盘空间) * * @param uuid 文件记录表uuid * @param onlineViewFile 是否在线预览 * @return * @throws BaseException */ public File getFile(String uuid, boolean onlineViewFile) throws BaseException { FieldSetEntity fse = getFileRecord(uuid); return getFile(fse.getString(CmnConst.ATTACHMENT_URL), fse.getString(CmnConst.ATTACHMENT_TITLE), onlineViewFile, fse.getBoolean(CmnConst.UPLOAD_SIGN)); } /** * 获取文件记录 * * @param uuid * @return * @throws BaseException */ public FieldSetEntity getFileRecord(String uuid) throws BaseException { FieldSetEntity fse = baseDao.getFieldSetEntity(CmnConst.PRODUCT_SYS_ATTACHMENTS, uuid, false); if (fse == null || StringUtils.isEmpty(fse.getUUID())) { throw new BaseException(FileCode.GET_FILE_RECORD_FAIL); } return fse; } /** * 输出文件流 * * @param uuid 文件记录uuid * @param onlineView 在线预览 * @param response * @throws Exception */ public void getFile(String uuid, boolean onlineView, HttpServletResponse response) throws Exception { FieldSetEntity fse = getFileRecord(uuid); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String userAgent = request.getHeader("User-Agent"); String file_name = fse.getString("file_name"); if (userAgent.contains("MSIE") || userAgent.contains("Trident")) { file_name = java.net.URLEncoder.encode(file_name, "UTF-8"); } else { // 非IE浏览器的处理: file_name = new String(file_name.getBytes("UTF-8"), "ISO-8859-1"); } response.setContentType("multipart/form-data"); response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", file_name)); String path = fse.getString(CmnConst.ATTACHMENT_URL) + File.separator + (onlineView && fse.getBoolean(CmnConst.VIEW_ONLINE_SIGN) ? CmnConst.TRANSFER_DIR_NAME : "") + File.separator + fse.getString(CmnConst.ATTACHMENT_TITLE); if (fse.getBoolean(CmnConst.UPLOAD_SIGN)) { //服务器上获取文件 FTPService ftpService = new FTPService(); ftpService.downloadFile(path, response.getOutputStream()); } else { //本地服务器获取文件 File file = new File(Global.getSystemConfig("local.dir", "") + File.separator + path); if (file.isFile()) { IoUtil.write(response.getOutputStream(), true, cn.hutool.core.io.FileUtil.readBytes(file)); } else { throw new BaseException(FileCode.GET_FILE_FAIL); } } } /** * 上传文件 * 删除传入的文件 * * @param filePath 文件路径 * @return 返回上传后的文件名称 */ public static String uploadFile(String filePath) throws BaseException { return uploadFile(new File(filePath), null, true); } /** * 上传文件 * 删除传入的文件 * * @param file 文件 * @return 返回上传后的文件名称 */ public static String uploadFile(File file) throws BaseException { return uploadFile(file, null, true); } /** * 上传文件 * 删除传入的文件 * * @param file * @param templateType 模板类型 * @return 返回上传后的文件名称 */ public static String uploadFile(File file, String templateType) throws BaseException { return uploadFile(file, templateType, true); } /** * 上传文件 * 删除传入的文件 * * @param file * @param templateType 模板类型 * @return 返回上传后的文件名称 */ public static String uploadFile(File file, String templateType, String clientUuid) throws BaseException { return uploadFile(file, templateType, true, clientUuid); } /** * @param file 文件 * @param templateType 模板类型 1 = import 2 = print , 其他 * @param deleteFile 是否删除传入的文件 * @return */ public static String uploadFile(File file, String templateType, boolean deleteFile, String clientUuid) throws BaseException { if (file == null || !file.isFile()) { throw new BaseException(FileCode.UPLOAD_FILE_NOT_EXISTS); } if (StringUtils.isEmpty(clientUuid)) { throw new BaseException(FileCode.GET_CLIENT_INFO_FAIL); } String dir; if (StringUtils.isEmpty(templateType)) { String timeStr = new SimpleDateFormat("yyyyMMdd").format(new Date()); dir = clientUuid + File.separator + timeStr; } else { dir = CmnConst.DIR_TEMPLATE + File.separator + ("1".equals(templateType) ? CmnConst.DIR_IMPORT : ("2".equals(templateType) ? CmnConst.DIR_PRINT : CmnConst.DIR_OTHER)); } String saveFileName = System.currentTimeMillis() + RandomUtil.randomString(2); //文件加密 boolean encryptFile = Global.getPropertyToBoolean("file.encrypt", "true"); try { //上传至FTP 服务器 if (FTPService.needUpload2FileServer()) { FTPService ftpService = new FTPService(); String tail = file.getName().substring(file.getName().lastIndexOf(".")); String tempEncryptFilePath = Global.getSystemConfig("temp.dir", "./attachment/temp") + File.separator + "encrypt_" + saveFileName + tail; FileUtil.copyFile(file, tempEncryptFilePath, encryptFile ? 1 : 0); ftpService.uploadFile(new FileInputStream(tempEncryptFilePath), saveFileName, dir); File sourceFile = new File(tempEncryptFilePath); if (sourceFile.isFile()) { convertPdf(deleteFile, true, encryptFile, false, sourceFile, dir + File.separator + CmnConst.TRANSFER_DIR_NAME, saveFileName, file.getName()); } if (deleteFile && file.isFile()) { file.delete(); } sourceFile.delete(); } else { //上传到本地 String path = Global.getSystemConfig("local.dir", "") + File.separator + dir + File.separator + saveFileName; FileUtil.copyFile(file, path, encryptFile ? 1 : 0); File sourceFile = new File(path); if (sourceFile.isFile()) { convertPdf(false, encryptFile, false, sourceFile, dir + File.separator + CmnConst.TRANSFER_DIR_NAME, saveFileName, file.getName()); } if (deleteFile && file.isFile()) { file.delete(); } } return saveFileName; } catch (Exception e) { e.printStackTrace(); throw new BaseException(FileCode.UPLOAD_FILE_FAIL); } } /** * @param file 文件 * @param templateType 模板类型 1 = import 2 = print , 其他 * @param deleteFile 是否删除传入的文件 * @return */ public static String uploadFile(File file, String templateType, boolean deleteFile) throws BaseException { SystemUser currentUser = SpringMVCContextHolder.getCurrentUser(); String clientUuid = null; if (currentUser != null) { clientUuid = currentUser.getClient_uuid(); } return uploadFile(file, templateType, deleteFile, clientUuid); } /** * 上传其他文件 * * @param encryptFile 加密文件 * @param catalogue 上传目录 * @param file 上传文件 * @param fileName 文件名称 */ public static void uploadOtherFile(boolean encryptFile, String catalogue, File file, String fileName) throws BaseException { uploadOtherFile(encryptFile, true, catalogue, file, fileName); } /** * 上传其他文件 * * @param encryptFile 加密文件 * @param uploadServer 上传至服务器 * @param catalogue 上传目录 * @param file 上传文件 * @param fileName 文件名称 */ public static void uploadOtherFile(boolean encryptFile, boolean uploadServer, String catalogue, File file, String fileName) throws BaseException { if (file == null || !file.isFile()) { return; } try { catalogue = catalogue.replace("\\", "/"); if (catalogue.indexOf("/") == 0) { catalogue = catalogue.substring(1); } if (uploadServer && FTPService.needUpload2FileServer()) { //上传至服务器 FTPService ftpService = new FTPService(); if (encryptFile) { String path = Global.getSystemConfig("temp.dir", "") + "/upload_other_file_" + RandomUtil.randomString(5) + "_" + file.getName(); file = FileUtil.copyFile(file, path, 1); } FileInputStream is = new FileInputStream(file); ftpService.uploadFile(is, fileName, catalogue); is.close(); if (encryptFile) { file.delete(); } } else { String path = Global.getSystemConfig("local.dir", "") + File.separator + catalogue + File.separator + fileName; FileUtil.copyFile(file, path, encryptFile ? 1 : 0); } } catch (Exception e) { throw new BaseException(FileCode.UPLOAD_FILE_FAIL); } } /** * 替换文件 * * @param sourceFileCatalogue 替换文件所在的目录 (attachment_url) * @param sourceFileName 替换的文件名称 (attachment_title) * @param originalFileName 原始文件名称 (file_name) * @param sourceFile 需要替换的文件 * @param encryptSign 加密标识 * @param isUploadServer 上传到服务器 * @param convertPDF 是否转换PDF * @throws BaseException */ public void replaceFile(String sourceFileCatalogue, String sourceFileName, String originalFileName, File sourceFile, boolean encryptSign, boolean isUploadServer, boolean convertPDF) throws BaseException { try { if (isUploadServer) { boolean deleteFile = false; if (encryptSign) { //加密文件 String tempPath = Global.getSystemConfig("temp.dir", "./attachment/temp") + "/" + "encrypt_replace_" + IdUtil.randomUUID(); FileUtil.copyFile(sourceFile, tempPath, 1); sourceFile = new File(tempPath); deleteFile = true; } FTPService ftpService = new FTPService(); InputStream is = new FileInputStream(sourceFile); ftpService.uploadFile(is, sourceFileName, sourceFileCatalogue); is.close(); if (convertPDF && sourceFile.isFile()) { convertPdf(deleteFile, isUploadServer, encryptSign, false, sourceFile, sourceFileCatalogue + File.separator + CmnConst.TRANSFER_DIR_NAME, sourceFileName, originalFileName); } } else { String localDir = Global.getSystemConfig("local.dir", ""); FileUtil.copyFile(sourceFile, localDir + File.separator + sourceFileCatalogue + File.separator + sourceFileName, encryptSign ? 1 : 0); File file = new File(localDir + File.separator + sourceFileCatalogue + File.separator + sourceFileName); if (convertPDF && file.isFile()) { convertPdf(false, encryptSign, false, file, sourceFileCatalogue + File.separator + CmnConst.TRANSFER_DIR_NAME, sourceFileName, originalFileName); } } } catch (Exception e) { throw new BaseException(FileCode.REPLACE_FILE_FAIL); } } /** * 替换文件 * * @param uuid 附件表uuid * @param sourceFile * @return 返回文件记录 */ public FieldSetEntity replaceFile(String uuid, File sourceFile) throws BaseException { FieldSetEntity fse = getFileRecord(uuid); replaceFile(fse.getString(CmnConst.ATTACHMENT_URL), fse.getString(CmnConst.ATTACHMENT_TITLE), fse.getString(CmnConst.FILE_NAME), sourceFile, fse.getBoolean(CmnConst.ENCRPT_SIGN), fse.getBoolean(CmnConst.UPLOAD_SIGN), fse.getBoolean(CmnConst.VIEW_ONLINE_SIGN)); return fse; } /** * 转换pdf * * @param uploadServer 上传到服务器 * @param isEncrypt 是否加密 * @param threadSync 线程同步 * @param file 文件 * @param placeLocation 文件所在目录 * @param fileName 文件名称 * @param sourceFileName 源文件名称 * @return * @throws BaseException */ public static boolean convertPdf(boolean uploadServer, boolean isEncrypt, boolean threadSync, File file, String placeLocation, String fileName, String sourceFileName) throws BaseException { return convertPdf(false, uploadServer, isEncrypt, threadSync, file, placeLocation, fileName, sourceFileName); } /** * @param threadSync 线程同步 false 异步转换 * @param file 需要转换的文件 * @param placeLocation 转换后存放的路径 (不需要拼接服务器文件夹路径) * @param fileName 转换后的文件名称 * @return 是否转换成功 异步转换时忽略该返回 */ public static boolean convertPdf(boolean deleteFile, boolean uploadServer, boolean isEncrypt, boolean threadSync, File file, String placeLocation, String fileName, String sourceFileName) throws BaseException { if (file.isFile() && !StringUtils.isEmpty(placeLocation) && !StringUtils.isEmpty(fileName)) { String tail = sourceFileName.substring(sourceFileName.lastIndexOf(".") + 1); boolean needTransferFlag = Global.getPropertyToBoolean("file.view.online", "true") && ("," + Global.getSystemConfig("can.transfer.format", "") + ",").contains("," + tail + ","); if (!needTransferFlag) { return false; } placeLocation = placeLocation.replace("\\", "/"); if (placeLocation.indexOf("/") != 0) { placeLocation += "/"; } //线程同步 if (threadSync) { boolean b = convertPdf(uploadServer, isEncrypt, file, placeLocation, fileName); if (deleteFile && file.isFile()) { file.delete(); } return b; } else { ExecutorService executorService = Executors.newSingleThreadExecutor(); String finalPlaceLocation = placeLocation; final File ff = FileUtil.copyFile(file, Global.getSystemConfig("temp.dir", "") + "/" + "temp_convert_pdf_" + RandomUtil.randomString(5) + "_" + file.getName(), 0); executorService.submit(() -> { convertPdf(uploadServer, isEncrypt, ff, finalPlaceLocation, fileName); if (ff.isFile()) { ff.delete(); } if (deleteFile && file.isFile()) { file.delete(); } }); } } return false; } private static boolean convertPdf(boolean uploadServer, boolean isEncrypt, File file, String placeLocation, String fileName) throws BaseException { File pdfFile = null; String random = RandomUtil.randomString(5); String tempPath = Global.getSystemConfig("temp.dir", "./attachment/temp") + "/" + "convertPDF_" + random + "_" + file.getName(); String tempPathSuccess = Global.getSystemConfig("temp.dir", "./attachment/temp") + "/" + "convertPDF_success_" + random + ".pdf"; try { FileUtil.copyFile(file, tempPath, 0); pdfFile = PdfConcurrenceUtil.convertToPdf(tempPath, tempPathSuccess); String s = Global.getSystemConfig("temp.dir", "") + "/" + "convertPDF_encryptTemp_" + random + ".pdf"; FileUtil.copyFile(pdfFile, s, isEncrypt ? 1 : 0); pdfFile.delete(); pdfFile = new File(s); uploadOtherFile(false, uploadServer, placeLocation, pdfFile, fileName); return true; } catch (Exception e) { e.printStackTrace(); throw new BaseException(FileCode.CONVERT_PDF_FILE_FAIL); } finally { try { if (pdfFile.isFile()) { pdfFile.delete(); } com.product.common.io.FileUtils.delFile(tempPath); } catch (Exception e) { e.printStackTrace(); } } } }