Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 27ae58a0f4 | |||
| 4d83674806 | |||
| 12c85c60c7 | |||
| 4747ee93b2 | |||
| 5ec53c4b33 | |||
| ee7f7f50cc | |||
| 92869e8d6c | |||
| c66dda239f | |||
| e927760c40 | |||
| 8783f9059a | |||
| 12e1239267 | |||
| 7c963193ef | |||
| bce9a624d7 | |||
| dac3606b4e | |||
| eb00385d76 | |||
| 986f562266 | |||
| 11d0441ed4 | |||
| ef46e2c51e | |||
| 0a3c03f18b | |||
| 7a7e1a1855 | |||
| f530f441d5 | |||
| 10160e8104 | |||
| 602e80ee9e | |||
| 9c83860e1b |
2
.gitignore
vendored
2
.gitignore
vendored
@ -17,7 +17,6 @@ target/
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
@ -29,4 +28,3 @@ nbdist/
|
||||
|
||||
server/src/main/cache/
|
||||
server/src/main/file/
|
||||
server/src/main/log
|
||||
@ -28,5 +28,5 @@ ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
|
||||
ENV PATH $PATH:$JAVA_HOME/bin
|
||||
ENV LANG zh_CN.UTF-8
|
||||
ENV LC_ALL zh_CN.UTF-8
|
||||
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-2.2.1/bin
|
||||
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider","-Dspring.config.location=/opt/kkFileView-2.2.1/config/application.properties","-jar","/opt/kkFileView-2.2.1/bin/kkFileView-2.2.1.jar"]
|
||||
ENV KKFILEVIEW_BIN_FOLDER /opt/kkFileView-3.3.0/bin
|
||||
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider","-Dspring.config.location=/opt/kkFileView-3.3.0/config/application.properties","-jar","/opt/kkFileView-3.3.0/bin/kkFileView-3.3.0.jar"]
|
||||
20
README.md
20
README.md
@ -109,6 +109,26 @@ pdf预览模式预览效果如下
|
||||
|
||||
### 历史更新记录
|
||||
|
||||
> 2020年12月27日 :
|
||||
|
||||
2020年年终大版本更新,架构全面设计,代码全面重构,代码质量全面提升,二次开发更便捷,欢迎拉源码品鉴,提issue、pr共同建设
|
||||
|
||||
1. 架构模块调整,大量的代码重构,代码质量提升N个等级,欢迎品鉴
|
||||
2. 增强XML文件预览效果,新增XML文档数结构预览
|
||||
3. 新增markdown文件预览支持,预览支持md渲染和源文本切换支持
|
||||
4. 切换底层web server为jetty,解决这个issue:https://github.com/kekingcn/kkFileView/issues/168
|
||||
5. 引入cpdetector,解决文件编码识别问题
|
||||
6. url采用base64+urlencode双编码,彻底解决各种奇葩文件名预览问题
|
||||
7. 新增配置项office.preview.switch.disabled,控制offic文件预览切换开关
|
||||
8. 优化文本类型文件预览逻辑,采用Base64传输内容,避免预览时再次请求文件内容
|
||||
9. office预览图片模式禁用图片放大效果,达到图片和pdf预览效果一致的体验
|
||||
10. 直接代码静态设置pdfbox兼容低版本jdk,在IDEA中运行也不会有警告提示
|
||||
11. 移除guava、hutool等非必须的工具包,减少代码体积
|
||||
12. Office组件加载异步化,提速应用启动速度最快到5秒内
|
||||
13. 合理设置预览消费队列的线程数
|
||||
14. 修复压缩包里文件再次预览失败的bug
|
||||
15. 修复图片预览的bug
|
||||
|
||||
> 2020年05月20日 :
|
||||
1. 新增支持全局水印,并支持通过参数动态改变水印内容
|
||||
2. 新增支持CAD文件预览
|
||||
|
||||
2
pom.xml
2
pom.xml
@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>filepreview</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>3.3.0</version>
|
||||
<modules>
|
||||
<module>office-plugin</module>
|
||||
<module>server</module>
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>kkFileView</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>3.3.0</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@ -56,12 +56,6 @@
|
||||
<groupId>cn.keking</groupId>
|
||||
<artifactId>office-plugin</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<groupId>commons-io</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@ -105,11 +99,6 @@
|
||||
<artifactId>fr.opensagres.xdocreport.document</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<!-- 解压(apache) -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@ -201,6 +190,12 @@
|
||||
<scope>system</scope>
|
||||
<systemPath>${basedir}/lib/cpdetector-1.04.jar</systemPath>
|
||||
</dependency>
|
||||
<!-- url 规范化 -->
|
||||
<dependency>
|
||||
<groupId>io.mola.galimatias</groupId>
|
||||
<artifactId>galimatias</artifactId>
|
||||
<version>0.2.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
|
||||
@ -6,4 +6,4 @@ echo Starting kkFileView...
|
||||
echo Please check log file in ../log/kkFileView.log for more information
|
||||
echo You can get help in our official homesite: https://kkFileView.keking.cn
|
||||
echo If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers
|
||||
java -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=..\config\application.properties -jar kkFileView-2.2.1.jar -> ..\log\kkFileView.log
|
||||
java -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=..\config\application.properties -jar kkFileView-3.3.0.jar -> ..\log\kkFileView.log
|
||||
@ -29,4 +29,4 @@ echo "Starting kkFileView..."
|
||||
echo "Please execute ./showlog.sh to check log for more information"
|
||||
echo "You can get help in our official homesite: https://kkFileView.keking.cn"
|
||||
echo "If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers"
|
||||
nohup java -Dfile.encoding=UTF-8 -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=../config/application.properties -jar kkFileView-2.2.1.jar > ../log/kkFileView.log 2>&1 &
|
||||
nohup java -Dfile.encoding=UTF-8 -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider -Dspring.config.location=../config/application.properties -jar kkFileView-3.3.0.jar > ../log/kkFileView.log 2>&1 &
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
[#ftl]
|
||||
[#-- @implicitly included --]
|
||||
[#-- @ftlvariable name="file" type="cn.keking.model.FileAttribute" --]
|
||||
[#-- @ftlvariable name="fileName" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="fileTree" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="baseUrl" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="imgUrls" type="String" --]
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package cn.keking.config;
|
||||
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.utils.FileUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
@ -31,7 +31,7 @@ public class SchedulerCleanConfig {
|
||||
public void clean() {
|
||||
logger.info("Cache clean start");
|
||||
cacheService.cleanCache();
|
||||
FileUtils.deleteDirectory(fileDir);
|
||||
KkFileUtils.deleteDirectory(fileDir);
|
||||
logger.info("Cache clean end");
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import java.util.Map;
|
||||
* Content :文件类型,文本,office,压缩包等等
|
||||
*/
|
||||
public enum FileType {
|
||||
|
||||
picture("pictureFilePreviewImpl"),
|
||||
compress("compressFilePreviewImpl"),
|
||||
office("officeFilePreviewImpl"),
|
||||
@ -19,12 +20,13 @@ public enum FileType {
|
||||
media("mediaFilePreviewImpl"),
|
||||
markdown("markdownFilePreviewImpl"),
|
||||
xml("xmlFilePreviewImpl"),
|
||||
flv("flvFilePreviewImpl"),
|
||||
cad("cadFilePreviewImpl");
|
||||
|
||||
private static final String[] OFFICE_TYPES = {"docx", "doc", "xls", "xlsx", "ppt", "pptx"};
|
||||
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "RAW"};
|
||||
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "raw"};
|
||||
private static final String[] ARCHIVE_TYPES = {"rar", "zip", "jar", "7-zip", "tar", "gzip", "7z"};
|
||||
private static final String[] SIMTEXT_TYPES = ConfigConstants.getSimText();
|
||||
private static final String[] SSIM_TEXT_TYPES = ConfigConstants.getSimText();
|
||||
private static final String[] MEDIA_TYPES = ConfigConstants.getMedia();
|
||||
private static final Map<String, FileType> FILE_TYPE_MAPPER = new HashMap<>();
|
||||
|
||||
@ -38,7 +40,7 @@ public enum FileType {
|
||||
for (String archive : ARCHIVE_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(archive, FileType.compress);
|
||||
}
|
||||
for (String text : SIMTEXT_TYPES) {
|
||||
for (String text : SSIM_TEXT_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(text, FileType.simText);
|
||||
}
|
||||
for (String media : MEDIA_TYPES) {
|
||||
@ -48,6 +50,8 @@ public enum FileType {
|
||||
FILE_TYPE_MAPPER.put("xml", FileType.xml);
|
||||
FILE_TYPE_MAPPER.put("pdf", FileType.pdf);
|
||||
FILE_TYPE_MAPPER.put("dwg", FileType.cad);
|
||||
FILE_TYPE_MAPPER.put("flv", FileType.flv);
|
||||
|
||||
}
|
||||
|
||||
private static FileType to(String fileType){
|
||||
@ -67,7 +71,8 @@ public enum FileType {
|
||||
|
||||
public static FileType typeFromFileName(String fileName) {
|
||||
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
return FileType.to(fileType);
|
||||
String lowerCaseFileType = fileType.toLowerCase();
|
||||
return FileType.to(lowerCaseFileType);
|
||||
}
|
||||
|
||||
private final String instanceName;
|
||||
|
||||
@ -2,7 +2,7 @@ package cn.keking.service;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.utils.FileUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@ -48,7 +48,7 @@ public class CompressFileReader {
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
String archiveFileName = fileHandlerService.getFileNameFromPath(filePath);
|
||||
try {
|
||||
ZipFile zipFile = new ZipFile(filePath, FileUtils.getFileEncode(filePath));
|
||||
ZipFile zipFile = new ZipFile(filePath, KkFileUtils.getFileEncode(filePath));
|
||||
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
|
||||
// 排序
|
||||
entries = sortZipEntries(entries);
|
||||
@ -382,7 +382,7 @@ public class CompressFileReader {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FileUtils.deleteFileByPath(filePath);
|
||||
KkFileUtils.deleteFileByPath(filePath);
|
||||
}
|
||||
|
||||
private void extractZipFile(String childName, InputStream zipFile) {
|
||||
@ -439,7 +439,7 @@ public class CompressFileReader {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FileUtils.deleteFileByPath(filePath);
|
||||
KkFileUtils.deleteFileByPath(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,7 +468,7 @@ public class CompressFileReader {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FileUtils.deleteFileByPath(filePath);
|
||||
KkFileUtils.deleteFileByPath(filePath);
|
||||
}
|
||||
|
||||
private void extractRarFile(String childName, FileHeader header, Archive archive) {
|
||||
|
||||
@ -4,7 +4,7 @@ import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.utils.FileUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import com.aspose.cad.Color;
|
||||
import com.aspose.cad.fileformats.cad.CadDrawTypeMode;
|
||||
@ -263,7 +263,7 @@ public class FileHandlerService {
|
||||
if (StringUtils.hasText(fullFileName)) {
|
||||
fileName = fullFileName;
|
||||
type = FileType.typeFromFileName(fullFileName);
|
||||
suffix = FileUtils.suffixFromFileName(fullFileName);
|
||||
suffix = KkFileUtils.suffixFromFileName(fullFileName);
|
||||
} else {
|
||||
fileName = WebUtils.getFileNameFromURL(url);
|
||||
type = FileType.typeFromUrl(url);
|
||||
@ -275,7 +275,7 @@ public class FileHandlerService {
|
||||
attribute.setUrl(url);
|
||||
if (req != null) {
|
||||
String officePreviewType = req.getParameter("officePreviewType");
|
||||
String fileKey = req.getParameter("fileKey");
|
||||
String fileKey = WebUtils.getUrlParameterReg(url,"fileKey");
|
||||
if (StringUtils.hasText(officePreviewType)) {
|
||||
attribute.setOfficePreviewType(officePreviewType);
|
||||
}
|
||||
|
||||
@ -8,5 +8,18 @@ import org.springframework.ui.Model;
|
||||
* Content :
|
||||
*/
|
||||
public interface FilePreview {
|
||||
|
||||
String FLV_FILE_PREVIEW_PAGE = "flv";
|
||||
String PDF_FILE_PREVIEW_PAGE = "pdf";
|
||||
String COMPRESS_FILE_PREVIEW_PAGE = "compress";
|
||||
String MEDIA_FILE_PREVIEW_PAGE = "media";
|
||||
String PICTURE_FILE_PREVIEW_PAGE = "picture";
|
||||
String OFFICE_PICTURE_FILE_PREVIEW_PAGE = "officePicture";
|
||||
String TXT_FILE_PREVIEW_PAGE = "txt";
|
||||
String EXEL_FILE_PREVIEW_PAGE = "html";
|
||||
String XML_FILE_PREVIEW_PAGE = "xml";
|
||||
String MARKDOWN_FILE_PREVIEW_PAGE = "markdown";
|
||||
String NOT_SUPPORTED_FILE_PAGE = "fileNotSupported";
|
||||
|
||||
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);
|
||||
}
|
||||
|
||||
@ -25,9 +25,11 @@ public class CadFilePreviewImpl implements FilePreview {
|
||||
private static final String FILE_DIR = ConfigConstants.getFileDir();
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public CadFilePreviewImpl(FileHandlerService fileHandlerService) {
|
||||
public CadFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -35,7 +37,6 @@ public class CadFilePreviewImpl implements FilePreview {
|
||||
// 预览Type,参数传了就取参数的,没传取系统默认
|
||||
String officePreviewType = model.asMap().get("officePreviewType") == null ? ConfigConstants.getOfficePreviewType() : model.asMap().get("officePreviewType").toString();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
String suffix = fileAttribute.getSuffix();
|
||||
String fileName = fileAttribute.getName();
|
||||
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";
|
||||
String outFilePath = FILE_DIR + pdfName;
|
||||
@ -44,17 +45,13 @@ public class CadFilePreviewImpl implements FilePreview {
|
||||
String filePath;
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||
if (response.isFailure()) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
filePath = response.getContent();
|
||||
if (StringUtils.hasText(outFilePath)) {
|
||||
boolean convertResult = fileHandlerService.cadToPdf(filePath, outFilePath);
|
||||
if (!convertResult) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", "cad文件转换异常,请联系管理员");
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "cad文件转换异常,请联系管理员");
|
||||
}
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
@ -63,10 +60,10 @@ public class CadFilePreviewImpl implements FilePreview {
|
||||
}
|
||||
}
|
||||
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);
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE,otherFilePreview);
|
||||
}
|
||||
model.addAttribute("pdfUrl", pdfName);
|
||||
return "pdf";
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -20,10 +20,12 @@ public class CompressFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final CompressFileReader compressFileReader;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public CompressFilePreviewImpl(FileHandlerService fileHandlerService, CompressFileReader compressFileReader) {
|
||||
public CompressFilePreviewImpl(FileHandlerService fileHandlerService, CompressFileReader compressFileReader, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.compressFileReader = compressFileReader;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -35,9 +37,7 @@ public class CompressFilePreviewImpl implements FilePreview {
|
||||
if (!StringUtils.hasText(fileHandlerService.getConvertedFile(fileName)) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
if ("zip".equalsIgnoreCase(suffix) || "jar".equalsIgnoreCase(suffix) || "gzip".equalsIgnoreCase(suffix)) {
|
||||
@ -55,11 +55,9 @@ public class CompressFilePreviewImpl implements FilePreview {
|
||||
}
|
||||
if (fileTree != null && !"null".equals(fileTree)) {
|
||||
model.addAttribute("fileTree", fileTree);
|
||||
return "compress";
|
||||
return COMPRESS_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", "压缩文件类型不受支持,尝试在压缩的时候选择RAR4格式");
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "压缩文件类型不受支持,尝试在压缩的时候选择RAR4格式");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* @author : kl
|
||||
* create : 2020-12-27 2:50 下午
|
||||
* flv文件预览处理实现
|
||||
**/
|
||||
@Service
|
||||
public class FlvFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final MediaFilePreviewImpl mediaFilePreview;
|
||||
|
||||
public FlvFilePreviewImpl(MediaFilePreviewImpl mediaFilePreview) {
|
||||
this.mediaFilePreview = mediaFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
mediaFilePreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return FLV_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@ -5,8 +5,6 @@ import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import static com.sun.glass.ui.Clipboard.TEXT_TYPE;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2020/12/25
|
||||
@ -23,7 +21,7 @@ public class MarkdownFilePreviewImpl implements FilePreview {
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
model.addAttribute(TEXT_TYPE,"markdown");
|
||||
return simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
|
||||
simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
|
||||
return MARKDOWN_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,9 +19,11 @@ import org.springframework.ui.Model;
|
||||
public class MediaFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public MediaFilePreviewImpl(FileHandlerService fileHandlerService) {
|
||||
public MediaFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -29,10 +31,8 @@ public class MediaFilePreviewImpl implements FilePreview {
|
||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileAttribute.getName());
|
||||
if (!response.isSuccess()) {
|
||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
} else {
|
||||
model.addAttribute("mediaUrl", BaseUrlFilter.getBaseUrl() + fileHandlerService.getRelativePath(response.getContent()));
|
||||
}
|
||||
@ -40,11 +40,7 @@ public class MediaFilePreviewImpl implements FilePreview {
|
||||
model.addAttribute("mediaUrl", url);
|
||||
}
|
||||
model.addAttribute("mediaUrl", url);
|
||||
String suffix = fileAttribute.getSuffix();
|
||||
if ("flv".equalsIgnoreCase(suffix)) {
|
||||
return "flv";
|
||||
}
|
||||
return "media";
|
||||
return MEDIA_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -27,10 +27,12 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OfficeToPdfService officeToPdfService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, OfficeToPdfService officeToPdfService) {
|
||||
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, OfficeToPdfService officeToPdfService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.officeToPdfService = officeToPdfService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -38,8 +40,8 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
||||
// 预览Type,参数传了就取参数的,没传取系统默认
|
||||
String officePreviewType = fileAttribute.getOfficePreviewType();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
String suffix=fileAttribute.getSuffix();
|
||||
String fileName=fileAttribute.getName();
|
||||
String suffix = fileAttribute.getSuffix();
|
||||
String fileName = fileAttribute.getName();
|
||||
boolean isHtml = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx");
|
||||
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + (isHtml ? "html" : "pdf");
|
||||
String outFilePath = FILE_DIR + pdfName;
|
||||
@ -48,9 +50,7 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
||||
String filePath;
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||
if (response.isFailure()) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
filePath = response.getContent();
|
||||
if (StringUtils.hasText(outFilePath)) {
|
||||
@ -66,25 +66,23 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
||||
}
|
||||
}
|
||||
if (!isHtml && 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);
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, baseUrl, pdfName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
|
||||
}
|
||||
model.addAttribute("pdfUrl", pdfName);
|
||||
return isHtml ? "html" : "pdf";
|
||||
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) {
|
||||
static String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String baseUrl, String pdfName, String outFilePath, FileHandlerService fileHandlerService, String officePreviewTypeImage, OtherFilePreviewImpl otherFilePreview) {
|
||||
List<String> imageUrls = fileHandlerService.pdf2jpg(outFilePath, pdfName, baseUrl);
|
||||
if (imageUrls == null || imageUrls.size() < 1) {
|
||||
model.addAttribute("msg", "office转图片异常,请联系管理员");
|
||||
model.addAttribute("fileType",fileAttribute.getSuffix());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "office转图片异常,请联系管理员");
|
||||
}
|
||||
model.addAttribute("imgurls", imageUrls);
|
||||
model.addAttribute("currentUrl", imageUrls.get(0));
|
||||
if (officePreviewTypeImage.equals(officePreviewType)) {
|
||||
return "officePicture";
|
||||
return OFFICE_PICTURE_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
return "picture";
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,10 +11,41 @@ import org.springframework.ui.Model;
|
||||
*/
|
||||
@Service
|
||||
public class OtherFilePreviewImpl implements FilePreview {
|
||||
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
model.addAttribute("fileType",fileAttribute.getSuffix());
|
||||
model.addAttribute("msg", "系统还不支持该格式文件的在线预览");
|
||||
return "fileNotSupported";
|
||||
return this.notSupportedFile(model, fileAttribute, "系统还不支持该格式文件的在线预览");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, FileAttribute fileAttribute, String errMsg) {
|
||||
return this.notSupportedFile(model, fileAttribute.getSuffix(), errMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, String errMsg) {
|
||||
return this.notSupportedFile(model, "未知", errMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, String fileType, String errMsg) {
|
||||
model.addAttribute("fileType", fileType);
|
||||
model.addAttribute("msg", errMsg);
|
||||
return NOT_SUPPORTED_FILE_PAGE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -20,16 +20,17 @@ import java.util.List;
|
||||
public class PdfFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
private static final String FILE_DIR = ConfigConstants.getFileDir();
|
||||
|
||||
public PdfFilePreviewImpl(FileHandlerService fileHandlerService) {
|
||||
public PdfFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
String suffix=fileAttribute.getSuffix();
|
||||
String fileName=fileAttribute.getName();
|
||||
String fileName = fileAttribute.getName();
|
||||
String officePreviewType = fileAttribute.getOfficePreviewType();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + "pdf";
|
||||
@ -39,9 +40,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
outFilePath = response.getContent();
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
@ -51,16 +50,14 @@ public class PdfFilePreviewImpl implements FilePreview {
|
||||
}
|
||||
List<String> imageUrls = fileHandlerService.pdf2jpg(outFilePath, pdfName, baseUrl);
|
||||
if (imageUrls == null || imageUrls.size() < 1) {
|
||||
model.addAttribute("msg", "pdf转图片异常,请联系管理员");
|
||||
model.addAttribute("fileType",fileAttribute.getSuffix());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "pdf转图片异常,请联系管理员");
|
||||
}
|
||||
model.addAttribute("imgurls", imageUrls);
|
||||
model.addAttribute("currentUrl", imageUrls.get(0));
|
||||
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
|
||||
return "officePicture";
|
||||
return OFFICE_PICTURE_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
return "picture";
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
} else {
|
||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||
@ -68,9 +65,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, pdfName);
|
||||
if (response.isFailure()) {
|
||||
model.addAttribute("fileType", suffix);
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
model.addAttribute("pdfUrl", fileHandlerService.getRelativePath(response.getContent()));
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
@ -84,6 +79,6 @@ public class PdfFilePreviewImpl implements FilePreview {
|
||||
model.addAttribute("pdfUrl", url);
|
||||
}
|
||||
}
|
||||
return "pdf";
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,9 +19,11 @@ import java.util.List;
|
||||
public class PictureFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public PictureFilePreviewImpl(FileHandlerService fileHandlerService) {
|
||||
public PictureFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -37,20 +39,18 @@ public class PictureFilePreviewImpl implements FilePreview {
|
||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||
if (response.isFailure()) {
|
||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
} else {
|
||||
String file = fileHandlerService.getRelativePath(response.getContent());
|
||||
imgUrls.clear();
|
||||
imgUrls.add(file);
|
||||
model.addAttribute("imgurls", imgUrls);
|
||||
model.addAttribute("imgUrls", imgUrls);
|
||||
model.addAttribute("currentUrl", file);
|
||||
}
|
||||
} else {
|
||||
model.addAttribute("imgurls", imgUrls);
|
||||
model.addAttribute("imgUrls", imgUrls);
|
||||
model.addAttribute("currentUrl", url);
|
||||
}
|
||||
return "picture";
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,14 +4,14 @@ import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import jodd.io.FileUtil;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
@ -20,31 +20,28 @@ import java.nio.charset.StandardCharsets;
|
||||
@Service
|
||||
public class SimTextFilePreviewImpl implements FilePreview {
|
||||
|
||||
public static final String TEXT_TYPE = "textType";
|
||||
public static final String DEFAULT_TEXT_TYPE = "simText";
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public SimTextFilePreviewImpl(OtherFilePreviewImpl otherFilePreview) {
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
String fileName = fileAttribute.getName();
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
model.addAttribute("msg", response.getMsg());
|
||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
try {
|
||||
File originFile = new File(response.getContent());
|
||||
String xmlString = FileUtils.readFileToString(originFile, StandardCharsets.UTF_8);
|
||||
model.addAttribute("textData", Base64Utils.encodeToString(xmlString.getBytes()));
|
||||
String charset = KkFileUtils.getFileEncode(originFile);
|
||||
String fileData = FileUtil.readString(originFile, charset);
|
||||
model.addAttribute("textData", Base64.encodeBase64String(fileData.getBytes()));
|
||||
} catch (IOException e) {
|
||||
model.addAttribute("msg", e.getLocalizedMessage());
|
||||
model.addAttribute("fileType", fileAttribute.getSuffix());
|
||||
return "fileNotSupported";
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, e.getLocalizedMessage());
|
||||
}
|
||||
if (!model.containsAttribute(TEXT_TYPE)) {
|
||||
model.addAttribute(TEXT_TYPE, DEFAULT_TEXT_TYPE);
|
||||
}
|
||||
return "txt";
|
||||
return TXT_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,8 +5,6 @@ import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import static com.sun.glass.ui.Clipboard.TEXT_TYPE;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2020/12/25
|
||||
@ -20,10 +18,9 @@ public class XmlFilePreviewImpl implements FilePreview {
|
||||
this.simTextFilePreview = simTextFilePreview;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
model.addAttribute(TEXT_TYPE,"xml");
|
||||
return simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
|
||||
simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
|
||||
return XML_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,16 +2,20 @@ package cn.keking.utils;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
import jodd.io.FileUtil;
|
||||
import jodd.io.NetUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
|
||||
import static cn.keking.utils.KkFileUtils.isFtpUrl;
|
||||
import static cn.keking.utils.KkFileUtils.isHttpUrl;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
*/
|
||||
@ -30,42 +34,26 @@ public class DownloadUtils {
|
||||
*/
|
||||
public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
|
||||
String urlStr = fileAttribute.getUrl();
|
||||
String type = fileAttribute.getSuffix();
|
||||
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
|
||||
UUID uuid = UUID.randomUUID();
|
||||
if (null == fileName) {
|
||||
fileName = uuid + "." + type;
|
||||
} else { // 文件后缀不一致时,以type为准(针对simText【将类txt文件转为txt】)
|
||||
fileName = fileName.replace(fileName.substring(fileName.lastIndexOf(".") + 1), type);
|
||||
}
|
||||
String realPath = fileDir + fileName;
|
||||
File dirFile = new File(fileDir);
|
||||
if (!dirFile.exists() && !dirFile.mkdirs()) {
|
||||
logger.error("创建目录【{}】失败,可能是权限不够,请检查", fileDir);
|
||||
}
|
||||
String realPath = DownloadUtils.getRelFilePath(fileName, fileAttribute);
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
if (url.getProtocol() != null && (url.getProtocol().toLowerCase().startsWith("file") || url.getProtocol().toLowerCase().startsWith("http"))) {
|
||||
byte[] bytes = getBytesFromUrl(urlStr);
|
||||
OutputStream os = new FileOutputStream(realPath);
|
||||
saveBytesToOutStream(bytes, os);
|
||||
} else if (url.getProtocol() != null && "ftp".equalsIgnoreCase(url.getProtocol())) {
|
||||
URL url = WebUtils.normalizedURL(urlStr);
|
||||
if (isHttpUrl(url)) {
|
||||
File realFile = new File(realPath);
|
||||
NetUtil.downloadFile(url.toString(),realFile);
|
||||
} else if (isFtpUrl(url)) {
|
||||
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||
String ftpControlEncoding = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
|
||||
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
|
||||
} else {
|
||||
response.setCode(1);
|
||||
response.setContent(null);
|
||||
response.setMsg("url不能识别url" + urlStr);
|
||||
}
|
||||
response.setContent(realPath);
|
||||
response.setMsg(fileName);
|
||||
if (FileType.simText.equals(fileAttribute.getType())) {
|
||||
convertTextPlainFileCharsetToUtf8(realPath);
|
||||
}
|
||||
return response;
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | GalimatiasParseException e) {
|
||||
logger.error("文件下载失败,url:{}", urlStr, e);
|
||||
response.setCode(1);
|
||||
response.setContent(null);
|
||||
@ -78,82 +66,27 @@ public class DownloadUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] getBytesFromUrl(String urlStr) throws IOException {
|
||||
InputStream is = getInputStreamFromUrl(urlStr);
|
||||
if (is == null) {
|
||||
// urlStr = URLUtil.normalize(urlStr, true, true);
|
||||
is = getInputStreamFromUrl(urlStr);
|
||||
if (is == null) {
|
||||
logger.error("文件下载异常:url:{}", urlStr);
|
||||
throw new IOException("文件下载异常:url:" + urlStr);
|
||||
}
|
||||
}
|
||||
return getBytesFromStream(is);
|
||||
}
|
||||
|
||||
public static void saveBytesToOutStream(byte[] b, OutputStream os) throws IOException {
|
||||
os.write(b);
|
||||
os.close();
|
||||
}
|
||||
|
||||
private static InputStream getInputStreamFromUrl(String urlStr) {
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
URLConnection connection = url.openConnection();
|
||||
if (connection instanceof HttpURLConnection) {
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
|
||||
}
|
||||
return connection.getInputStream();
|
||||
} catch (IOException e) {
|
||||
logger.warn("连接url异常:url:{}", urlStr);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBytesFromStream(InputStream is) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = is.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
byte[] b = baos.toByteArray();
|
||||
is.close();
|
||||
baos.close();
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换文本文件编码为utf8
|
||||
* 探测源文件编码,探测到编码切不为utf8则进行转码
|
||||
* 获取真实文件绝对路径
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @param fileName 文件名
|
||||
* @return 文件路径
|
||||
*/
|
||||
private static void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
|
||||
File sourceFile = new File(filePath);
|
||||
if (sourceFile.exists() && sourceFile.isFile() && sourceFile.canRead()) {
|
||||
String encoding = FileUtils.getFileEncode(filePath);
|
||||
if (!FileUtils.DEFAULT_FILE_ENCODING.equals(encoding)) {
|
||||
// 不为utf8,进行转码
|
||||
File tmpUtf8File = new File(filePath + ".utf8");
|
||||
Writer writer = new OutputStreamWriter(new FileOutputStream(tmpUtf8File), StandardCharsets.UTF_8);
|
||||
Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile), encoding));
|
||||
char[] buf = new char[1024];
|
||||
int read;
|
||||
while ((read = reader.read(buf)) > 0) {
|
||||
writer.write(buf, 0, read);
|
||||
}
|
||||
reader.close();
|
||||
writer.close();
|
||||
// 删除源文件
|
||||
if (!sourceFile.delete()) {
|
||||
logger.error("源文件【{}】删除失败,请检查文件目录权限!", filePath);
|
||||
}
|
||||
// 重命名
|
||||
if (tmpUtf8File.renameTo(sourceFile)) {
|
||||
logger.error("临时文件【{}】重命名失败,请检查文件路径权限!", tmpUtf8File.getPath());
|
||||
}
|
||||
}
|
||||
private static String getRelFilePath(String fileName, FileAttribute fileAttribute) {
|
||||
String type = fileAttribute.getSuffix();
|
||||
if (null == fileName) {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
fileName = uuid + "." + type;
|
||||
} else { // 文件后缀不一致时,以type为准(针对simText【将类txt文件转为txt】)
|
||||
fileName = fileName.replace(fileName.substring(fileName.lastIndexOf(".") + 1), type);
|
||||
}
|
||||
String realPath = fileDir + fileName;
|
||||
File dirFile = new File(fileDir);
|
||||
if (!dirFile.exists() && !dirFile.mkdirs()) {
|
||||
logger.error("创建目录【{}】失败,可能是权限不够,请检查", fileDir);
|
||||
}
|
||||
return realPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,19 +6,39 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FileUtils {
|
||||
public class KkFileUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KkFileUtils.class);
|
||||
|
||||
public static final String DEFAULT_FILE_ENCODING = "UTF-8";
|
||||
|
||||
/**
|
||||
* 判断url是否是http资源
|
||||
*
|
||||
* @param url url
|
||||
* @return 是否http
|
||||
*/
|
||||
public static boolean isHttpUrl(URL url) {
|
||||
return url.getProtocol().toLowerCase().startsWith("file") || url.getProtocol().toLowerCase().startsWith("http");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断url是否是ftp资源
|
||||
*
|
||||
* @param url url
|
||||
* @return 是否ftp
|
||||
*/
|
||||
public static boolean isFtpUrl(URL url) {
|
||||
return "ftp".equalsIgnoreCase(url.getProtocol());
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个文件
|
||||
*
|
||||
* @param fileName
|
||||
* 要删除的文件的文件名
|
||||
* @param fileName 要删除的文件的文件名
|
||||
* @return 单个文件删除成功返回true,否则返回false
|
||||
*/
|
||||
public static boolean deleteFileByName(String fileName) {
|
||||
@ -39,17 +59,26 @@ public class FileUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件编码格式
|
||||
* 检测文件编码格式
|
||||
*
|
||||
* @param filePath 绝对路径
|
||||
* @return 编码格式
|
||||
*/
|
||||
public static String getFileEncode(String filePath) {
|
||||
File file = new File(filePath);
|
||||
return getFileEncode(new File(filePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测文件编码格式
|
||||
*
|
||||
* @param file 检测的文件
|
||||
* @return 编码格式
|
||||
*/
|
||||
public static String getFileEncode(File file) {
|
||||
CharsetPrinter cp = new CharsetPrinter();
|
||||
try {
|
||||
String encoding = cp.guessEncoding(file);
|
||||
LOGGER.info("检测到文件【{}】编码: {}", filePath, encoding);
|
||||
LOGGER.info("检测到文件【{}】编码: {}", file.getAbsolutePath(), encoding);
|
||||
return encoding;
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("文件编码获取失败,采用默认的编码格式:UTF-8", e);
|
||||
@ -59,6 +88,7 @@ public class FileUtils {
|
||||
|
||||
/**
|
||||
* 通过文件名获取文件后缀
|
||||
*
|
||||
* @param fileName 文件名称
|
||||
* @return 文件后缀
|
||||
*/
|
||||
@ -82,8 +112,7 @@ public class FileUtils {
|
||||
/**
|
||||
* 删除目录及目录下的文件
|
||||
*
|
||||
* @param dir
|
||||
* 要删除的目录的文件路径
|
||||
* @param dir 要删除的目录的文件路径
|
||||
* @return 目录删除成功返回true,否则返回false
|
||||
*/
|
||||
public static boolean deleteDirectory(String dir) {
|
||||
@ -103,13 +132,13 @@ public class FileUtils {
|
||||
for (int i = 0; i < Objects.requireNonNull(files).length; i++) {
|
||||
// 删除子文件
|
||||
if (files[i].isFile()) {
|
||||
flag = FileUtils.deleteFileByName(files[i].getAbsolutePath());
|
||||
flag = KkFileUtils.deleteFileByName(files[i].getAbsolutePath());
|
||||
if (!flag) {
|
||||
break;
|
||||
}
|
||||
} else if (files[i].isDirectory()) {
|
||||
} else if (files[i].isDirectory()) {
|
||||
// 删除子目录
|
||||
flag = FileUtils.deleteDirectory(files[i].getAbsolutePath());
|
||||
flag = KkFileUtils.deleteDirectory(files[i].getAbsolutePath());
|
||||
if (!flag) {
|
||||
break;
|
||||
}
|
||||
@ -1,5 +1,9 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -8,6 +12,16 @@ import java.util.Map;
|
||||
* create : 2020-12-27 1:30 上午
|
||||
**/
|
||||
public class WebUtils {
|
||||
|
||||
/**
|
||||
* 获取标准的URL
|
||||
* @param urlStr url
|
||||
* @return 标准的URL
|
||||
*/
|
||||
public static URL normalizedURL(String urlStr) throws GalimatiasParseException, MalformedURLException {
|
||||
return io.mola.galimatias.URL.parse(urlStr).toJavaURL();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取url中的参数
|
||||
*
|
||||
@ -81,6 +95,6 @@ public class WebUtils {
|
||||
public static String suffixFromUrl(String url) {
|
||||
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
||||
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
|
||||
return FileUtils.suffixFromFileName(fileName);
|
||||
return KkFileUtils.suffixFromFileName(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,14 +5,18 @@ import cn.keking.service.FilePreview;
|
||||
import cn.keking.service.FilePreviewFactory;
|
||||
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.service.impl.OtherFilePreviewImpl;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import com.thoughtworks.xstream.core.util.Base64JavaUtilCodec;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import fr.opensagres.xdocreport.core.io.IOUtils;
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
import jodd.io.NetUtil;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -20,73 +24,96 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.keking.service.FilePreview.PICTURE_FILE_PREVIEW_PAGE;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
*/
|
||||
@Controller
|
||||
public class OnlinePreviewController {
|
||||
|
||||
public static final String BASE64_DECODE_ERROR_MSG = "Base64解码失败,请检查你的 %s 是否采用 Base64 + urlEncode 双重编码了!";
|
||||
private final Logger logger = LoggerFactory.getLogger(OnlinePreviewController.class);
|
||||
|
||||
private final FilePreviewFactory previewFactory;
|
||||
private final CacheService cacheService;
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public OnlinePreviewController(FilePreviewFactory filePreviewFactory, FileHandlerService fileHandlerService, CacheService cacheService) {
|
||||
public OnlinePreviewController(FilePreviewFactory filePreviewFactory, FileHandlerService fileHandlerService, CacheService cacheService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.previewFactory = filePreviewFactory;
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.cacheService = cacheService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/onlinePreview")
|
||||
public String onlinePreview(String url, Model model, HttpServletRequest req) {
|
||||
String fileUrl = new String(Base64Utils.decodeFromString(url));
|
||||
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(fileUrl,req);
|
||||
String fileUrl;
|
||||
try {
|
||||
fileUrl = new String(Base64.decodeBase64(url));
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url");
|
||||
return otherFilePreview.notSupportedFile(model, errorMsg);
|
||||
}
|
||||
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(fileUrl, req);
|
||||
model.addAttribute("file", fileAttribute);
|
||||
FilePreview filePreview = previewFactory.get(fileAttribute);
|
||||
logger.info("预览文件url:{},previewType:{}", fileUrl, fileAttribute.getType());
|
||||
return filePreview.filePreviewHandle(fileUrl, model, fileAttribute);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/picturesPreview")
|
||||
public String picturesPreview(Model model, HttpServletRequest req) throws UnsupportedEncodingException {
|
||||
String urls = req.getParameter("urls");
|
||||
String currentUrl = req.getParameter("currentUrl");
|
||||
logger.info("预览文件url:{},urls:{}", currentUrl, urls);
|
||||
// 路径转码
|
||||
String decodedUrl = URLDecoder.decode(urls, "utf-8");
|
||||
String decodedCurrentUrl = URLDecoder.decode(currentUrl, "utf-8");
|
||||
public String picturesPreview(String urls, Model model, HttpServletRequest req) throws UnsupportedEncodingException {
|
||||
String fileUrls;
|
||||
try {
|
||||
fileUrls = new String(Base64.decodeBase64(urls));
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "urls");
|
||||
return otherFilePreview.notSupportedFile(model, errorMsg);
|
||||
}
|
||||
logger.info("预览文件url:{},urls:{}", fileUrls, urls);
|
||||
// 抽取文件并返回文件列表
|
||||
String[] imgs = decodedUrl.split("\\|");
|
||||
List<String> imgUrls = Arrays.asList(imgs);
|
||||
String[] images = fileUrls.split("\\|");
|
||||
List<String> imgUrls = Arrays.asList(images);
|
||||
model.addAttribute("imgUrls", imgUrls);
|
||||
model.addAttribute("currentUrl",decodedCurrentUrl);
|
||||
return "picture";
|
||||
|
||||
String currentUrl = req.getParameter("currentUrl");
|
||||
if (StringUtils.hasText(currentUrl)) {
|
||||
String decodedCurrentUrl = new String(Base64.decodeBase64(currentUrl));
|
||||
model.addAttribute("currentUrl", decodedCurrentUrl);
|
||||
} else {
|
||||
model.addAttribute("currentUrl", imgUrls.get(0));
|
||||
}
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据url获取文件内容
|
||||
* 当pdfjs读取存在跨域问题的文件时将通过此接口读取
|
||||
*
|
||||
* @param urlPath url
|
||||
* @param urlPath url
|
||||
* @param response response
|
||||
*/
|
||||
@RequestMapping(value = "/getCorsFile", method = RequestMethod.GET)
|
||||
public void getCorsFile(String urlPath, HttpServletResponse response) {
|
||||
logger.info("下载跨域pdf文件url:{}", urlPath);
|
||||
try {
|
||||
byte[] bytes = DownloadUtils.getBytesFromUrl(urlPath);
|
||||
DownloadUtils.saveBytesToOutStream(bytes, response.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
URL url = WebUtils.normalizedURL(urlPath);
|
||||
byte[] bytes = NetUtil.downloadBytes(url.toString());
|
||||
IOUtils.write(bytes, response.getOutputStream());
|
||||
} catch (IOException | GalimatiasParseException e) {
|
||||
logger.error("下载跨域pdf文件异常,url:{}", urlPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过api接口入队
|
||||
*
|
||||
* @param url 请编码后在入队
|
||||
*/
|
||||
@RequestMapping("/addTask")
|
||||
|
||||
7
server/src/main/log/README.txt
Normal file
7
server/src/main/log/README.txt
Normal file
@ -0,0 +1,7 @@
|
||||
README.txt
|
||||
log目录是用来存放kkFileView.log的,预览服务的运行情况最终都会反映到这个日志文件里,
|
||||
可以提供给开发、运维排查系统问题。如果通过kkFileView.log还无法定位问题所在,请你在寻求
|
||||
kk官方支持时,QQ群一 613025121、QQ群二 484680571。将此日志文件一并携带,并按照这个
|
||||
格式重命名日志文件 kkFileView-QQ昵称-时间日期.log。如:kkFileView-kl博主-2020-12-27.log 。
|
||||
所有收集的日志文件我们都会存档,供所有的kk用户作为排查案例使用,所以在你提供日志前,请
|
||||
先自行处理日志文件里的业务敏感内容。
|
||||
25473
server/src/main/resources/static/pdfjs/build/pdf.js
Normal file
25473
server/src/main/resources/static/pdfjs/build/pdf.js
Normal file
File diff suppressed because it is too large
Load Diff
1
server/src/main/resources/static/pdfjs/build/pdf.js.map
Normal file
1
server/src/main/resources/static/pdfjs/build/pdf.js.map
Normal file
File diff suppressed because one or more lines are too long
57878
server/src/main/resources/static/pdfjs/build/pdf.worker.js
vendored
Normal file
57878
server/src/main/resources/static/pdfjs/build/pdf.worker.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
server/src/main/resources/static/pdfjs/build/pdf.worker.js.map
vendored
Normal file
1
server/src/main/resources/static/pdfjs/build/pdf.worker.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
49
server/src/main/resources/web/commonHeader.ftl
Normal file
49
server/src/main/resources/web/commonHeader.ftl
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<script src="js/jquery-3.0.0.min.js" type="text/javascript"></script>
|
||||
<script src="js/jquery.form.min.js" type="text/javascript"></script>
|
||||
<script src="bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="js/watermark.js" type="text/javascript"></script>
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 初始化水印
|
||||
*/
|
||||
function initWaterMark() {
|
||||
let watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color: '${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@ -5,15 +5,8 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<link href="css/zTreeStyle.css" rel="stylesheet" type="text/css">
|
||||
<#include "*/commonHeader.ftl">
|
||||
<style type="text/css">
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #404040;
|
||||
}
|
||||
@ -32,10 +25,7 @@
|
||||
<div class="zTreeDemoBackground left">
|
||||
<ul id="treeDemo" class="ztree"></ul>
|
||||
</div>
|
||||
<script src="js/watermark.js" type="text/javascript"></script>
|
||||
<script type="text/javascript" src="js/jquery-3.0.0.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery.ztree.core.js"></script>
|
||||
<script type="text/javascript" src="js/base64.min.js" ></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
const data = JSON.parse('${fileTree}');
|
||||
@ -87,25 +77,7 @@
|
||||
|
||||
/*初始化水印*/
|
||||
window.onload = function() {
|
||||
var watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color:'${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
initWaterMark();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
<div class="container">
|
||||
<img src="images/sorry.jpg" />
|
||||
<span>
|
||||
该文件类型(${fileType})系统暂时不支持在线预览,<b>说明</b>:
|
||||
该文件类型(${file.suffix})系统暂时不支持在线预览,<b>说明</b>:
|
||||
<p style="color: red;">${msg}</p>
|
||||
有任何疑问,请加 <a href="https://jq.qq.com/?_wv=1027&k=5c0UAtu">官方QQ群:613025121</a> 咨询
|
||||
</span>
|
||||
|
||||
@ -3,18 +3,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>多媒体文件预览</title>
|
||||
<script src="js/flv.min.js"type="text/javascript"></script>
|
||||
<script src="js/watermark.js" type="text/javascript"></script>
|
||||
<script src="js/flv.min.js" type="text/javascript"></script>
|
||||
<#include "*/commonHeader.ftl">
|
||||
</head>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #404040;
|
||||
}
|
||||
@ -40,25 +32,7 @@
|
||||
}
|
||||
/*初始化水印*/
|
||||
window.onload = function() {
|
||||
var watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color:'${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
initWaterMark();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -4,21 +4,11 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<#include "*/commonHeader.ftl">
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="${pdfUrl}" width="100%" frameborder="0"></iframe>
|
||||
</body>
|
||||
<script src="js/watermark.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
document.getElementsByTagName('iframe')[0].height = document.documentElement.clientHeight-10;
|
||||
/**
|
||||
@ -30,25 +20,7 @@
|
||||
}
|
||||
/*初始化水印*/
|
||||
window.onload = function() {
|
||||
var watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color:'${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
initWaterMark();
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
@ -2,51 +2,49 @@
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0" />
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0"/>
|
||||
<title>kkFileView演示首页</title>
|
||||
<link rel="stylesheet" href="css/viewer.min.css" />
|
||||
<link rel="stylesheet" href="css/loading.css" />
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="bootstrap-table/bootstrap-table.min.css" />
|
||||
<link rel="stylesheet" href="gitalk/gitalk.css" />
|
||||
<link rel="stylesheet" href="css/viewer.min.css"/>
|
||||
<link rel="stylesheet" href="css/loading.css"/>
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" href="bootstrap-table/bootstrap-table.min.css"/>
|
||||
<link rel="stylesheet" href="gitalk/gitalk.css"/>
|
||||
<script type="text/javascript" src="js/jquery-3.0.0.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery.form.min.js"></script>
|
||||
<script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="bootstrap-table/bootstrap-table.min.js"></script>
|
||||
<script type="text/javascript" src="gitalk/gitalk.min.js"></script>
|
||||
<script type="text/javascript" src="js/base64.min.js" ></script>
|
||||
<script type="text/javascript" src="js/base64.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>文件预览项目接入和测试界面</h1>
|
||||
<div class="panel-group" id="accordion">
|
||||
<div class="panel-group container" id="accordion">
|
||||
<h1>文件预览项目接入和测试界面</h1>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion"
|
||||
href="#collapseOne">
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
|
||||
接入说明
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="collapseOne" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<div>
|
||||
如果你的项目需要接入文件预览项目,达到对docx、excel、ppt、jpg等文件的预览效果,那么通过在你的项目中加入下面的代码就可以
|
||||
成功实现:
|
||||
<pre style="background-color: #2f332a;color: #cccccc">
|
||||
var url = 'http://127.0.0.1:8080/file/test.txt'; //要预览文件的访问地址
|
||||
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(base64Encode(url)));
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
新增多图片同时预览功能,接口如下:
|
||||
<pre style="background-color: #2f332a;color: #cccccc">
|
||||
var fileUrl =url1+"|"+"url2";//多文件使用“|”字符隔开
|
||||
window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(base64Encode(fileUrl)));
|
||||
</pre>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div>
|
||||
如果你的项目需要接入文件预览项目,达到对docx、excel、ppt、jpg等文件的预览效果,那么通过在你的项目中加入下面的代码就可以
|
||||
成功实现:
|
||||
<pre style="background-color: #2f332a;color: #cccccc">
|
||||
var url = 'http://127.0.0.1:8080/file/test.txt'; //要预览文件的访问地址
|
||||
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(base64Encode(url)));
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
新增多图片同时预览功能,接口如下:
|
||||
<pre style="background-color: #2f332a;color: #cccccc">
|
||||
var fileUrl =url1+"|"+"url2";//多文件使用“|”字符隔开
|
||||
window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(base64Encode(fileUrl)));
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -59,86 +57,100 @@ window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(bas
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="collapseTwo" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<div style="padding: 10px">
|
||||
<form enctype="multipart/form-data" id="fileUpload">
|
||||
<input type="file" name="file" />
|
||||
<input type="button" id="btnsubmit" value=" 上 传 " />
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<table id="table" data-pagination="true"></table>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div style="padding: 10px">
|
||||
<form enctype="multipart/form-data" id="fileUpload">
|
||||
<input type="file" name="file"/>
|
||||
<input type="button" id="btnSubmit" value=" 上 传 "/>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<table id="table" data-pagination="true"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion"
|
||||
href="#collapseThree">
|
||||
更新记录
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseThree">
|
||||
发版记录
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="collapseThree" class="panel-collapse collapse in">
|
||||
<div class="panel-body">
|
||||
<div>
|
||||
2020年05月20日 :<br>
|
||||
1. 新增支持全局水印,并支持通过参数动态改变水印内容<br>
|
||||
2. 新增支持CAD文件预览<br>
|
||||
3. 新增base.url配置,支持使用nginx反向代理和使用context-path<br>
|
||||
4. 支持所有配置项支持从环境变量里读取,方便Docker镜像部署和集群中大规模使用<br>
|
||||
5. 支持配置限信任站点(只能预览来自信任点的文件源),保护预览服务不被滥用<br>
|
||||
6. 支持配置自定义缓存清理时间(cron表达式)<br>
|
||||
7. 全部能识别的纯文本直接预览,不用再转跳下载,如.md .java .py等<br>
|
||||
8. 支持配置限制转换后的PDF文件下载<br>
|
||||
9. 优化maven打包配置,解决 .sh 脚本可能出现换行符问题<br>
|
||||
10. 将前端所有CDN依赖放到本地,方便没有外网连接的用户使用<br>
|
||||
11. 首页评论服务由搜狐畅言切换到Gitalk<br>
|
||||
12. 修复url中包含特殊字符可能会引起的预览异常<br>
|
||||
13. 修复转换文件队列addTask异常<br>
|
||||
14. 修复其他已经问题<br>
|
||||
15. 官网建设:<a href="https://kkfileview.keking.cn">https://kkfileview.keking.cn</a><br>
|
||||
16. 官方Docker镜像仓库建设:<a href="https://hub.docker.com/r/keking/kkfileview">https://hub.docker.com/r/keking/kkfileview</a><br><br>
|
||||
<div class="panel-body">
|
||||
<div>
|
||||
2020年12月27日 :<br>
|
||||
2020年年终大版本更新,架构全面设计,代码全面重构,代码质量全面提升,二次开发更便捷,欢迎拉源码品鉴,提issue、pr共同建设<br>
|
||||
1. 架构模块调整,大量的代码重构,代码质量提升N个等级,欢迎品鉴<br>
|
||||
2. 增强XML文件预览效果,新增XML文档数结构预览<br>
|
||||
3. 新增markdown文件预览支持,预览支持md渲染和源文本切换支持<br>
|
||||
4. 切换底层web server为jetty,解决这个issue:<a href="https://github.com/kekingcn/kkFileView/issues/168">#issues/168</a><br>
|
||||
5. 引入cpdetector,解决文件编码识别问题<br>
|
||||
6. url采用base64+urlencode双编码,彻底解决各种奇葩文件名预览问题<br>
|
||||
7. 新增配置项office.preview.switch.disabled,控制offic文件预览切换开关<br>
|
||||
8. 优化文本类型文件预览逻辑,采用Base64传输内容,避免预览时再次请求文件内容<br>
|
||||
9. office预览图片模式禁用图片放大效果,达到图片和pdf预览效果一致的体验<br>
|
||||
10. 直接代码静态设置pdfbox兼容低版本jdk,在IDEA中运行也不会有警告提示<br>
|
||||
11. 移除guava、hutool等非必须的工具包,减少代码体积<br>
|
||||
12. Office组件加载异步化,提速应用启动速度最快到5秒内<br>
|
||||
13. 合理设置预览消费队列的线程数<br>
|
||||
14. 修复压缩包里文件再次预览失败的bug<br>
|
||||
15. 修复图片预览的bug<br><br>
|
||||
|
||||
2019年06月18日 :<br>
|
||||
1. 支持自动清理缓存及预览文件<br>
|
||||
2. 支持http/https下载流url文件预览<br>
|
||||
3. 支持FTP url文件预览<br>
|
||||
4. 加入Docker构建<br><br>
|
||||
2020年05月20日 :<br>
|
||||
1. 新增支持全局水印,并支持通过参数动态改变水印内容<br>
|
||||
2. 新增支持CAD文件预览<br>
|
||||
3. 新增base.url配置,支持使用nginx反向代理和使用context-path<br>
|
||||
4. 支持所有配置项支持从环境变量里读取,方便Docker镜像部署和集群中大规模使用<br>
|
||||
5. 支持配置限信任站点(只能预览来自信任点的文件源),保护预览服务不被滥用<br>
|
||||
6. 支持配置自定义缓存清理时间(cron表达式)<br>
|
||||
7. 全部能识别的纯文本直接预览,不用再转跳下载,如.md .java .py等<br>
|
||||
8. 支持配置限制转换后的PDF文件下载<br>
|
||||
9. 优化maven打包配置,解决 .sh 脚本可能出现换行符问题<br>
|
||||
10. 将前端所有CDN依赖放到本地,方便没有外网连接的用户使用<br>
|
||||
11. 首页评论服务由搜狐畅言切换到Gitalk<br>
|
||||
12. 修复url中包含特殊字符可能会引起的预览异常<br>
|
||||
13. 修复转换文件队列addTask异常<br>
|
||||
14. 修复其他已经问题<br>
|
||||
15. 官网建设:<a href="https://kkfileview.keking.cn">https://kkfileview.keking.cn</a><br>
|
||||
16. 官方Docker镜像仓库建设:<a href="https://hub.docker.com/r/keking/kkfileview">https://hub.docker.com/r/keking/kkfileview</a><br><br>
|
||||
|
||||
2019年04月08日 :<br>
|
||||
1. 缓存及队列实现抽象,提供JDK和REDIS两种实现(REDIS成为可选依赖)<br>
|
||||
2. 打包方式提供zip和tar.gz包,并提供一键启动脚本<br><br>
|
||||
2019年06月18日 :<br>
|
||||
1. 支持自动清理缓存及预览文件<br>
|
||||
2. 支持http/https下载流url文件预览<br>
|
||||
3. 支持FTP url文件预览<br>
|
||||
4. 加入Docker构建<br><br>
|
||||
|
||||
2018年01月19日 :<br>
|
||||
1. 大文件入队提前处理<br>
|
||||
1. 新增addTask文件转换入队接口<br>
|
||||
1. 采用redis队列,支持kkFIleView接口和异构系统入队两种方式<br><br>
|
||||
2019年04月08日 :<br>
|
||||
1. 缓存及队列实现抽象,提供JDK和REDIS两种实现(REDIS成为可选依赖)<br>
|
||||
2. 打包方式提供zip和tar.gz包,并提供一键启动脚本<br><br>
|
||||
|
||||
2018年01月15日 :<br>
|
||||
1.首页新增社会化评论框<br><br>
|
||||
2018年01月19日 :<br>
|
||||
1. 大文件入队提前处理<br>
|
||||
1. 新增addTask文件转换入队接口<br>
|
||||
1. 采用redis队列,支持kkFIleView接口和异构系统入队两种方式<br><br>
|
||||
|
||||
2018年01月12日 :<br>
|
||||
1.新增多图片同时预览<br>
|
||||
2.支持压缩包内图片轮番预览<br><br>
|
||||
2018年01月15日 :<br>
|
||||
1.首页新增社会化评论框<br><br>
|
||||
|
||||
2018年01月02日 :<br>
|
||||
1.修复txt等文本编码问题导致预览乱码<br>
|
||||
2.修复项目模块依赖引入不到的问题<br>
|
||||
3.新增spring boot profile,支持多环境配置<br>
|
||||
4.引入pdf.js预览doc等文件,支持doc标题生成pdf预览菜单,支持手机端预览<br><br>
|
||||
2018年01月12日 :<br>
|
||||
1.新增多图片同时预览<br>
|
||||
2.支持压缩包内图片轮番预览<br><br>
|
||||
|
||||
2017年12月12日:<br>
|
||||
1.项目gitee开源:<a href="https://gitee.com/kekingcn/file-online-preview" target="_blank">https://gitee.com/kekingcn/file-online-preview</a><br>
|
||||
2.项目github开源:<a href="https://github.com/kekingcn/kkFileView" target="_blank">https://github.com/kekingcn/kkFileView</a>
|
||||
</div>
|
||||
2018年01月02日 :<br>
|
||||
1.修复txt等文本编码问题导致预览乱码<br>
|
||||
2.修复项目模块依赖引入不到的问题<br>
|
||||
3.新增spring boot profile,支持多环境配置<br>
|
||||
4.引入pdf.js预览doc等文件,支持doc标题生成pdf预览菜单,支持手机端预览<br><br>
|
||||
|
||||
2017年12月12日:<br>
|
||||
1.项目gitee开源:<a href="https://gitee.com/kekingcn/file-online-preview" target="_blank">https://gitee.com/kekingcn/file-online-preview</a><br>
|
||||
2.项目github开源:<a href="https://github.com/kekingcn/kkFileView" target="_blank">https://github.com/kekingcn/kkFileView</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div id = "comments"></div>
|
||||
<div id="comments"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -172,9 +184,9 @@ window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(bas
|
||||
url: '${baseUrl}deleteFile?fileName=' + encodeURIComponent(fileName),
|
||||
success: function (data) {
|
||||
// 删除完成,刷新table
|
||||
if (1 == data.code) {
|
||||
if (1 === data.code) {
|
||||
alert(data.msg);
|
||||
} else{
|
||||
} else {
|
||||
$('#table').bootstrapTable('refresh', {});
|
||||
}
|
||||
},
|
||||
@ -183,6 +195,7 @@ window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(bas
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$('#table').bootstrapTable({
|
||||
url: 'listFiles',
|
||||
@ -193,14 +206,14 @@ window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(bas
|
||||
field: 'action',
|
||||
title: '操作'
|
||||
},]
|
||||
}).on('pre-body.bs.table', function (e,data) {
|
||||
}).on('pre-body.bs.table', function (e, data) {
|
||||
// 每个data添加一列用来操作
|
||||
$(data).each(function (index, item) {
|
||||
item.action = "<a class='btn btn-default' target='_blank' href='${baseUrl}onlinePreview?url="+ encodeURIComponent(Base64.encode('${baseUrl}' + item.fileName)) +"'>预览</a>" +
|
||||
"<a class='btn btn-default' href='javascript:void(0);' onclick='deleteFile(\""+item.fileName+"\")'>删除</a>";
|
||||
item.action = "<a class='btn btn-default' target='_blank' href='${baseUrl}onlinePreview?url=" + encodeURIComponent(Base64.encode('${baseUrl}' + item.fileName)) + "'>预览</a>" +
|
||||
"<a class='btn btn-default' href='javascript:void(0);' onclick='deleteFile(\"" + item.fileName + "\")'>删除</a>";
|
||||
});
|
||||
return data;
|
||||
}).on('post-body.bs.table', function (e,data) {
|
||||
}).on('post-body.bs.table', function (e, data) {
|
||||
return data;
|
||||
});
|
||||
|
||||
@ -210,12 +223,12 @@ window.open('http://127.0.0.1:8012/picturesPreview?urls='+encodeURIComponent(bas
|
||||
$(".loading_container").css("height", height).show();
|
||||
}
|
||||
|
||||
$("#btnsubmit").click(function () {
|
||||
$("#btnSubmit").click(function () {
|
||||
showLoadingDiv();
|
||||
$("#fileUpload").ajaxSubmit({
|
||||
success: function (data) {
|
||||
// 上传完成,刷新table
|
||||
if (1 == data.code) {
|
||||
if (1 === data.code) {
|
||||
alert(data.msg);
|
||||
} else {
|
||||
$('#table').bootstrapTable('refresh', {});
|
||||
|
||||
73
server/src/main/resources/web/markdown.ftl
Normal file
73
server/src/main/resources/web/markdown.ftl
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>markdown文本预览</title>
|
||||
<script src="js/marked.min.js" type="text/javascript"></script>
|
||||
<#include "*/commonHeader.ftl">
|
||||
</head>
|
||||
<body>
|
||||
<input hidden id="textData" value="${textData}"/>
|
||||
|
||||
<div class="container">
|
||||
<div class="panel panel-default">
|
||||
<div id="markdown_btn" class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
|
||||
${file.name}
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="text_btn" class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
|
||||
${file.name}
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="markdown"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
window.onload = function () {
|
||||
$("#markdown_btn").hide()
|
||||
initWaterMark();
|
||||
loadMarkdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载markdown
|
||||
*/
|
||||
function loadMarkdown() {
|
||||
var textData = Base64.decode($("#textData").val())
|
||||
window.textPreData = "<pre style='background-color: #FFFFFF;border:none'>" + textData + "</pre>";
|
||||
window.textMarkdownData = marked(textData);
|
||||
$("#markdown").html(window.textMarkdownData);
|
||||
}
|
||||
|
||||
|
||||
$(function () {
|
||||
$("#markdown_btn").click(function () {
|
||||
$("#markdown").html(window.textMarkdownData);
|
||||
$("#text_btn").show()
|
||||
$("#markdown_btn").hide()
|
||||
});
|
||||
|
||||
$("#text_btn").click(function () {
|
||||
$("#markdown_btn").show()
|
||||
$("#text_btn").hide();
|
||||
$("#markdown").html(window.textPreData);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -1,23 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8"/>
|
||||
<title>多媒体文件预览</title>
|
||||
<link rel="stylesheet" href="plyr/plyr.css" />
|
||||
<link rel="stylesheet" href="plyr/plyr.css"/>
|
||||
<script type="text/javascript" src="plyr/plyr.js"></script>
|
||||
<script type="text/javascript" src="js/watermark.js"></script>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
.m {
|
||||
width: 1024px;
|
||||
margin: 0 auto;
|
||||
@ -27,31 +20,13 @@
|
||||
<body>
|
||||
<div class="m">
|
||||
<video>
|
||||
<source src="${mediaUrl}" />
|
||||
<source src="${mediaUrl}"/>
|
||||
</video>
|
||||
</div>
|
||||
<script>
|
||||
plyr.setup();
|
||||
window.onload = function() {
|
||||
var watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color:'${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
window.onload = function () {
|
||||
initWaterMark();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -4,15 +4,8 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>PDF图片预览</title>
|
||||
<script src="js/lazyload.js"></script>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #404040;
|
||||
}
|
||||
@ -37,29 +30,10 @@
|
||||
<#if "false" == switchDisabled>
|
||||
<img src="images/pdf.svg" width="63" height="63" style="position: fixed; cursor: pointer; top: 40%; right: 48px; z-index: 999;" alt="使用PDF预览" title="使用PDF预览" onclick="changePreviewType('pdf')"/>
|
||||
</#if>
|
||||
<script src="js/watermark.js" type="text/javascript"></script>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
/*初始化水印*/
|
||||
var watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color:'${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
initWaterMark();
|
||||
checkImgs();
|
||||
};
|
||||
window.onscroll = throttle(checkImgs);
|
||||
|
||||
@ -2,41 +2,33 @@
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>PDF预览</title>
|
||||
<style type="text/css">
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<#include "*/commonHeader.ftl">
|
||||
</head>
|
||||
<body>
|
||||
<#if pdfUrl?contains("http://") || pdfUrl?contains("https://")>
|
||||
<#assign finalUrl="${pdfUrl}">
|
||||
<#else>
|
||||
<#assign finalUrl="${baseUrl}${pdfUrl}">
|
||||
</#if>
|
||||
<iframe src="" width="100%" frameborder="0"></iframe>
|
||||
<#if "false" == switchDisabled>
|
||||
<img src="images/jpg.svg" width="63" height="63" style="position: fixed; cursor: pointer; top: 40%; right: 48px; z-index: 999;" alt="使用图片预览" title="使用图片预览" onclick="goForImage()"/>
|
||||
</#if>
|
||||
<#if pdfUrl?contains("http://") || pdfUrl?contains("https://")>
|
||||
<#assign finalUrl="${pdfUrl}">
|
||||
<#else>
|
||||
<#assign finalUrl="${baseUrl}${pdfUrl}">
|
||||
</#if>
|
||||
<iframe src="" width="100%" frameborder="0"></iframe>
|
||||
<#if "false" == switchDisabled>
|
||||
<img src="images/jpg.svg" width="63" height="63"
|
||||
style="position: fixed; cursor: pointer; top: 40%; right: 48px; z-index: 999;" alt="使用图片预览" title="使用图片预览"
|
||||
onclick="goForImage()"/>
|
||||
</#if>
|
||||
</body>
|
||||
<script src="js/watermark.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
document.getElementsByTagName('iframe')[0].src = "${baseUrl}pdfjs/web/viewer.html?base=${baseUrl}&file="+encodeURIComponent('${finalUrl}')+"&disabledownload=${pdfDownloadDisable}";
|
||||
document.getElementsByTagName('iframe')[0].height = document.documentElement.clientHeight-10;
|
||||
document.getElementsByTagName('iframe')[0].src = "${baseUrl}pdfjs/web/viewer.html?base=${baseUrl}&file=" + encodeURIComponent('${finalUrl}') + "&disabledownload=${pdfDownloadDisable}";
|
||||
document.getElementsByTagName('iframe')[0].height = document.documentElement.clientHeight - 10;
|
||||
/**
|
||||
* 页面变化调整高度
|
||||
*/
|
||||
window.onresize = function(){
|
||||
window.onresize = function () {
|
||||
var fm = document.getElementsByTagName("iframe")[0];
|
||||
fm.height = window.document.documentElement.clientHeight-10;
|
||||
fm.height = window.document.documentElement.clientHeight - 10;
|
||||
}
|
||||
|
||||
function goForImage() {
|
||||
@ -46,29 +38,12 @@
|
||||
} else {
|
||||
url = url + "&officePreviewType=image";
|
||||
}
|
||||
window.location.href=url;
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
/*初始化水印*/
|
||||
window.onload = function() {
|
||||
var watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color:'${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
window.onload = function () {
|
||||
initWaterMark();
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
@ -4,25 +4,20 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>图片预览</title>
|
||||
<link rel="stylesheet" href="css/viewer.min.css">
|
||||
<script src="js/viewer.min.js"></script>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #404040;
|
||||
}
|
||||
#dowebok { width: 800px; margin: 0 auto; font-size: 0;}
|
||||
#dowebok li { display: inline-block;width: 50px;height: 50px; margin-left: 1%; padding-top: 1%;}
|
||||
#image { width: 800px; margin: 0 auto; font-size: 0;}
|
||||
#image li { display: inline-block;width: 50px;height: 50px; margin-left: 1%; padding-top: 1%;}
|
||||
/*#dowebok li img { width: 200%;}*/
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<ul id="dowebok">
|
||||
|
||||
<ul id="image">
|
||||
<#list imgUrls as img>
|
||||
<#if img?contains("http://") || img?contains("https://")>
|
||||
<#assign img="${img}">
|
||||
@ -32,11 +27,9 @@
|
||||
<li><img id="${img}" url="${img}" src="${img}" width="1px" height="1px"></li>
|
||||
</#list>
|
||||
</ul>
|
||||
<script src="js/jquery-3.0.0.min.js"></script>
|
||||
<script src="js/viewer.min.js"></script>
|
||||
<script src="js/watermark.js" type="text/javascript"></script>
|
||||
|
||||
<script>
|
||||
var viewer = new Viewer(document.getElementById('dowebok'), {
|
||||
var viewer = new Viewer(document.getElementById('image'), {
|
||||
url: 'src',
|
||||
navbar: false,
|
||||
button: false,
|
||||
@ -44,61 +37,10 @@
|
||||
loop : true
|
||||
});
|
||||
document.getElementById("${currentUrl}").click();
|
||||
// 修改下一页按钮的样式和位置
|
||||
$(function () {
|
||||
var outHandler = function(){
|
||||
$(this).css('background-color','rgba(0, 0, 0, 0)');
|
||||
};
|
||||
var overHandler = function(){
|
||||
$(this).css('background-color','rgba(0, 0, 0, .5)');
|
||||
};
|
||||
var next = $("li[data-action=next]");
|
||||
var prev = $("li[data-action=prev]");
|
||||
var viewerToolBar = $(".viewer-footer");
|
||||
// 覆盖按钮父类原始样式
|
||||
viewerToolBar.css("overflow", "visible");
|
||||
// 获取文档高度、宽度
|
||||
var clientHeight = window.innerHeight;
|
||||
var clientWidth = window.innerWidth;
|
||||
// 调整样式
|
||||
var styleCss = {},nextCss={},prevCss={};
|
||||
styleCss.position = "absolute";
|
||||
styleCss.top = -clientHeight;
|
||||
styleCss.width = clientWidth*0.1;
|
||||
styleCss.height = clientHeight + 52;
|
||||
// 覆盖原始样式
|
||||
styleCss.backgroundColor='rgba(0, 0, 0, 0)';
|
||||
styleCss.borderRadius='inherit';
|
||||
nextCss.right = "0";
|
||||
prevCss.left = "0";
|
||||
next.css($.extend(nextCss, styleCss));
|
||||
prev.css($.extend(prevCss, styleCss));
|
||||
next.on('mouseout',outHandler);
|
||||
next.on('mouseover',overHandler);
|
||||
prev.on('mouseout',outHandler);
|
||||
prev.on('mouseover',overHandler);
|
||||
});
|
||||
|
||||
/*初始化水印*/
|
||||
window.onload = function() {
|
||||
var watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color:'${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
initWaterMark();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -4,144 +4,49 @@
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>普通文本预览</title>
|
||||
<#include "*/commonHeader.ftl">
|
||||
</head>
|
||||
<body>
|
||||
<input hidden id="textType" value="${textType}"/>
|
||||
|
||||
<input hidden id="textData" value="${textData}"/>
|
||||
|
||||
<div class="container">
|
||||
<#if textType?? && textType == "markdown">
|
||||
<p>
|
||||
<button id="markdown_btn" type="button" class="btn btn-primary">切换markdown</button>
|
||||
<button id="text_btn" type="button" class="btn btn-primary">切换text</button>
|
||||
</p>
|
||||
<div id="markdown" style="padding: 18px;"></div>
|
||||
<#elseif textType?? && textType == "xml" >
|
||||
<div id="xml" style="padding: 18px;"></div>
|
||||
<#else>
|
||||
<div id="text"></div>
|
||||
</#if>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
|
||||
${file.name}
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<link rel="stylesheet" href="css/xmlTreeViewer.css"/>
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"/>
|
||||
|
||||
<script src="js/jquery-3.0.0.min.js" type="text/javascript"></script>
|
||||
<script src="js/jquery.form.min.js" type="text/javascript"></script>
|
||||
<script src="bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="js/watermark.js" type="text/javascript"></script>
|
||||
<script src="js/marked.min.js" type="text/javascript"></script>
|
||||
<script src="js/xmlTreeViewer.js" type="text/javascript"></script>
|
||||
<script src="js/base64.min.js" type="text/javascript"></script>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
window.onload = function () {
|
||||
$("#markdown_btn").hide()
|
||||
initWaterMark();
|
||||
fetchData();
|
||||
loadText();
|
||||
loadXmlData()
|
||||
loadMarkdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化水印
|
||||
*/
|
||||
function initWaterMark() {
|
||||
let watermarkTxt = '${watermarkTxt}';
|
||||
if (watermarkTxt !== '') {
|
||||
watermark.init({
|
||||
watermark_txt: '${watermarkTxt}',
|
||||
watermark_x: 0,
|
||||
watermark_y: 0,
|
||||
watermark_rows: 0,
|
||||
watermark_cols: 0,
|
||||
watermark_x_space: ${watermarkXSpace},
|
||||
watermark_y_space: ${watermarkYSpace},
|
||||
watermark_font: '${watermarkFont}',
|
||||
watermark_fontsize: '${watermarkFontsize}',
|
||||
watermark_color: '${watermarkColor}',
|
||||
watermark_alpha: ${watermarkAlpha},
|
||||
watermark_width: ${watermarkWidth},
|
||||
watermark_height: ${watermarkHeight},
|
||||
watermark_angle: ${watermarkAngle},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文本数据
|
||||
*/
|
||||
function fetchData() {
|
||||
window.textData = Base64.decode($("#textData").val())
|
||||
window.textPreData = "<pre>" + window.textData + "</pre>";
|
||||
}
|
||||
|
||||
/**
|
||||
*加载普通文本
|
||||
*/
|
||||
function loadText() {
|
||||
$("#text").html(window.textPreData);
|
||||
var base64data = $("#textData").val()
|
||||
var textData = Base64.decode(base64data);
|
||||
var textPreData = "<xmp style='background-color: #FFFFFF;overflow-y: scroll;border:none'>" + textData + "</xmp>";
|
||||
$("#text").append(textPreData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载markdown
|
||||
*/
|
||||
function loadMarkdown() {
|
||||
if ($("#textType").val() === "markdown") {
|
||||
window.textMarkdownData = marked(window.textData);
|
||||
$("#markdown").html(window.textMarkdownData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载xml数据
|
||||
*/
|
||||
function loadXmlData() {
|
||||
if ($("#textType").val() === "xml") {
|
||||
var xmlNode = xmlTreeViewer.parseXML(window.textData);
|
||||
var retNode = xmlTreeViewer.getXMLViewerNode(xmlNode.xml);
|
||||
$("#xml").html(retNode);
|
||||
}
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$("#markdown_btn").click(function () {
|
||||
$("#markdown").html(window.textMarkdownData);
|
||||
$("#text_btn").show()
|
||||
$("#markdown_btn").hide()
|
||||
});
|
||||
|
||||
$("#text_btn").click(function () {
|
||||
$("#markdown_btn").show()
|
||||
$("#text_btn").hide();
|
||||
$("#markdown").html(window.textPreData);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#markdown, #xml {
|
||||
height: 97%;
|
||||
max-height: 97%;
|
||||
border: 1px solid #ece7e7;
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
73
server/src/main/resources/web/xml.ftl
Normal file
73
server/src/main/resources/web/xml.ftl
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
|
||||
<title>xml文本预览</title>
|
||||
<#include "*/commonHeader.ftl">
|
||||
<link rel="stylesheet" href="css/xmlTreeViewer.css"/>
|
||||
<script src="js/xmlTreeViewer.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input hidden id="textData" value="${textData}"/>
|
||||
<div class="container">
|
||||
<div class="panel panel-default">
|
||||
<div id="xml_btn" class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
|
||||
${file.name}
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="text_btn" class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
|
||||
${file.name}
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="xml"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
window.onload = function () {
|
||||
$("#xml_btn").hide()
|
||||
initWaterMark();
|
||||
loadXmlData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载xml数据
|
||||
*/
|
||||
function loadXmlData() {
|
||||
var textData = Base64.decode($("#textData").val())
|
||||
window.textPreData = "<xmp style='background-color: #FFFFFF;overflow-y: scroll;border:none'>" + textData + "</xmp>";
|
||||
var xmlNode = xmlTreeViewer.parseXML(textData);
|
||||
window.retNode = xmlTreeViewer.getXMLViewerNode(xmlNode.xml);
|
||||
$("#xml").html(window.retNode);
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$("#xml_btn").click(function () {
|
||||
$("#xml").html(window.retNode);
|
||||
$("#text_btn").show()
|
||||
$("#xml_btn").hide()
|
||||
});
|
||||
|
||||
$("#text_btn").click(function () {
|
||||
$("#xml_btn").show()
|
||||
$("#text_btn").hide();
|
||||
$("#xml").html(window.textPreData);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user