Переглянути джерело

1.修复压缩包 二级目录无法解压问题 修改压缩包生成PDF路径
2.修复PDF 带密码缓存问题 新增PDF带密码缓存方法 userToken
3.精简OFFICE 转换代码
4.精简TIF转换代码 新增TIF转换图片缓存 修复tif错误文件不自动释放内存 等待其他修复
5.修复下载方法错 特殊符号下载错误
6.调整文件名 统一方法在FileHandlerService
7.新增判断文件名是否被URL转义

gaoxiongzaq 2 роки тому
батько
коміт
deb91728d4

+ 38 - 3
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;
     }

+ 16 - 10
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<String> 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 {

+ 87 - 33
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;
@@ -195,11 +199,13 @@ public class FileHandlerService implements InitializingBean {
      * @param index 图片索引
      * @return 图片访问地址
      */
-    private String getPdf2jpgUrl(String pdfName, int index) {
+    private String getPdf2jpgUrl(String pdfName, int index,String fileKey) {
         String baseUrl = BaseUrlFilter.getBaseUrl();
+        if (!ObjectUtils.isEmpty(fileKey)) { // 是压缩包文件 改变PDF生成图片的路径
+                pdfName = "_decompression"+ pdfName;
+        }
         String pdfFolder = pdfName.substring(0, pdfName.length() - 4);
         String urlPrefix;
-
         try {
             urlPrefix = baseUrl + URLEncoder.encode(pdfFolder, uriEncoding).replaceAll("\\+", "%20");
         } catch (UnsupportedEncodingException e) {
@@ -215,14 +221,14 @@ public class FileHandlerService implements InitializingBean {
      * @param pdfName pdf文件名称
      * @return 图片访问集合
      */
-    private List<String> loadPdf2jpgCache(String pdfFilePath, String pdfName) {
+    private List<String> loadPdf2jpgCache(String pdfFilePath, String pdfName, String fileKey) {
         List<String> 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(pdfName, i,fileKey);
             imageUrls.add(imageUrl);
         });
         return imageUrls;
@@ -230,26 +236,28 @@ public class FileHandlerService implements InitializingBean {
 
     /**
      * pdf文件转换成jpg图片集
-     *
-     * @param pdfFilePath pdf文件路径
-     * @param pdfName     pdf文件名称
-     * @return 图片访问集合
+     * fileNameFilePath pdf文件路径
+     * pdfFilePath pdf输出文件路径
+     * pdfName     pdf文件名称
+     *  loadPdf2jpgCache 图片访问集合
      */
-    public List<String> pdf2jpg(String pdfFilePath, String pdfName, FileAttribute fileAttribute) throws Exception {
+    public List<String> 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<String> cacheResult = this.loadPdf2jpgCache(pdfFilePath, pdfName);
+            List<String> cacheResult = this.loadPdf2jpgCache(pdfFilePath, pdfName,fileKey);
             if (!CollectionUtils.isEmpty(cacheResult)) {
                 return cacheResult;
             }
         }
         List<String> imageUrls = new ArrayList<>();
         try {
-            File pdfFile = new File(pdfFilePath);
+            File pdfFile = new File(fileNameFilePath);
             if (!pdfFile.exists()) {
                 return null;
             }
@@ -268,36 +276,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(pdfName, pageIndex,fileKey);
                 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) {   //关闭
@@ -411,8 +422,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 +445,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");
+                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.MEDIA)){
+            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 +520,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);

+ 13 - 14
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,18 +40,17 @@ 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<String> response = DownloadUtils.downLoad(fileAttribute, null);
+        if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) {
+            ReturnResponse<String> 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 {
@@ -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;
     }
 }

+ 3 - 2
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()) {

+ 81 - 102
server/src/main/java/cn/keking/service/impl/MediaFilePreviewImpl.java

@@ -1,20 +1,18 @@
 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 java.io.File;
 
 /**
@@ -28,139 +26,120 @@ 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<String> 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[] mediaTypesConvert = FileType.MEDIA_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<String> 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);
+                    }else {
+                        convertedUrl =outFilePath;  //不是http协议的  但是不是转换格式的直接输出
                     }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                if (convertedUrl == null ) {
+                    fileHandlerService.addConvertedFile(cacheName, "error");  //失败加入缓存
+                    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;
+        model.addAttribute("mediaUrl", url);
+        return MEDIA_FILE_PREVIEW_PAGE;
     }
-
     /**
      * 检查视频文件转换是否已开启,以及当前文件是否需要转换
      * @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)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;
             }
-
             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;
     }
+
 }

+ 21 - 51
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<String> 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<String> 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) {

+ 9 - 13
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<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
+                ReturnResponse<String> 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<String> 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 {

+ 0 - 5
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

+ 2 - 2
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<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
             if (response.isFailure()) {

+ 84 - 61
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<String> 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<String> 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<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
-                    if (response.isFailure()) {
-                        return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
+                }else {
+                    // 将tif转换为jpg,返回转换后的文件路径、文件名的list
+                    List<String> 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<String> listPic2Jpg = ConvertPicUtil.convertTif2Jpg(strLocalTif, jpgName);
-                // 将返回页面的图片url的list对象
-                List<String> 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<String> 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;
     }
 }
+

+ 51 - 62
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<String> convertTif2Jpg(String strInputFile, String strOutputFile) {
+    public static List<String> convertTif2Jpg(String strInputFile, String strOutputFile, boolean forceUpdatedCache) throws Exception {
         List<String> 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;
     }
 }

+ 39 - 19
server/src/main/java/cn/keking/utils/DownloadUtils.java

@@ -8,24 +8,27 @@ 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.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,6 +49,7 @@ public class DownloadUtils {
      * @return 本地文件绝对路径
      */
     public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
+        String fileKey = fileAttribute.getFileKey();
         // 忽略ssl证书
         String urlStr = null;
         try {
@@ -70,8 +74,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 +90,37 @@ 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<String,String>  proxyAuthorizationMap = mapper.readValue(proxyAuthorization, Map.class);
-                          proxyAuthorizationMap.entrySet().forEach(entry-> request.getHeaders().set(entry.getKey(), entry.getValue()));
+                            Map<String,String>  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 (RestClientException e) {
+                        if (e.getMessage().contains("404 Not Found") || e.getMessage().contains("403 Not Found") || e.getMessage().contains("500 Not Found") ){
+                            response.setCode(1);
+                            response.setContent(null);
+                            response.setMsg("下载失败:" + e);
+                            return response;
+                        }else {
+                            e.printStackTrace();
+                        }
+
+                    }
                 } else if (isFtpUrl(url)) {
                     String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
                     String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);

+ 82 - 0
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后的内容呢?<br>
+         * 其实问题是一样的,比如遇到123%2B456,它到底是原文即使如此,还是123+456 urlEncode后的呢? <br>
+         * 在这里,我认为只要符合urlEncode规范的,就当作已经urlEncode过了<br>
+         * 毕竟这个方法的初衷就是判断string是否urlEncode过<br>
+         */
+
+        dontNeedEncoding.set('-');
+        dontNeedEncoding.set('_');
+        dontNeedEncoding.set('.');
+        dontNeedEncoding.set('*');
+    }
+
+    /**
+     * 判断str是否urlEncoder.encode过<br>
+     * 经常遇到这样的情况,拿到一个URL,但是搞不清楚到底要不要encode.<Br>
+     * 不做encode吧,担心出错,做encode吧,又怕重复了<Br>
+     *
+     * @param str
+     * @return
+     */
+    public static boolean hasUrlEncoded(String str) {
+
+        /**
+         * 支持JAVA的URLEncoder.encode出来的string做判断。 即: 将' '转成'+' <br>
+         * 0-9a-zA-Z保留 <br>
+         * '-','_','.','*'保留 <br>
+         * 其他字符转成%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');
+    }
+}

+ 1 - 1
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));
         }
     }