diff --git a/server/src/main/java/cn/keking/model/FileAttribute.java b/server/src/main/java/cn/keking/model/FileAttribute.java index 24694ab6..def5501d 100644 --- a/server/src/main/java/cn/keking/model/FileAttribute.java +++ b/server/src/main/java/cn/keking/model/FileAttribute.java @@ -14,11 +14,16 @@ public class FileAttribute { private String url; private String fileKey; private String filePassword; - private String userToken; + private boolean userToken; private String officePreviewType = ConfigConstants.getOfficePreviewType(); private String tifPreviewType; private Boolean skipDownLoad = false; private Boolean forceUpdatedCache = false; + private String cacheName; + private String outFilePath; + private String fileNameFilePath; + private String cacheListName; + private boolean isHtml; /** * 代理请求到文件服务器的认证请求头,格式如下: @@ -61,11 +66,11 @@ public class FileAttribute { this.filePassword = filePassword; } - public String getUserToken() { + public boolean getUserToken() { return userToken; } - public void setUserToken(String userToken) { + public void setUserToken(boolean userToken) { this.userToken = userToken; } @@ -96,7 +101,37 @@ public class FileAttribute { public String getName() { return name; } + public String getcacheName() { + return cacheName; + } + public String getcacheListName() { + return cacheListName; + } + public String getoutFilePath() { + return outFilePath; + } + public String getfileNameFilePath() { + return fileNameFilePath; + } + public boolean getisHtml() { + return isHtml; + } + public void setcacheName(String cacheName) { + this.cacheName = cacheName; + } + public void setcacheListName(String cacheListName) { + this.cacheListName = cacheListName; + } + public void setoutFilePath(String outFilePath) { + this.outFilePath = outFilePath; + } + public void setfileNameFilePath(String fileNameFilePath) { + this.fileNameFilePath = fileNameFilePath; + } + public void setisHtml(boolean isHtml) { + this.isHtml = isHtml; + } public void setName(String name) { this.name = name; } diff --git a/server/src/main/java/cn/keking/model/FileType.java b/server/src/main/java/cn/keking/model/FileType.java index ac48be56..e5870e2d 100644 --- a/server/src/main/java/cn/keking/model/FileType.java +++ b/server/src/main/java/cn/keking/model/FileType.java @@ -19,6 +19,7 @@ public enum FileType { CODE("codeFilePreviewImpl"), OTHER("otherFilePreviewImpl"), MEDIA("mediaFilePreviewImpl"), + MEDIACONVERT("mediaFilePreviewImpl"), MARKDOWN("markdownFilePreviewImpl"), XML("xmlFilePreviewImpl"), CAD("cadFilePreviewImpl"), @@ -50,7 +51,7 @@ public enum FileType { private static final String[] SSIM_TEXT_TYPES = ConfigConstants.getSimText(); private static final String[] CODES = {"java", "c", "php", "go", "python", "py", "js", "html", "ftl", "css", "lua", "sh", "rb", "yaml", "yml", "json", "h", "cpp", "cs", "aspx", "jsp", "sql"}; private static final String[] MEDIA_TYPES = ConfigConstants.getMedia(); - public static final String[] MEDIA_TYPES_CONVERT = ConfigConstants.getConvertMedias(); + public static final String[] MEDIACONVERT_TYPES_CONVERT = ConfigConstants.getConvertMedias(); private static final Map FILE_TYPE_MAPPER = new HashMap<>(); static { @@ -69,8 +70,8 @@ public enum FileType { for (String media : MEDIA_TYPES) { FILE_TYPE_MAPPER.put(media, FileType.MEDIA); } - for (String media : MEDIA_TYPES_CONVERT) { - FILE_TYPE_MAPPER.put(media, FileType.MEDIA); + for (String MEDIACONVERT : MEDIACONVERT_TYPES_CONVERT) { + FILE_TYPE_MAPPER.put( MEDIACONVERT, FileType. MEDIACONVERT); } for (String tif : TIFF_TYPES) { FILE_TYPE_MAPPER.put(tif, FileType.TIFF); diff --git a/server/src/main/java/cn/keking/service/CompressFileReader.java b/server/src/main/java/cn/keking/service/CompressFileReader.java index 7e795033..51f6c0ed 100644 --- a/server/src/main/java/cn/keking/service/CompressFileReader.java +++ b/server/src/main/java/cn/keking/service/CompressFileReader.java @@ -1,5 +1,6 @@ package cn.keking.service; +import cn.keking.config.ConfigConstants; import cn.keking.model.FileType; import cn.keking.utils.RarUtils; import cn.keking.web.filter.BaseUrlFilter; @@ -12,6 +13,7 @@ import net.sf.sevenzipjbinding.simple.ISimpleInArchive; import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; import org.apache.commons.io.IOUtils; import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; import java.io.*; import java.nio.charset.StandardCharsets; @@ -25,45 +27,49 @@ import java.util.List; @Component public class CompressFileReader { private final FileHandlerService fileHandlerService; + private static final String fileDir = ConfigConstants.getFileDir(); public CompressFileReader(FileHandlerService fileHandlerService) { this.fileHandlerService = fileHandlerService; } - public String unRar(String paths, String passWord, String fileName) throws Exception { + public String unRar(String filePath, String filePassword, String fileName, String fileKey) throws Exception { List imgUrls = new ArrayList<>(); String baseUrl = BaseUrlFilter.getBaseUrl(); - String archiveFileName = fileHandlerService.getFileNameFromPath(paths); + String folderName = filePath.replace(fileDir, ""); //修复压缩包 多重目录获取路径错误 + if (!ObjectUtils.isEmpty(fileKey)) { //压缩包文件 直接赋予路径 不予下载 + folderName = "_decompression"+folderName; + } RandomAccessFile randomAccessFile = null; IInArchive inArchive = null; try { - randomAccessFile = new RandomAccessFile(paths, "r"); + randomAccessFile = new RandomAccessFile(filePath, "r"); inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile)); - String folderName = paths.substring(paths.lastIndexOf(File.separator) + 1); - String extractPath = paths.substring(0, paths.lastIndexOf(folderName)); ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface(); final String[] str = {null}; for (final ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) { if (!item.isFolder()) { ExtractOperationResult result; + String finalFolderName = folderName; result = item.extractSlow(data -> { try { - str[0] = RarUtils.getUtf8String(item.getPath()); + str[0] = RarUtils.getUtf8String(item.getPath()); if (RarUtils.isMessyCode(str[0])){ str[0] = new String(item.getPath().getBytes(StandardCharsets.ISO_8859_1), "gbk"); } str[0] = str[0].replace("\\", File.separator); //Linux 下路径错误 String str1 = str[0].substring(0, str[0].lastIndexOf(File.separator)+ 1); - File file = new File(extractPath, folderName + "_" + File.separator + str1); + File file = new File(fileDir, finalFolderName + "_" + File.separator + str1); if (!file.exists()) { file.mkdirs(); } - OutputStream out = new FileOutputStream( extractPath+ folderName + "_" + File.separator + str[0], true); + OutputStream out = new FileOutputStream( fileDir+ finalFolderName + "_" + File.separator + str[0], true); IOUtils.write(data, out); out.close(); } catch (Exception e) { e.printStackTrace(); + return Integer.parseInt(null); } return data.length; - }, passWord); + }, filePassword); if (result == ExtractOperationResult.OK) { FileType type = FileType.typeFromUrl(str[0]); if (type.equals(FileType.PICTURE)) { @@ -75,7 +81,7 @@ public class CompressFileReader { } } } - return archiveFileName + "_"; + return folderName + "_"; } catch (Exception e) { throw new Exception(e); } finally { diff --git a/server/src/main/java/cn/keking/service/FileHandlerService.java b/server/src/main/java/cn/keking/service/FileHandlerService.java index 0aae8722..c9156e66 100644 --- a/server/src/main/java/cn/keking/service/FileHandlerService.java +++ b/server/src/main/java/cn/keking/service/FileHandlerService.java @@ -7,6 +7,7 @@ import cn.keking.service.cache.CacheService; import cn.keking.service.cache.NotResourceCache; import cn.keking.utils.EncodingDetects; import cn.keking.utils.KkFileUtils; +import cn.keking.utils.UrlEncoderUtils; import cn.keking.utils.WebUtils; import cn.keking.web.filter.BaseUrlFilter; import com.aspose.cad.*; @@ -36,6 +37,9 @@ import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; import java.awt.image.BufferedImage; import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -191,17 +195,17 @@ public class FileHandlerService implements InitializingBean { /** * 获取本地 pdf 转 image 后的 web 访问地址 - * @param pdfName pdf文件名 + * @param pdfFilePath pdf文件名 * @param index 图片索引 * @return 图片访问地址 */ - private String getPdf2jpgUrl(String pdfName, int index) { + private String getPdf2jpgUrl(String pdfFilePath, int index) { String baseUrl = BaseUrlFilter.getBaseUrl(); - String pdfFolder = pdfName.substring(0, pdfName.length() - 4); + pdfFilePath = pdfFilePath.replace(fileDir, ""); + String pdfFolder = pdfFilePath.substring(0, pdfFilePath.length() - 4); String urlPrefix; - try { - urlPrefix = baseUrl + URLEncoder.encode(pdfFolder, uriEncoding).replaceAll("\\+", "%20"); + urlPrefix = baseUrl + URLEncoder.encode(pdfFolder, uriEncoding).replaceAll("\\+", "%2B"); } catch (UnsupportedEncodingException e) { logger.error("UnsupportedEncodingException", e); urlPrefix = baseUrl + pdfFolder; @@ -215,14 +219,14 @@ public class FileHandlerService implements InitializingBean { * @param pdfName pdf文件名称 * @return 图片访问集合 */ - private List loadPdf2jpgCache(String pdfFilePath, String pdfName) { + private List loadPdf2jpgCache(String pdfFilePath, String pdfName, String fileKey) { List imageUrls = new ArrayList<>(); Integer imageCount = this.getPdf2jpgCache(pdfFilePath); if (Objects.isNull(imageCount)) { return imageUrls; } IntStream.range(0, imageCount).forEach(i -> { - String imageUrl = this.getPdf2jpgUrl(pdfName, i); + String imageUrl = this.getPdf2jpgUrl(pdfFilePath, i); imageUrls.add(imageUrl); }); return imageUrls; @@ -230,26 +234,28 @@ public class FileHandlerService implements InitializingBean { /** * pdf文件转换成jpg图片集 - * - * @param pdfFilePath pdf文件路径 - * @param pdfName pdf文件名称 - * @return 图片访问集合 + * fileNameFilePath pdf文件路径 + * pdfFilePath pdf输出文件路径 + * pdfName pdf文件名称 + * loadPdf2jpgCache 图片访问集合 */ - public List pdf2jpg(String pdfFilePath, String pdfName, FileAttribute fileAttribute) throws Exception { + public List pdf2jpg(String fileNameFilePath,String pdfFilePath, String pdfName, FileAttribute fileAttribute) throws Exception { boolean forceUpdatedCache = fileAttribute.forceUpdatedCache(); + boolean userToken = fileAttribute.getUserToken(); String filePassword = fileAttribute.getFilePassword(); + String fileKey = fileAttribute.getFileKey(); String pdfPassword = null; PDDocument doc = null; PdfReader pdfReader = null; if (!forceUpdatedCache) { - List cacheResult = this.loadPdf2jpgCache(pdfFilePath, pdfName); + List cacheResult = this.loadPdf2jpgCache(pdfFilePath, pdfName,fileKey); if (!CollectionUtils.isEmpty(cacheResult)) { return cacheResult; } } List imageUrls = new ArrayList<>(); try { - File pdfFile = new File(pdfFilePath); + File pdfFile = new File(fileNameFilePath); if (!pdfFile.exists()) { return null; } @@ -268,36 +274,39 @@ public class FileHandlerService implements InitializingBean { imageFilePath = folder + File.separator + pageIndex + PDF2JPG_IMAGE_FORMAT; BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, ConfigConstants.getPdf2JpgDpi(), ImageType.RGB); ImageIOUtil.writeImage(image, imageFilePath, ConfigConstants.getPdf2JpgDpi()); - String imageUrl = this.getPdf2jpgUrl(pdfName, pageIndex); + String imageUrl = this.getPdf2jpgUrl(pdfFilePath, pageIndex); imageUrls.add(imageUrl); } try { - if (ObjectUtils.isEmpty(filePassword)){ - pdfReader = new PdfReader(pdfFilePath); //读取PDF文件 - }else { - pdfReader = new PdfReader(pdfFilePath,filePassword.getBytes()); //读取PDF文件 + if (!ObjectUtils.isEmpty(filePassword)){ //获取到密码 判断是否是加密文件 + pdfReader = new PdfReader(fileNameFilePath); //读取PDF文件 通过异常获取该文件是否有密码字符 } } catch (Exception e) { //获取异常方法 判断是否有加密字符串 Throwable[] throwableArray = ExceptionUtils.getThrowables(e); for (Throwable throwable : throwableArray) { if (throwable instanceof IOException || throwable instanceof EncryptedDocumentException) { if (e.getMessage().toLowerCase().contains(PDF_PASSWORD_MSG)) { - pdfPassword = PDF_PASSWORD_MSG; + pdfPassword = PDF_PASSWORD_MSG; //查询到该文件是密码文件 输出带密码的值 } } } - logger.error("Convert pdf exception, pdfFilePath:{}", pdfFilePath, e); + if (!PDF_PASSWORD_MSG.equals(pdfPassword)) { //该文件异常 错误原因非密码原因输出错误 + logger.error("Convert pdf exception, pdfFilePath:{}", pdfFilePath, e); + } + } finally { if (pdfReader != null) { //关闭 pdfReader.close(); } } - //判断是否加密文件 加密文件不缓存 - if (!PDF_PASSWORD_MSG.equals(pdfPassword)) { + + if (userToken || !PDF_PASSWORD_MSG.equals(pdfPassword)) { //加密文件 判断是否启用缓存命令 this.addPdf2jpgCache(pdfFilePath, pageCount); } } catch (IOException e) { - logger.error("Convert pdf to jpg exception, pdfFilePath:{}", pdfFilePath, e); + if (!e.getMessage().contains(PDF_PASSWORD_MSG) ) { + logger.error("Convert pdf to jpg exception, pdfFilePath:{}", pdfFilePath, e); + } throw new Exception(e); } finally { if (doc != null) { //关闭 @@ -314,8 +323,17 @@ public class FileHandlerService implements InitializingBean { * @param outputFilePath pdf输出文件路径 * @return 转换是否成功 */ - public String cadToPdf(String inputFilePath, String outputFilePath ,String cadPreviewType) throws Exception { + public String cadToPdf(String inputFilePath, String outputFilePath ,String cadPreviewType ,String fileKey) throws Exception { final InterruptionTokenSource source = new InterruptionTokenSource();//CAD延时 + if (!ObjectUtils.isEmpty(fileKey)) { //判断 是压缩包的创建新的目录 + int index = outputFilePath.lastIndexOf("/"); //截取最后一个斜杠的前面的内容 + String folder = outputFilePath.substring(0, index); + File path = new File(folder); + //目录不存在 创建新的目录 + if (!path.exists()) { + path.mkdirs(); + } + } Callable call = () -> { File outputFile = new File(outputFilePath); LoadOptions opts = new LoadOptions(); @@ -411,8 +429,14 @@ public class FileHandlerService implements InitializingBean { FileAttribute attribute = new FileAttribute(); String suffix; FileType type; - String fileName; + String fileName; //原始文件名 + String cacheName; //缓存文件名 + String cacheUnifyName; //缓存文件名统一去除文件后缀名 + String cacheListName; //缓存列表文件名称 + String outFilePath; //生成文件的路径 + String fileNameFilePath; //原始文件路径 String fullFileName = WebUtils.getUrlParameterReg(url, "fullfilename"); + String fileKey = WebUtils.getUrlParameterReg(url, "kkCompressfileKey"); //压缩包指定特殊符号 if (StringUtils.hasText(fullFileName)) { fileName = fullFileName; type = FileType.typeFromFileName(fullFileName); @@ -428,23 +452,62 @@ public class FileHandlerService implements InitializingBean { type = FileType.typeFromUrl(url); suffix = WebUtils.suffixFromUrl(url); } - if (url.contains("?fileKey=")) { - String[] strs = url.split("="); //处理解压后有反代情况下 文件的路径 - String urlStrr = getSubString(url, strs[1]); - urlStrr = urlStrr.substring(0,urlStrr.lastIndexOf("?")); - fileName = strs[1] + urlStrr.trim(); - attribute.setSkipDownLoad(true); + if (!ObjectUtils.isEmpty(fileKey)) { //判断是否使用特定压缩包符号 + try { + URL urll = new URL(url); + fileName = urll.getPath(); //压缩包类型文件 获取解压后的绝对地址 不在执行重复下载方法 + attribute.setSkipDownLoad(true); + } catch (MalformedURLException e) { + e.printStackTrace(); + } } url = WebUtils.encodeUrlFileName(url); + if(UrlEncoderUtils.hasUrlEncoded(fileName) && UrlEncoderUtils.hasUrlEncoded(suffix)){ //判断文件名是否转义 + try { + fileName = URLDecoder.decode(fileName, "UTF-8").replaceAll("\\+", "%20").replaceAll(" ", "%20"); + suffix = URLDecoder.decode(suffix, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } fileName = KkFileUtils.htmlEscape(fileName); //文件名处理 + boolean isHtml = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx") || suffix.equalsIgnoreCase("csv") || suffix.equalsIgnoreCase("xlsm") || suffix.equalsIgnoreCase("xlt") || suffix.equalsIgnoreCase("xltm") || suffix.equalsIgnoreCase("et") || suffix.equalsIgnoreCase("ett") || suffix.equalsIgnoreCase("xlam"); + cacheUnifyName = fileName.substring(0, fileName.lastIndexOf(".") ) + suffix+"."; //这里统一文件名处理 下面更具类型 各自添加后缀 + if(type.equals(FileType.OFFICE)){ + cacheName = cacheUnifyName +(isHtml ? "html" : "pdf"); //生成文件添加类型后缀 防止同名文件 + }else if(type.equals(FileType.PDF)){ + cacheName = fileName; + }else if(type.equals(FileType.MEDIACONVERT)){ + cacheName = cacheUnifyName +"mp4" ; + }else if(type.equals(FileType.CAD)){ + String cadPreviewType = ConfigConstants.getCadPreviewType(); + cacheName = cacheUnifyName + cadPreviewType ; //生成文件添加类型后缀 防止同名文件 + }else if(type.equals(FileType.COMPRESS)){ + cacheName = fileName; + }else if(type.equals(FileType.TIFF)){ + cacheName = cacheUnifyName + ConfigConstants.getTifPreviewType(); + }else { + cacheName = fileName; + } + if (!ObjectUtils.isEmpty(fileKey)) { //判断是否使用特定压缩包符号 + cacheName = "_decompression"+ cacheName; + } + outFilePath = fileDir + cacheName; + fileNameFilePath = fileDir + fileName; + cacheListName = cacheUnifyName+"ListName"; //文件列表缓存文件名 attribute.setType(type); attribute.setName(fileName); + attribute.setcacheName(cacheName); + attribute.setcacheListName(cacheListName); + attribute.setisHtml(isHtml); + attribute.setoutFilePath(outFilePath); + attribute.setfileNameFilePath(fileNameFilePath); attribute.setSuffix(suffix); attribute.setUrl(url); if (req != null) { String officePreviewType = req.getParameter("officePreviewType"); String forceUpdatedCache = req.getParameter("forceUpdatedCache"); - String fileKey = WebUtils.getUrlParameterReg(url, "fileKey"); + String userToken =req.getParameter("userToken"); if (StringUtils.hasText(officePreviewType)) { attribute.setOfficePreviewType(officePreviewType); } @@ -464,10 +527,8 @@ public class FileHandlerService implements InitializingBean { if (StringUtils.hasText(filePassword)) { attribute.setFilePassword(filePassword); } - - String userToken = req.getParameter("userToken"); - if (StringUtils.hasText(userToken)) { - attribute.setUserToken(userToken); + if ("true".equalsIgnoreCase(userToken)) { + attribute.setUserToken(true); } String kkProxyAuthorization = req.getHeader( "kk-proxy-authorization"); attribute.setKkProxyAuthorization(kkProxyAuthorization); diff --git a/server/src/main/java/cn/keking/service/impl/CadFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/CadFilePreviewImpl.java index 4dea7432..17c39ec4 100644 --- a/server/src/main/java/cn/keking/service/impl/CadFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/CadFilePreviewImpl.java @@ -10,6 +10,7 @@ import cn.keking.utils.KkFileUtils; import cn.keking.web.filter.BaseUrlFilter; import org.springframework.stereotype.Service; import org.springframework.ui.Model; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType; @@ -23,7 +24,6 @@ public class CadFilePreviewImpl implements FilePreview { private static final String OFFICE_PREVIEW_TYPE_IMAGE = "image"; private static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages"; - private static final String FILE_DIR = ConfigConstants.getFileDir(); private final FileHandlerService fileHandlerService; private final OtherFilePreviewImpl otherFilePreview; @@ -40,22 +40,21 @@ public class CadFilePreviewImpl implements FilePreview { String baseUrl = BaseUrlFilter.getBaseUrl(); boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); String fileName = fileAttribute.getName(); - String suffix = fileAttribute.getSuffix(); String cadPreviewType = ConfigConstants.getCadPreviewType(); - String pdfName = fileName.substring(0, fileName.lastIndexOf(".")) + suffix +"." + cadPreviewType ; //生成文件添加类型后缀 防止同名文件 - String outFilePath = FILE_DIR + pdfName; + String cacheName = fileAttribute.getcacheName(); + String outFilePath = fileAttribute.getoutFilePath(); + String fileKey = fileAttribute.getFileKey(); //判断是否压缩包 // 判断之前是否已转换过,如果转换过,直接返回,否则执行转换 - if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) { - String filePath; - ReturnResponse response = DownloadUtils.downLoad(fileAttribute, null); + if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) { + ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); if (response.isFailure()) { return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); } - filePath = response.getContent(); + String filePath = response.getContent(); String imageUrls = null; if (StringUtils.hasText(outFilePath)) { try { - imageUrls = fileHandlerService.cadToPdf(filePath, outFilePath,cadPreviewType); + imageUrls = fileHandlerService.cadToPdf(filePath, outFilePath,cadPreviewType,fileKey); } catch (Exception e) { e.printStackTrace(); } @@ -63,26 +62,26 @@ public class CadFilePreviewImpl implements FilePreview { return otherFilePreview.notSupportedFile(model, fileAttribute, "office转图片异常,请联系管理员"); } //是否保留CAD源文件 - if( ConfigConstants.getDeleteSourceFile()) { + if(ObjectUtils.isEmpty(fileKey) && ConfigConstants.getDeleteSourceFile()) { KkFileUtils.deleteFileByPath(filePath); } if (ConfigConstants.isCacheEnabled()) { // 加入缓存 - fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath)); + fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath)); } } } if("tif".equalsIgnoreCase(cadPreviewType)){ - model.addAttribute("currentUrl", pdfName); + model.addAttribute("currentUrl", cacheName); return TIFF_FILE_PREVIEW_PAGE; }else if("svg".equalsIgnoreCase(cadPreviewType)){ - model.addAttribute("currentUrl", pdfName); + model.addAttribute("currentUrl", cacheName); return SVG_FILE_PREVIEW_PAGE; } if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) { - return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE,otherFilePreview); + return getPreviewType(model, fileAttribute, officePreviewType, cacheName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE,otherFilePreview); } - model.addAttribute("pdfUrl", pdfName); + model.addAttribute("pdfUrl", cacheName); return PDF_FILE_PREVIEW_PAGE; } } diff --git a/server/src/main/java/cn/keking/service/impl/CompressFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/CompressFilePreviewImpl.java index 60aedc0c..ca8f814e 100644 --- a/server/src/main/java/cn/keking/service/impl/CompressFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/CompressFilePreviewImpl.java @@ -39,6 +39,7 @@ public class CompressFilePreviewImpl implements FilePreview { String fileName=fileAttribute.getName(); String filePassword = fileAttribute.getFilePassword(); boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); + String fileKey = fileAttribute.getFileKey(); //判断是否压缩包 String fileTree = null; // 判断文件名是否存在(redis缓存读取) if (forceUpdatedCache || !StringUtils.hasText(fileHandlerService.getConvertedFile(fileName)) || !ConfigConstants.isCacheEnabled()) { @@ -48,7 +49,7 @@ public class CompressFilePreviewImpl implements FilePreview { } String filePath = response.getContent(); try { - fileTree = compressFileReader.unRar(filePath, filePassword,fileName); + fileTree = compressFileReader.unRar(filePath, filePassword,fileName,fileKey); } catch (Exception e) { Throwable[] throwableArray = ExceptionUtils.getThrowables(e); for (Throwable throwable : throwableArray) { @@ -62,7 +63,7 @@ public class CompressFilePreviewImpl implements FilePreview { } if (!ObjectUtils.isEmpty(fileTree)) { //是否保留压缩包源文件 - if (ConfigConstants.getDeleteSourceFile()) { + if (ObjectUtils.isEmpty(fileKey) && ConfigConstants.getDeleteSourceFile()) { KkFileUtils.deleteFileByPath(filePath); } if (ConfigConstants.isCacheEnabled()) { diff --git a/server/src/main/java/cn/keking/service/impl/MediaFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/MediaFilePreviewImpl.java index 169ec9d7..1842b8a6 100644 --- a/server/src/main/java/cn/keking/service/impl/MediaFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/MediaFilePreviewImpl.java @@ -1,20 +1,19 @@ package cn.keking.service.impl; - import cn.keking.config.ConfigConstants; import cn.keking.model.FileAttribute; import cn.keking.model.FileType; import cn.keking.model.ReturnResponse; +import cn.keking.service.FileHandlerService; import cn.keking.service.FilePreview; -import cn.keking.utils.ConfigUtils; import cn.keking.utils.DownloadUtils; -import cn.keking.service.FileHandlerService; -import cn.keking.web.filter.BaseUrlFilter; import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.FFmpegFrameRecorder; import org.bytedeco.javacv.Frame; import org.springframework.stereotype.Service; import org.springframework.ui.Model; +import org.springframework.util.ObjectUtils; + import java.io.File; /** @@ -28,139 +27,133 @@ public class MediaFilePreviewImpl implements FilePreview { private final FileHandlerService fileHandlerService; private final OtherFilePreviewImpl otherFilePreview; - - private static Object LOCK=new Object(); - + private static final String mp4 = "mp4"; public MediaFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) { this.fileHandlerService = fileHandlerService; this.otherFilePreview = otherFilePreview; } - @Override public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) { - // 不是http开头,浏览器不能直接访问,需下载到本地 - if (url != null && !url.toLowerCase().startsWith("http")) { - ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileAttribute.getName()); - if (response.isFailure()) { - return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); - } else { - url=BaseUrlFilter.getBaseUrl() + fileHandlerService.getRelativePath(response.getContent()); - fileAttribute.setUrl(url); + String fileName = fileAttribute.getName(); + String suffix = fileAttribute.getSuffix(); + String cacheName = fileAttribute.getcacheName(); + String outFilePath = fileAttribute.getoutFilePath(); + boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); + String fileKey = fileAttribute.getFileKey(); + FileType type = fileAttribute.getType(); + String[] mediaTypesConvert = FileType.MEDIACONVERT_TYPES_CONVERT; //获取支持的转换格式 + boolean mediaTypes = false; + for(String temp : mediaTypesConvert){ + if (suffix.equals(temp)) { + mediaTypes = true; + break; } } - - if(checkNeedConvert(fileAttribute.getSuffix())){ - url=convertUrl(fileAttribute); - }else{ - //正常media类型 - String[] medias = ConfigConstants.getMedia(); - for(String media:medias){ - if(media.equals(fileAttribute.getSuffix())){ - model.addAttribute("mediaUrl", url); - return MEDIA_FILE_PREVIEW_PAGE; + if(!url.toLowerCase().startsWith("http") || checkNeedConvert(mediaTypes)){ //不是http协议的 // 开启转换方式并是支持转换格式的 + if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) { //查询是否开启缓存 + ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); + if (response.isFailure()) { + return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); } - } - return otherFilePreview.notSupportedFile(model, fileAttribute, "暂不支持"); - } - model.addAttribute("mediaUrl", url); - return MEDIA_FILE_PREVIEW_PAGE; - } - - /** - * 检查视频文件处理逻辑 - * 返回处理过后的url - * @return url - */ - private String convertUrl(FileAttribute fileAttribute) { - String url = fileAttribute.getUrl(); - if(fileHandlerService.listConvertedMedias().containsKey(url)){ - url= fileHandlerService.getConvertedMedias(url); - }else{ - if(!fileHandlerService.listConvertedMedias().containsKey(url)){ - synchronized(LOCK){ - if(!fileHandlerService.listConvertedMedias().containsKey(url)){ - String convertedUrl=convertToMp4(fileAttribute); - //加入缓存 - fileHandlerService.addConvertedMedias(url,convertedUrl); - url=convertedUrl; + String filePath = response.getContent(); + String convertedUrl = null; + try { + if(mediaTypes){ + convertedUrl=convertToMp4(filePath,outFilePath,fileKey); + }else { + convertedUrl =outFilePath; //其他协议的 不需要转换方式的文件 直接输出 } + } catch (Exception e) { + e.printStackTrace(); + } + if (convertedUrl == null ) { + return otherFilePreview.notSupportedFile(model, fileAttribute, "视频转换异常,请联系管理员"); + } + if (ConfigConstants.isCacheEnabled()) { + // 加入缓存 + fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath)); } + model.addAttribute("mediaUrl", fileHandlerService.getRelativePath(outFilePath)); + }else{ + model.addAttribute("mediaUrl", fileHandlerService.listConvertedFiles().get(cacheName)); } + return MEDIA_FILE_PREVIEW_PAGE; } - return url; + if(type.equals(FileType.MEDIA)){ // 支持输出 只限默认格式 + model.addAttribute("mediaUrl", url); + return MEDIA_FILE_PREVIEW_PAGE; + } + return otherFilePreview.notSupportedFile(model, fileAttribute, "系统还不支持该格式文件的在线预览"); } - /** * 检查视频文件转换是否已开启,以及当前文件是否需要转换 * @return */ - private boolean checkNeedConvert(String suffix) { + private boolean checkNeedConvert(boolean mediaTypes) { //1.检查开关是否开启 - if("false".equals(ConfigConstants.getMediaConvertDisable())){ - return false; - } - //2.检查当前文件是否需要转换 - String[] mediaTypesConvert = FileType.MEDIA_TYPES_CONVERT; - String type = suffix; - for(String temp : mediaTypesConvert){ - if(type.equals(temp)){ - return true; - } + if("true".equals(ConfigConstants.getMediaConvertDisable())){ + return mediaTypes; } return false; } - - /** - * 将浏览器不兼容视频格式转换成MP4 - * @param fileAttribute - * @return - */ - private static String convertToMp4(FileAttribute fileAttribute) { - - //说明:这里做临时处理,取上传文件的目录 - String homePath = ConfigUtils.getHomePath(); - String filePath = homePath+File.separator+"file"+File.separator+"demo"+File.separator+fileAttribute.getName(); - String convertFileName=fileAttribute.getUrl().replace(fileAttribute.getSuffix(),"mp4"); - - File file=new File(filePath); - FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(file); - String fileName = null; - Frame captured_frame = null; + private static String convertToMp4(String filePath,String outFilePath,String fileKey)throws Exception { + FFmpegFrameGrabber frameGrabber = FFmpegFrameGrabber.createDefault(filePath); + Frame captured_frame; FFmpegFrameRecorder recorder = null; try { - fileName = file.getAbsolutePath().replace(fileAttribute.getSuffix(),"mp4"); - File desFile=new File(fileName); - //判断一下防止穿透缓存 + File desFile=new File(outFilePath); + //判断一下防止重复转换 if(desFile.exists()){ - return fileName; + return outFilePath; + } + if (!ObjectUtils.isEmpty(fileKey)) { //判断 是压缩包的创建新的目录 + int index = outFilePath.lastIndexOf("/"); //截取最后一个斜杠的前面的内容 + String folder = outFilePath.substring(0, index); + File path = new File(folder); + //目录不存在 创建新的目录 + if (!path.exists()) { + path.mkdirs(); + } } - frameGrabber.start(); - recorder = new FFmpegFrameRecorder(fileName, frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels()); - recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //avcodec.AV_CODEC_ID_H264  //AV_CODEC_ID_MPEG4 - recorder.setFormat("mp4"); + recorder = new FFmpegFrameRecorder(outFilePath, frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels()); + // recorder.setImageHeight(640); + // recorder.setImageWidth(480); + recorder.setFormat(mp4); recorder.setFrameRate(frameGrabber.getFrameRate()); - //recorder.setSampleFormat(frameGrabber.getSampleFormat()); // recorder.setSampleRate(frameGrabber.getSampleRate()); - + //视频编码属性配置 H.264 H.265 MPEG + recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); + //设置视频比特率,单位:b + recorder.setVideoBitrate(frameGrabber.getVideoBitrate()); + recorder.setAspectRatio(frameGrabber.getAspectRatio()); + // 设置音频通用编码格式 + recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); + //设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 128000 = 182kb) + recorder.setAudioBitrate(frameGrabber.getAudioBitrate()); + recorder.setAudioOptions(frameGrabber.getAudioOptions()); recorder.setAudioChannels(frameGrabber.getAudioChannels()); - recorder.setFrameRate(frameGrabber.getFrameRate()); recorder.start(); - while ((captured_frame = frameGrabber.grabFrame()) != null) { - try { - recorder.setTimestamp(frameGrabber.getTimestamp()); - recorder.record(captured_frame); - } catch (Exception e) { + while (true) { + captured_frame = frameGrabber.grabFrame(); + if (captured_frame == null) { + System.out.println("转码完成:"+filePath); + break; } + recorder.record(captured_frame); } - recorder.stop(); - recorder.release(); - frameGrabber.stop(); } catch (Exception e) { e.printStackTrace(); + return null; + }finally { + if (recorder != null) { //关闭 + recorder.stop(); + recorder.close(); + } + frameGrabber.stop(); + frameGrabber.close(); } - //是否删除源文件 - //file.delete(); - return convertFileName; + return outFilePath; } + } diff --git a/server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java index 82b1191f..ae1a7a13 100644 --- a/server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/OfficeFilePreviewImpl.java @@ -15,10 +15,10 @@ import org.apache.poi.EncryptedDocumentException; import org.jodconverter.core.office.OfficeException; import org.springframework.stereotype.Service; import org.springframework.ui.Model; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import java.io.IOException; -import java.net.URLEncoder; import java.util.List; /** @@ -30,7 +30,6 @@ public class OfficeFilePreviewImpl implements FilePreview { public static final String OFFICE_PREVIEW_TYPE_IMAGE = "image"; public static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages"; - private static final String FILE_DIR = ConfigConstants.getFileDir(); private static final String OFFICE_PASSWORD_MSG = "password"; private final FileHandlerService fileHandlerService; @@ -47,16 +46,16 @@ public class OfficeFilePreviewImpl implements FilePreview { public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) { // 预览Type,参数传了就取参数的,没传取系统默认 String officePreviewType = fileAttribute.getOfficePreviewType(); + boolean userToken = fileAttribute.getUserToken(); String baseUrl = BaseUrlFilter.getBaseUrl(); - String suffix = fileAttribute.getSuffix(); - String fileName = fileAttribute.getName(); - String filePassword = fileAttribute.getFilePassword(); - boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); - String userToken = fileAttribute.getUserToken(); - boolean isHtml = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx") || suffix.equalsIgnoreCase("csv") || suffix.equalsIgnoreCase("xlsm") || suffix.equalsIgnoreCase("xlt") || suffix.equalsIgnoreCase("xltm") || suffix.equalsIgnoreCase("et") || suffix.equalsIgnoreCase("ett") || suffix.equalsIgnoreCase("xlam"); - String pdfName = fileName.substring(0, fileName.lastIndexOf(".") ) + suffix +"." +(isHtml ? "html" : "pdf"); //生成文件添加类型后缀 防止同名文件 - String cacheFileName = userToken == null ? pdfName : userToken + "_" + pdfName; - String outFilePath = FILE_DIR + cacheFileName; + String suffix = fileAttribute.getSuffix(); //获取文件后缀 + String fileName = fileAttribute.getName(); //获取文件原始名称 + String filePassword = fileAttribute.getFilePassword(); //获取密码 + boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); //是否启用强制更新命令 + boolean isHtml =fileAttribute.getisHtml(); //xlsx 转换成html + String cacheName = fileAttribute.getcacheName(); //转换后的文件名 + String outFilePath = fileAttribute.getoutFilePath(); //转换后生成文件的路径 + String fileKey = fileAttribute.getFileKey(); //判断是否压缩包 if (!officePreviewType.equalsIgnoreCase("html")) { if (ConfigConstants.getOfficeTypeWeb() .equalsIgnoreCase("web")) { if (suffix.equalsIgnoreCase("xlsx")) { @@ -69,40 +68,14 @@ public class OfficeFilePreviewImpl implements FilePreview { } } } - if (forceUpdatedCache|| !fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) { + if (forceUpdatedCache|| !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) { // 下载远程文件到本地,如果文件在本地已存在不会重复下载 ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); if (response.isFailure()) { return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); } - String filePath = response.getContent(); - /* - * 1. 缓存判断-如果文件已经进行转换过,就直接返回,否则执行转换 - * 2. 缓存判断-加密文件基于userToken进行缓存,如果没有就不缓存 - */ - boolean isCached = false; - boolean isUseCached = false; - boolean isPwdProtectedOffice = false; - if (ConfigConstants.isCacheEnabled()) { - // 全局开启缓存 - isUseCached = true; - if (!forceUpdatedCache && fileHandlerService.listConvertedFiles().containsKey(cacheFileName)) { - // 存在缓存 - isCached = true; - } - if (OfficeUtils.isPwdProtected(filePath)) { - isPwdProtectedOffice = true; - if (!StringUtils.hasLength(userToken)) { - // 不缓存没有userToken的加密文件 - isUseCached = false; - } - } - } else { - isPwdProtectedOffice = OfficeUtils.isPwdProtected(filePath); - } - - if (!isCached) { - // 没有缓存执行转换逻辑 + String filePath = response.getContent(); + boolean isPwdProtectedOffice = OfficeUtils.isPwdProtected(filePath); // 判断是否加密文件 if (isPwdProtectedOffice && !StringUtils.hasLength(filePassword)) { // 加密文件需要密码 model.addAttribute("needFilePassword", true); @@ -118,40 +91,37 @@ public class OfficeFilePreviewImpl implements FilePreview { model.addAttribute("filePasswordError", true); return EXEL_FILE_PREVIEW_PAGE; } - return otherFilePreview.notSupportedFile(model, fileAttribute, "抱歉,该文件版本不兼容,文件版本错误。"); } - if (isHtml) { // 对转换后的文件进行操作(改变编码方式) fileHandlerService.doActionConvertedFile(outFilePath); } //是否保留OFFICE源文件 - if (ConfigConstants.getDeleteSourceFile()) { + if (ObjectUtils.isEmpty(fileKey) && ConfigConstants.getDeleteSourceFile()) { KkFileUtils.deleteFileByPath(filePath); } - if (isUseCached) { + if (userToken || !isPwdProtectedOffice) { // 加入缓存 - fileHandlerService.addConvertedFile(cacheFileName, fileHandlerService.getRelativePath(outFilePath)); + fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath)); } } } - } + } if (!isHtml && baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) { - return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, cacheFileName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview); + return getPreviewType(model, fileAttribute, officePreviewType, cacheName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview); } - cacheFileName = URLEncoder.encode(cacheFileName).replaceAll("\\+", "%20"); - model.addAttribute("pdfUrl", cacheFileName); + model.addAttribute("pdfUrl", cacheName); return isHtml ? EXEL_FILE_PREVIEW_PAGE : PDF_FILE_PREVIEW_PAGE; } - static String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String baseUrl, String pdfName, String outFilePath, FileHandlerService fileHandlerService, String officePreviewTypeImage, OtherFilePreviewImpl otherFilePreview) { + static String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String pdfName, String outFilePath, FileHandlerService fileHandlerService, String officePreviewTypeImage, OtherFilePreviewImpl otherFilePreview) { String suffix = fileAttribute.getSuffix(); boolean isPPT = suffix.equalsIgnoreCase("ppt") || suffix.equalsIgnoreCase("pptx"); List imageUrls = null; try { - imageUrls = fileHandlerService.pdf2jpg(outFilePath, pdfName, fileAttribute); + imageUrls = fileHandlerService.pdf2jpg(outFilePath,outFilePath, pdfName, fileAttribute); } catch (Exception e) { Throwable[] throwableArray = ExceptionUtils.getThrowables(e); for (Throwable throwable : throwableArray) { diff --git a/server/src/main/java/cn/keking/service/impl/PdfFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/PdfFilePreviewImpl.java index 2d92980b..7d91f640 100644 --- a/server/src/main/java/cn/keking/service/impl/PdfFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/PdfFilePreviewImpl.java @@ -24,37 +24,34 @@ public class PdfFilePreviewImpl implements FilePreview { private final FileHandlerService fileHandlerService; private final OtherFilePreviewImpl otherFilePreview; - private static final String FILE_DIR = ConfigConstants.getFileDir(); private static final String PDF_PASSWORD_MSG = "password"; - public PdfFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) { this.fileHandlerService = fileHandlerService; this.otherFilePreview = otherFilePreview; } - @Override public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) { - String fileName = fileAttribute.getName(); - String officePreviewType = fileAttribute.getOfficePreviewType(); - boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); - String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf"; - String outFilePath = FILE_DIR + pdfName; + String pdfName = fileAttribute.getName(); //获取原始文件名 + String officePreviewType = fileAttribute.getOfficePreviewType(); //转换类型 + boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); //是否启用强制更新命令 + String outFilePath = fileAttribute.getoutFilePath(); //生成的文件路径 + String fileNameFilePath = fileAttribute.getfileNameFilePath(); //原始文件路径 if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) { //当文件不存在时,就去下载 if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) { - ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); + ReturnResponse response = DownloadUtils.downLoad(fileAttribute, pdfName); if (response.isFailure()) { return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); } - outFilePath = response.getContent(); + fileNameFilePath = response.getContent(); if (ConfigConstants.isCacheEnabled()) { // 加入缓存 - fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath)); + fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(fileNameFilePath)); } } List imageUrls; try { - imageUrls = fileHandlerService.pdf2jpg(outFilePath, pdfName, fileAttribute); + imageUrls = fileHandlerService.pdf2jpg(fileNameFilePath,outFilePath, pdfName, fileAttribute); } catch (Exception e) { Throwable[] throwableArray = ExceptionUtils.getThrowables(e); for (Throwable throwable : throwableArray) { @@ -91,7 +88,6 @@ public class PdfFilePreviewImpl implements FilePreview { fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath)); } } else { - pdfName = URLEncoder.encode(pdfName).replaceAll("\\+", "%20"); model.addAttribute("pdfUrl", pdfName); } } else { diff --git a/server/src/main/java/cn/keking/service/impl/PictureFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/PictureFilePreviewImpl.java index e991582b..21403a97 100644 --- a/server/src/main/java/cn/keking/service/impl/PictureFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/PictureFilePreviewImpl.java @@ -1,10 +1,7 @@ package cn.keking.service.impl; import cn.keking.model.FileAttribute; -import cn.keking.model.ReturnResponse; import cn.keking.service.FileHandlerService; -import cn.keking.service.FilePreview; -import cn.keking.utils.DownloadUtils; import cn.keking.utils.KkFileUtils; import org.springframework.stereotype.Service; import org.springframework.ui.Model; @@ -21,12 +18,10 @@ import java.util.List; public class PictureFilePreviewImpl extends CommonPreviewImpl { private final FileHandlerService fileHandlerService; - private final OtherFilePreviewImpl otherFilePreview; public PictureFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) { super(fileHandlerService, otherFilePreview); this.fileHandlerService = fileHandlerService; - this.otherFilePreview = otherFilePreview; } @Override diff --git a/server/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java index e4b8ece4..8df5ffdc 100644 --- a/server/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/SimTextFilePreviewImpl.java @@ -30,12 +30,12 @@ public class SimTextFilePreviewImpl implements FilePreview { this.fileHandlerService = fileHandlerService; this.otherFilePreview = otherFilePreview; } - private static final String FILE_DIR = ConfigConstants.getFileDir(); + @Override public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) { String fileName = fileAttribute.getName(); boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); - String filePath = FILE_DIR + fileName; + String filePath = fileAttribute.getfileNameFilePath(); if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(fileName) || !ConfigConstants.isCacheEnabled()) { ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); if (response.isFailure()) { diff --git a/server/src/main/java/cn/keking/service/impl/TiffFilePreviewImpl.java b/server/src/main/java/cn/keking/service/impl/TiffFilePreviewImpl.java index ec003969..0eea6a3c 100644 --- a/server/src/main/java/cn/keking/service/impl/TiffFilePreviewImpl.java +++ b/server/src/main/java/cn/keking/service/impl/TiffFilePreviewImpl.java @@ -8,13 +8,11 @@ import cn.keking.service.FilePreview; import cn.keking.utils.ConvertPicUtil; import cn.keking.utils.DownloadUtils; import cn.keking.utils.KkFileUtils; -import cn.keking.web.filter.BaseUrlFilter; import org.springframework.stereotype.Service; import org.springframework.ui.Model; -import org.springframework.util.StringUtils; +import org.springframework.util.ObjectUtils; -import java.io.File; -import java.util.ArrayList; +import java.io.IOException; import java.util.List; /** @@ -32,75 +30,100 @@ public class TiffFilePreviewImpl implements FilePreview { this.fileHandlerService = fileHandlerService; this.otherFilePreview = otherFilePreview; } - private final String fileDir = ConfigConstants.getFileDir(); @Override public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) { String fileName = fileAttribute.getName(); - String baseUrl = BaseUrlFilter.getBaseUrl(); String tifPreviewType = ConfigConstants.getTifPreviewType(); - String tifOnLinePreviewType = fileAttribute.getTifPreviewType(); - String suffix = fileAttribute.getSuffix(); + String cacheName = fileAttribute.getcacheName(); + String outFilePath = fileAttribute.getoutFilePath(); + String fileKey = fileAttribute.getFileKey(); //判断是否压缩包 boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); - if (StringUtils.hasText(tifOnLinePreviewType)) { - tifPreviewType = tifOnLinePreviewType; - } - if ("tif".equalsIgnoreCase(tifPreviewType)) { - model.addAttribute("currentUrl", url); - return TIFF_FILE_PREVIEW_PAGE; - } else if ("jpg".equalsIgnoreCase(tifPreviewType) || "pdf".equalsIgnoreCase(tifPreviewType)) { - String pdfName = fileName.substring(0, fileName.lastIndexOf(".")) + suffix +"." + "pdf" ; //生成文件添加类型后缀 防止同名文件 - String jpgName = fileName.substring(0, fileName.lastIndexOf(".")) + suffix; //生成文件添加类型后缀 防止同名文件 - String strLocalTif = fileDir + fileName; - String outFilePath = fileDir + pdfName; - if ("pdf".equalsIgnoreCase(tifPreviewType)) { - //当文件不存在时,就去下载 - if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) { - ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); - if (response.isFailure()) { - return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); - } - String filePath = response.getContent(); - if (ConvertPicUtil.convertJpg2Pdf(filePath, outFilePath)) { - //是否保留TIFF源文件 - if (ConfigConstants.getDeleteSourceFile()) { - KkFileUtils.deleteFileByPath(filePath); - } - if (ConfigConstants.isCacheEnabled()) { - // 加入缓存 - fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath)); + if ("jpg".equalsIgnoreCase(tifPreviewType) || "pdf".equalsIgnoreCase(tifPreviewType)) { + if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) { + ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); + if (response.isFailure()) { + return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); + } + String filePath = response.getContent(); + if ("pdf".equalsIgnoreCase(tifPreviewType)) { + try { + ConvertPicUtil.convertJpg2Pdf(filePath, outFilePath); + } catch (Exception e) { + if (e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) { + model.addAttribute("imgUrls", url); + model.addAttribute("currentUrl", url); + return PICTURE_FILE_PREVIEW_PAGE; + }else { + return otherFilePreview.notSupportedFile(model, fileAttribute, "TIF转pdf异常,请联系系统管理员!" ); } - model.addAttribute("pdfUrl", pdfName); - return PDF_FILE_PREVIEW_PAGE; - } else { - return NOT_SUPPORTED_FILE_PAGE; } - } else { - model.addAttribute("pdfUrl", pdfName); + //是否保留TIFF源文件 + if (ObjectUtils.isEmpty(fileKey) && ConfigConstants.getDeleteSourceFile()) { + // KkFileUtils.deleteFileByPath(filePath); + } + if (ConfigConstants.isCacheEnabled()) { + // 加入缓存 + fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath)); + } + model.addAttribute("pdfUrl", cacheName); return PDF_FILE_PREVIEW_PAGE; - } - } else { - File fileTiff = new File(strLocalTif); - // 如果本地不存在这个tif文件,则下载 - if (!fileTiff.exists()) { - ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); - if (response.isFailure()) { - return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); + }else { + // 将tif转换为jpg,返回转换后的文件路径、文件名的list + List listPic2Jpg; + try { + listPic2Jpg = ConvertPicUtil.convertTif2Jpg(filePath, outFilePath,forceUpdatedCache); + } catch (Exception e) { + if (e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) { + model.addAttribute("imgUrls", url); + model.addAttribute("currentUrl", url); + return PICTURE_FILE_PREVIEW_PAGE; + }else { + return otherFilePreview.notSupportedFile(model, fileAttribute, "TIF转JPG异常,请联系系统管理员!" ); + } } - strLocalTif = response.getContent(); + //是否保留源文件,转换失败保留源文件,转换成功删除源文件 + if(ObjectUtils.isEmpty(fileKey) && ConfigConstants.getDeleteSourceFile()) { + KkFileUtils.deleteFileByPath(filePath); + } + if (ConfigConstants.isCacheEnabled()) { + // 加入缓存 + fileHandlerService.putImgCache(cacheName, listPic2Jpg); + fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath)); + } + model.addAttribute("imgUrls", listPic2Jpg); + model.addAttribute("currentUrl", listPic2Jpg.get(0)); + return PICTURE_FILE_PREVIEW_PAGE; } - // 将tif转换为jpg,返回转换后的文件路径、文件名的list - List listPic2Jpg = ConvertPicUtil.convertTif2Jpg(strLocalTif, jpgName); - // 将返回页面的图片url的list对象 - List listImageUrls = new ArrayList<>(); - // 循环,拼装url的list对象 - for (String strJpg : listPic2Jpg) { - listImageUrls.add(baseUrl + strJpg); + } + if ("pdf".equalsIgnoreCase(tifPreviewType)) { + model.addAttribute("pdfUrl", fileHandlerService.listConvertedFiles().get(cacheName)); + return PDF_FILE_PREVIEW_PAGE; + } + else if ("jpg".equalsIgnoreCase(tifPreviewType)) { + model.addAttribute("imgUrls", fileHandlerService.getImgCache(cacheName)); + model.addAttribute("currentUrl", fileHandlerService.getImgCache(cacheName).get(0)); + return PICTURE_FILE_PREVIEW_PAGE; + } + } + // 不是http开头,浏览器不能直接访问,需下载到本地 + if (url != null && !url.toLowerCase().startsWith("http")) { + if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(fileName) || !ConfigConstants.isCacheEnabled()) { + ReturnResponse response = DownloadUtils.downLoad(fileAttribute, fileName); + if (response.isFailure()) { + return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg()); + } + model.addAttribute("currentUrl", fileHandlerService.getRelativePath(response.getContent())); + if (ConfigConstants.isCacheEnabled()) { + // 加入缓存 + fileHandlerService.addConvertedFile(fileName, fileHandlerService.getRelativePath(outFilePath)); } - model.addAttribute("imgUrls", listImageUrls); - model.addAttribute("currentUrl", listImageUrls.get(0)); + } else { + model.addAttribute("currentUrl", fileName); } - return PICTURE_FILE_PREVIEW_PAGE; + return TIFF_FILE_PREVIEW_PAGE; } - return NOT_SUPPORTED_FILE_PAGE; + model.addAttribute("currentUrl", url); + return TIFF_FILE_PREVIEW_PAGE; } } + diff --git a/server/src/main/java/cn/keking/utils/ConvertPicUtil.java b/server/src/main/java/cn/keking/utils/ConvertPicUtil.java index 21cfa429..e219c051 100644 --- a/server/src/main/java/cn/keking/utils/ConvertPicUtil.java +++ b/server/src/main/java/cn/keking/utils/ConvertPicUtil.java @@ -1,26 +1,26 @@ package cn.keking.utils; - import cn.keking.config.ConfigConstants; - -import com.sun.media.jai.codec.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import cn.keking.web.filter.BaseUrlFilter; import com.itextpdf.text.Document; import com.itextpdf.text.Image; import com.itextpdf.text.io.FileChannelRandomAccessSource; import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.text.pdf.RandomAccessFileOrArray; import com.itextpdf.text.pdf.codec.TiffImage; +import com.sun.media.jai.codec.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import javax.media.jai.JAI; import javax.media.jai.RenderedOp; import java.awt.image.RenderedImage; import java.awt.image.renderable.ParameterBlock; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.List; @@ -28,7 +28,6 @@ public class ConvertPicUtil { private static final int FIT_WIDTH = 500; private static final int FIT_HEIGHT = 900; - private final static Logger logger = LoggerFactory.getLogger(ConvertPicUtil.class); private final static String fileDir = ConfigConstants.getFileDir(); /** @@ -38,17 +37,14 @@ public class ConvertPicUtil { * @param strOutputFile 输出文件的路径和文件名 * @return boolean 是否转换成功 */ - public static List convertTif2Jpg(String strInputFile, String strOutputFile) { + public static List convertTif2Jpg(String strInputFile, String strOutputFile, boolean forceUpdatedCache) throws Exception { List listImageFiles = new ArrayList<>(); - - if (strInputFile == null || "".equals(strInputFile.trim())) { - return null; - } + String baseUrl = BaseUrlFilter.getBaseUrl(); if (!new File(strInputFile).exists()) { logger.info("找不到文件【" + strInputFile + "】"); return null; } - strInputFile = strInputFile.replaceAll("\\\\", "/"); + strOutputFile = strOutputFile.replaceAll(".jpg", ""); FileSeekableStream fileSeekStream = null; try { JPEGEncodeParam jpegEncodeParam = new JPEGEncodeParam(); @@ -58,20 +54,18 @@ public class ConvertPicUtil { fileSeekStream = new FileSeekableStream(strInputFile); ImageDecoder imageDecoder = ImageCodec.createImageDecoder("TIFF", fileSeekStream, null); int intTifCount = imageDecoder.getNumPages(); - logger.info("该tif文件共有【" + intTifCount + "】页"); - String strJpgPath = fileDir+strOutputFile; + // logger.info("该tif文件共有【" + intTifCount + "】页"); // 处理目标文件夹,如果不存在则自动创建 - File fileJpgPath = new File(strJpgPath); + File fileJpgPath = new File(strOutputFile); if (!fileJpgPath.exists() && !fileJpgPath.mkdirs()) { - logger.error("{} 创建失败", strJpgPath); + logger.error("{} 创建失败", strOutputFile); } // 循环,处理每页tif文件,转换为jpg for (int i = 0; i < intTifCount; i++) { - String strJpg= strJpgPath + "/" + i + ".jpg"; - String strJpgUrl = strOutputFile + "/" + i + ".jpg"; + String strJpg= strOutputFile + "/" + i + ".jpg"; File fileJpg = new File(strJpg); // 如果文件不存在,则生成 - if (!fileJpg.exists()) { + if (forceUpdatedCache|| !fileJpg.exists()) { RenderedImage renderedImage = imageDecoder.decodeAsRenderedImage(i); ParameterBlock pb = new ParameterBlock(); pb.addSource(renderedImage); @@ -80,24 +74,22 @@ public class ConvertPicUtil { pb.add(jpegEncodeParam); RenderedOp renderedOp = JAI.create("filestore", pb); renderedOp.dispose(); - logger.info("每页分别保存至: " + fileJpg.getCanonicalPath()); + // logger.info("每页分别保存至: " + fileJpg.getCanonicalPath()); } - listImageFiles.add(strJpgUrl); + strJpg = baseUrl+strJpg.replace(fileDir, ""); + listImageFiles.add(strJpg); } - - return listImageFiles; } catch (IOException e) { - e.printStackTrace(); - return null; + if (!e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) { + logger.error("TIF转JPG异常,文件路径:" + strInputFile, e); + } + throw new Exception(e); } finally { if (fileSeekStream != null) { - try { - fileSeekStream.close(); - } catch (IOException e) { - logger.error(e.getMessage(), e); - } + fileSeekStream.close(); } } + return listImageFiles; } /** @@ -106,44 +98,41 @@ public class ConvertPicUtil { * @param strJpgFile 输入的jpg的路径和文件名 * @param strPdfFile 输出的pdf的路径和文件名 */ - public static boolean convertJpg2Pdf(String strJpgFile, String strPdfFile) { - Document document = null; + public static String convertJpg2Pdf(String strJpgFile, String strPdfFile) throws Exception { + Document document = new Document(); RandomAccessFileOrArray rafa = null; + FileOutputStream outputStream = null; try { - document = new Document(); - PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(strPdfFile))); - document.open(); - rafa = new RandomAccessFileOrArray(new FileChannelRandomAccessSource(new RandomAccessFile(strJpgFile, "r").getChannel())); + RandomAccessFile aFile = new RandomAccessFile(strJpgFile, "r"); + FileChannel inChannel = aFile.getChannel(); + FileChannelRandomAccessSource fcra = new FileChannelRandomAccessSource(inChannel); + rafa = new RandomAccessFileOrArray(fcra); int pages = TiffImage.getNumberOfPages(rafa); + outputStream = new FileOutputStream(strPdfFile); + PdfWriter.getInstance(document, outputStream); + document.open(); Image image; for (int i = 1; i <= pages; i++) { - try { - image = TiffImage.getTiffImage(rafa, i); - image.scaleToFit(FIT_WIDTH, FIT_HEIGHT); - document.add(image); - } catch (Exception e) { - document.close(); - rafa.close(); - e.printStackTrace(); - } + image = TiffImage.getTiffImage(rafa, i); + image.scaleToFit(FIT_WIDTH, FIT_HEIGHT); + document.add(image); } - document.close(); - rafa.close(); - return true; - } catch (Exception e) { - logger.error("图片转PDF异常,图片文件路径:" + strJpgFile, e); + } catch (IOException e) { + if (!e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) { + logger.error("TIF转JPG异常,文件路径:" + strPdfFile, e); + } + throw new Exception(e); } finally { - try { - if (document != null && document.isOpen()) { - document.close(); - } - if (rafa != null) { - rafa.close(); - } - } catch (IOException e) { - e.printStackTrace(); + if (document != null) { + document.close(); + } + if (rafa != null) { + rafa.close(); + } + if (outputStream != null) { + outputStream.close(); } } - return false; + return strPdfFile; } } \ No newline at end of file diff --git a/server/src/main/java/cn/keking/utils/DownloadUtils.java b/server/src/main/java/cn/keking/utils/DownloadUtils.java index 9bd93fcd..b9a8a108 100644 --- a/server/src/main/java/cn/keking/utils/DownloadUtils.java +++ b/server/src/main/java/cn/keking/utils/DownloadUtils.java @@ -8,24 +8,28 @@ import io.mola.galimatias.GalimatiasParseException; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RequestCallback; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.net.URI; import java.net.URL; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; +import java.net.URLEncoder; import java.util.Arrays; import java.util.Map; import java.util.UUID; import static cn.keking.utils.KkFileUtils.isFtpUrl; import static cn.keking.utils.KkFileUtils.isHttpUrl; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.util.StringUtils; -import org.springframework.web.client.RequestCallback; -import org.springframework.web.client.RestTemplate; + /** * @author yudian-it */ @@ -46,11 +50,12 @@ public class DownloadUtils { * @return 本地文件绝对路径 */ public static ReturnResponse downLoad(FileAttribute fileAttribute, String fileName) { + String fileKey = fileAttribute.getFileKey(); // 忽略ssl证书 String urlStr = null; try { SslUtils.ignoreSsl(); - urlStr = fileAttribute.getUrl().replaceAll("\\+", "%20"); + urlStr = fileAttribute.getUrl().replaceAll("\\+", "%20").replaceAll(" ", "%20"); } catch (Exception e) { logger.error("忽略SSL证书异常:", e); } @@ -70,8 +75,7 @@ public class DownloadUtils { response.setMsg("下载失败:不支持的类型!" + urlStr); return response; } - assert urlStr != null; - if (urlStr.contains("?fileKey=")) { + if (!ObjectUtils.isEmpty(fileKey)) { //压缩包文件 直接赋予路径 不予下载 response.setContent(fileDir + fileName); response.setMsg(fileName); return response; @@ -87,20 +91,32 @@ public class DownloadUtils { if (!fileAttribute.getSkipDownLoad()) { if (isHttpUrl(url)) { File realFile = new File(realPath); + SimpleClientHttpRequestFactory httpFactory = new SimpleClientHttpRequestFactory(); + //连接超时10秒,默认无限制,单位:毫秒 + httpFactory.setConnectTimeout(60 * 1000); + //读取超时5秒,默认无限限制,单位:毫秒 + httpFactory.setReadTimeout(60 * 1000); + restTemplate.setRequestFactory(httpFactory); RequestCallback requestCallback = request -> { - request.getHeaders() - .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL)); - String proxyAuthorization = fileAttribute.getKkProxyAuthorization(); + request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL)); + String proxyAuthorization = fileAttribute.getKkProxyAuthorization(); if(StringUtils.hasText(proxyAuthorization)){ - Map proxyAuthorizationMap = mapper.readValue(proxyAuthorization, Map.class); - proxyAuthorizationMap.entrySet().forEach(entry-> request.getHeaders().set(entry.getKey(), entry.getValue())); + Map proxyAuthorizationMap = mapper.readValue(proxyAuthorization, Map.class); + proxyAuthorizationMap.forEach((key, value) -> request.getHeaders().set(key, value)); } }; - urlStr = URLDecoder.decode(urlStr, StandardCharsets.UTF_8.name()); - restTemplate.execute(urlStr, HttpMethod.GET, requestCallback, fileResponse -> { - FileUtils.copyToFile(fileResponse.getBody(), realFile); - return null; - }); + try { + URI uri = URI.create(urlStr); + restTemplate.execute(uri, HttpMethod.GET, requestCallback, fileResponse -> { + FileUtils.copyToFile(fileResponse.getBody(), realFile); + return null; + }); + } catch (Exception e) { + response.setCode(1); + response.setContent(null); + response.setMsg("下载失败:" + e); + return response; + } } else if (isFtpUrl(url)) { String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME); String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD); diff --git a/server/src/main/java/cn/keking/utils/UrlEncoderUtils.java b/server/src/main/java/cn/keking/utils/UrlEncoderUtils.java new file mode 100644 index 00000000..1cfb2bd3 --- /dev/null +++ b/server/src/main/java/cn/keking/utils/UrlEncoderUtils.java @@ -0,0 +1,82 @@ +package cn.keking.utils; +import java.util.BitSet; + + +public class UrlEncoderUtils { + + private static BitSet dontNeedEncoding; + + static { + dontNeedEncoding = new BitSet(256); + int i; + for (i = 'a'; i <= 'z'; i++) { + dontNeedEncoding.set(i); + } + for (i = 'A'; i <= 'Z'; i++) { + dontNeedEncoding.set(i); + } + for (i = '0'; i <= '9'; i++) { + dontNeedEncoding.set(i); + } + dontNeedEncoding.set('+'); + /** + * 这里会有误差,比如输入一个字符串 123+456,它到底是原文就是123+456还是123 456做了urlEncode后的内容呢?
+ * 其实问题是一样的,比如遇到123%2B456,它到底是原文即使如此,还是123+456 urlEncode后的呢?
+ * 在这里,我认为只要符合urlEncode规范的,就当作已经urlEncode过了
+ * 毕竟这个方法的初衷就是判断string是否urlEncode过
+ */ + + dontNeedEncoding.set('-'); + dontNeedEncoding.set('_'); + dontNeedEncoding.set('.'); + dontNeedEncoding.set('*'); + } + + /** + * 判断str是否urlEncoder.encode过
+ * 经常遇到这样的情况,拿到一个URL,但是搞不清楚到底要不要encode.
+ * 不做encode吧,担心出错,做encode吧,又怕重复了
+ * + * @param str + * @return + */ + public static boolean hasUrlEncoded(String str) { + + /** + * 支持JAVA的URLEncoder.encode出来的string做判断。 即: 将' '转成'+'
+ * 0-9a-zA-Z保留
+ * '-','_','.','*'保留
+ * 其他字符转成%XX的格式,X是16进制的大写字符,范围是[0-9A-F] + */ + boolean needEncode = false; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (dontNeedEncoding.get((int) c)) { + continue; + } + if (c == '%' && (i + 2) < str.length()) { + // 判断是否符合urlEncode规范 + char c1 = str.charAt(++i); + char c2 = str.charAt(++i); + if (isDigit16Char(c1) && isDigit16Char(c2)) { + continue; + } + } + // 其他字符,肯定需要urlEncode + needEncode = true; + break; + } + + return !needEncode; + } + + /** + * 判断c是否是16进制的字符 + * + * @param c + * @return + */ + private static boolean isDigit16Char(char c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'); + } +} \ No newline at end of file diff --git a/server/src/main/resources/web/compress.ftl b/server/src/main/resources/web/compress.ftl index e80c66c3..d8b4a000 100644 --- a/server/src/main/resources/web/compress.ftl +++ b/server/src/main/resources/web/compress.ftl @@ -52,7 +52,7 @@ function chooseNode(event, treeId, treeNode) { if (!treeNode.isParent) { - var path = '${baseUrl}' + treeNode.id + "?fileKey=" + '${fileName}'; + var path = '${baseUrl}' + treeNode.id + "?kkCompressfileKey=" + '${fileName}'; location.href = "${baseUrl}onlinePreview?url=" + encodeURIComponent(Base64.encode(path)); } }