支持压缩包内图片轮番预览

pull/2/head
kl 2018-01-12 16:52:03 +08:00
parent 8cbb1c3bb7
commit 3e5ba7d3ba
7 changed files with 179 additions and 78 deletions

View File

@ -9,6 +9,7 @@ import org.springframework.stereotype.Component;
import java.io.*; import java.io.*;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -21,7 +22,7 @@ import java.util.Map;
public class FileUtils { public class FileUtils {
final String REDIS_FILE_PREVIEW_PDF_KEY = "converted-preview-pdf-file"; final String REDIS_FILE_PREVIEW_PDF_KEY = "converted-preview-pdf-file";
final String REDIS_FILE_PREVIEW_IMGS_KEY = "converted-preview-imgs-file";//压缩包内图片文件集合
@Autowired @Autowired
RedissonClient redissonClient; RedissonClient redissonClient;
@Value("${file.dir}") @Value("${file.dir}")
@ -30,6 +31,8 @@ public class FileUtils {
@Value("${converted.file.charset}") @Value("${converted.file.charset}")
String charset; String charset;
@Value("${simText}")
String[] simText;
/** /**
* (redis) * (redis)
* @return * @return
@ -48,6 +51,30 @@ public class FileUtils {
return convertedList.get(key); return convertedList.get(key);
} }
/**
* (.)
*
* @param url
* @return
*/
public String typeFromUrl(String url) {
String nonPramStr = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?") : url.length());
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
if (listPictureTypes().contains(fileType.toLowerCase())) {
fileType = "picture";
}
if (listArchiveTypes().contains(fileType.toLowerCase())) {
fileType = "compress";
}
if (listOfficeTypes().contains(fileType.toLowerCase())) {
fileType = "office";
}
if (Arrays.asList(simText).contains(fileType.toLowerCase())) {
fileType = "simText";
}
return fileType;
}
/** /**
* url * url
* @param url * @param url
@ -129,6 +156,25 @@ public class FileUtils {
convertedList.fastPut(fileName, value); convertedList.fastPut(fileName, value);
} }
/**
* redis
* @param fileKey
* @return
*/
public List getRedisImgUrls(String fileKey){
RMapCache<String, List> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
return convertedList.get(fileKey);
}
/**
* redis
* @param fileKey
* @param imgs
*/
public void setRedisImgUrls(String fileKey,List imgs){
RMapCache<String, List> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
convertedList.fastPut(fileKey,imgs);
}
/** /**
* *
* @param path * @param path

View File

@ -12,6 +12,7 @@ import org.apache.commons.compress.archivers.zip.ZipFile;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
@ -49,9 +50,11 @@ public class ZipReader {
* </p> * </p>
* @param filePath * @param filePath
*/ */
public String readZipFile(String filePath) { public String readZipFile(String filePath,String fileKey) {
String archiveSeparator = "/"; String archiveSeparator = "/";
Map<String, FileNode> appender = Maps.newHashMap(); Map<String, FileNode> appender = Maps.newHashMap();
List imgUrls=Lists.newArrayList();
String baseUrl= (String) RequestContextHolder.currentRequestAttributes().getAttribute("baseUrl",0);
String archiveFileName = fileUtils.getFileNameFromPath(filePath); String archiveFileName = fileUtils.getFileNameFromPath(filePath);
try { try {
ZipFile zipFile = new ZipFile(filePath, fileUtils.getFileEncodeUTFGBK(filePath)); ZipFile zipFile = new ZipFile(filePath, fileUtils.getFileEncodeUTFGBK(filePath));
@ -73,12 +76,17 @@ public class ZipReader {
} }
String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName); String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
parentName = (level-1) + "_" + parentName; parentName = (level-1) + "_" + parentName;
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory); String type=fileUtils.typeFromUrl(childName);
if (type.equalsIgnoreCase("picture")){//添加图片文件到图片列表
imgUrls.add(baseUrl+childName);
}
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory,fileKey);
addNodes(appender, parentName, node); addNodes(appender, parentName, node);
appender.put(childName, node); appender.put(childName, node);
} }
// 开启新的线程处理文件解压 // 开启新的线程处理文件解压
executors.submit(new ZipExtractorWorker(entriesToBeExtracted, zipFile, filePath)); executors.submit(new ZipExtractorWorker(entriesToBeExtracted, zipFile, filePath));
fileUtils.setRedisImgUrls(fileKey,imgUrls);
return new ObjectMapper().writeValueAsString(appender.get("")); return new ObjectMapper().writeValueAsString(appender.get(""));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -86,6 +94,8 @@ public class ZipReader {
} }
} }
/** /**
* zipEntries() * zipEntries()
* @param entries * @param entries
@ -99,8 +109,10 @@ public class ZipReader {
return Collections.enumeration(sortedEntries); return Collections.enumeration(sortedEntries);
} }
public String unRar(String filePath){ public String unRar(String filePath,String fileKey){
Map<String, FileNode> appender = Maps.newHashMap(); Map<String, FileNode> appender = Maps.newHashMap();
List imgUrls=Lists.newArrayList();
String baseUrl= (String) RequestContextHolder.currentRequestAttributes().getAttribute("baseUrl",0);
try { try {
Archive archive = new Archive(new File(filePath)); Archive archive = new Archive(new File(filePath));
List<FileHeader> headers = archive.getFileHeaders(); List<FileHeader> headers = archive.getFileHeaders();
@ -123,11 +135,16 @@ public class ZipReader {
headersToBeExtracted.add(Collections.singletonMap(childName, header)); headersToBeExtracted.add(Collections.singletonMap(childName, header));
} }
String parentName = getLast2FileName(fullName, "\\", archiveFileName); String parentName = getLast2FileName(fullName, "\\", archiveFileName);
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory); String type=fileUtils.typeFromUrl(childName);
if (type.equalsIgnoreCase("picture")){//添加图片文件到图片列表
imgUrls.add(baseUrl+childName);
}
FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory,fileKey);
addNodes(appender, parentName, node); addNodes(appender, parentName, node);
appender.put(childName, node); appender.put(childName, node);
} }
executors.submit(new RarExtractorWorker(headersToBeExtracted, archive, filePath)); executors.submit(new RarExtractorWorker(headersToBeExtracted, archive, filePath));
fileUtils.setRedisImgUrls(fileKey,imgUrls);
return new ObjectMapper().writeValueAsString(appender.get("")); return new ObjectMapper().writeValueAsString(appender.get(""));
} catch (RarException e) { } catch (RarException e) {
e.printStackTrace(); e.printStackTrace();
@ -213,9 +230,12 @@ public class ZipReader {
private String fileName; private String fileName;
private String parentFileName; private String parentFileName;
private boolean directory; private boolean directory;
private String fileKey;//用于图片预览时寻址
private List<FileNode> childList; private List<FileNode> childList;
public FileNode() {
}
public FileNode(String originName, String fileName, String parentFileName, List<FileNode> childList, boolean directory) { public FileNode(String originName, String fileName, String parentFileName, List<FileNode> childList, boolean directory) {
this.originName = originName; this.originName = originName;
this.fileName = fileName; this.fileName = fileName;
@ -223,6 +243,21 @@ public class ZipReader {
this.childList = childList; this.childList = childList;
this.directory = directory; this.directory = directory;
} }
public FileNode(String originName, String fileName, String parentFileName, List<FileNode> childList, boolean directory,String fileKey) {
this.originName = originName;
this.fileName = fileName;
this.parentFileName = parentFileName;
this.childList = childList;
this.directory = directory;
this.fileKey=fileKey;
}
public String getFileKey() {
return fileKey;
}
public void setFileKey(String fileKey) {
this.fileKey = fileKey;
}
public String getFileName() { public String getFileName() {
return fileName; return fileName;

View File

@ -1,5 +1,6 @@
package com.yudianbank.web.controller; package com.yudianbank.web.controller;
import com.google.common.collect.Lists;
import com.yudianbank.param.ReturnResponse; import com.yudianbank.param.ReturnResponse;
import com.yudianbank.utils.*; import com.yudianbank.utils.*;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@ -22,6 +23,8 @@ import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map;
/** /**
* @author yudian-it * @author yudian-it
@ -38,30 +41,36 @@ public class OnlinePreviewController {
ZipReader zipReader; ZipReader zipReader;
@Autowired @Autowired
SimTextUtil simTextUtil; SimTextUtil simTextUtil;
@Value("${simText}")
String[] simText;
@Value("${file.dir}") @Value("${file.dir}")
String fileDir; String fileDir;
/** /**
* @param url * @param url
* @param model * @param model
* @return * @return
*/ */
@RequestMapping(value = "onlinePreview",method = RequestMethod.GET) @RequestMapping(value = "onlinePreview", method = RequestMethod.GET)
public String onlinePreview(String url, Model model, HttpServletRequest req) throws UnsupportedEncodingException { public String onlinePreview(String url, Model model, HttpServletRequest req) throws UnsupportedEncodingException {
// 路径转码 // 路径转码
String decodedUrl = URLDecoder.decode(url, "utf-8"); String decodedUrl = URLDecoder.decode(url, "utf-8");
String type = typeFromUrl(url); String type = fileUtils.typeFromUrl(url);
String suffix = suffixFromUrl(url); String suffix = suffixFromUrl(url);
// 抽取文件并返回文件列表 // 抽取文件并返回文件列表
String fileName = fileUtils.getFileNameFromURL(decodedUrl); String fileName = fileUtils.getFileNameFromURL(decodedUrl);
model.addAttribute("fileType", suffix); model.addAttribute("fileType", suffix);
if (type.equalsIgnoreCase("picture")) { if (type.equalsIgnoreCase("picture")) {
model.addAttribute("imgurl", url); List imgUrls = Lists.newArrayList(url);
try{
String fileKey = req.getParameter("fileKey");
imgUrls.clear();
imgUrls.addAll(fileUtils.getRedisImgUrls(fileKey));
}catch (Exception e){
imgUrls = Lists.newArrayList(url);
}
model.addAttribute("imgurls", imgUrls);
return "picture"; return "picture";
} else if (type.equalsIgnoreCase("simText")){ } else if (type.equalsIgnoreCase("simText")) {
ReturnResponse<String> response = simTextUtil.readSimText(decodedUrl, fileName); ReturnResponse<String> response = simTextUtil.readSimText(decodedUrl, fileName);
if (0 != response.getCode()) { if (0 != response.getCode()) {
model.addAttribute("msg", response.getMsg()); model.addAttribute("msg", response.getMsg());
@ -69,10 +78,10 @@ public class OnlinePreviewController {
} }
model.addAttribute("ordinaryUrl", response.getMsg()); model.addAttribute("ordinaryUrl", response.getMsg());
return "txt"; return "txt";
} else if(type.equalsIgnoreCase("pdf")){ } else if (type.equalsIgnoreCase("pdf")) {
model.addAttribute("pdfUrl",url); model.addAttribute("pdfUrl", url);
return "pdf"; return "pdf";
} else if(type.equalsIgnoreCase("compress")){ } else if (type.equalsIgnoreCase("compress")) {
String fileTree = null; String fileTree = null;
// 判断文件名是否存在(redis缓存读取) // 判断文件名是否存在(redis缓存读取)
if (!StringUtils.hasText(fileUtils.getConvertedFile(fileName))) { if (!StringUtils.hasText(fileUtils.getConvertedFile(fileName))) {
@ -82,28 +91,25 @@ public class OnlinePreviewController {
return "fileNotSupported"; return "fileNotSupported";
} }
String filePath = response.getContent(); String filePath = response.getContent();
if ("zip".equalsIgnoreCase(suffix) if ("zip".equalsIgnoreCase(suffix) || "jar".equalsIgnoreCase(suffix) || "gzip".equalsIgnoreCase(suffix)) {
|| "jar".equalsIgnoreCase(suffix) fileTree = zipReader.readZipFile(filePath, fileName);
|| "gzip".equalsIgnoreCase(suffix)) {
fileTree = zipReader.readZipFile(filePath);
} else if ("rar".equalsIgnoreCase(suffix)) { } else if ("rar".equalsIgnoreCase(suffix)) {
fileTree = zipReader.unRar(filePath); fileTree = zipReader.unRar(filePath, fileName);
} }
fileUtils.addConvertedFile(fileName, fileTree); fileUtils.addConvertedFile(fileName, fileTree);
}else { } else {
fileTree = fileUtils.getConvertedFile(fileName); fileTree = fileUtils.getConvertedFile(fileName);
} }
System.out.println("返回文件tree》》》》》》》》》》》》》》》》》》》");
if (null != fileTree) { if (null != fileTree) {
model.addAttribute("fileTree",fileTree); model.addAttribute("fileTree", fileTree);
return "compress"; return "compress";
}else { } else {
model.addAttribute("msg", "压缩文件类型不受支持尝试在压缩的时候选择RAR4格式"); model.addAttribute("msg", "压缩文件类型不受支持尝试在压缩的时候选择RAR4格式");
return "fileNotSupported"; return "fileNotSupported";
} }
} else if ("office".equalsIgnoreCase(type)) { } else if ("office".equalsIgnoreCase(type)) {
boolean isHtml = suffix.equalsIgnoreCase("xls") boolean isHtml = suffix.equalsIgnoreCase("xls")
|| suffix.equalsIgnoreCase("xlsx"); || suffix.equalsIgnoreCase("xlsx");
String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + (isHtml ? "html" : "pdf"); String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + (isHtml ? "html" : "pdf");
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换 // 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
if (!fileUtils.listConvertedFiles().containsKey(pdfName)) { if (!fileUtils.listConvertedFiles().containsKey(pdfName)) {
@ -133,47 +139,44 @@ public class OnlinePreviewController {
} }
model.addAttribute("pdfUrl", pdfName); model.addAttribute("pdfUrl", pdfName);
return isHtml ? "html" : "pdf"; return isHtml ? "html" : "pdf";
}else { } else {
model.addAttribute("msg", "系统还不支持该格式文件的在线预览," + model.addAttribute("msg", "系统还不支持该格式文件的在线预览," +
"如有需要请按下方显示的邮箱地址联系系统维护人员"); "如有需要请按下方显示的邮箱地址联系系统维护人员");
return "fileNotSupported"; return "fileNotSupported";
} }
} }
private String suffixFromUrl(String url) { /**
String nonPramStr = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?"): url.length()); *
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1); *
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1); * @param model
return fileType; * @param req
* @return
* @throws UnsupportedEncodingException
*/
@RequestMapping(value = "picturesPreview", method = RequestMethod.GET)
public String picturesPreview(String urls, Model model, HttpServletRequest req) throws UnsupportedEncodingException {
// 路径转码
String decodedUrl = URLDecoder.decode(urls, "utf-8");
// 抽取文件并返回文件列表
String[] imgs = decodedUrl.split("|");
List imgurls = Arrays.asList(imgs);
model.addAttribute("imgurls", imgurls);
return "picture";
} }
/**
* (.) private String suffixFromUrl(String url) {
* @param url String nonPramStr = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?") : url.length());
* @return
*/
private String typeFromUrl(String url) {
String nonPramStr = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?"): url.length());
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1); String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1); String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
if (fileUtils.listPictureTypes().contains(fileType.toLowerCase())) {
fileType = "picture";
}
if (fileUtils.listArchiveTypes().contains(fileType.toLowerCase())) {
fileType = "compress";
}
if (fileUtils.listOfficeTypes().contains(fileType.toLowerCase())) {
fileType = "office";
}
if (Arrays.asList(simText).contains(fileType.toLowerCase())) {
fileType = "simText";
}
return fileType; return fileType;
} }
/** /**
* url * url
* pdfjs * pdfjs
*
* @param urlPath * @param urlPath
* @param resp * @param resp
*/ */
@ -182,21 +185,21 @@ public class OnlinePreviewController {
InputStream inputStream = null; InputStream inputStream = null;
try { try {
String strUrl = urlPath.trim(); String strUrl = urlPath.trim();
URL url=new URL(strUrl); URL url = new URL(strUrl);
//打开请求连接 //打开请求连接
URLConnection connection = url.openConnection(); URLConnection connection = url.openConnection();
HttpURLConnection httpURLConnection=(HttpURLConnection) connection; HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
httpURLConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); httpURLConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
inputStream = httpURLConnection.getInputStream(); inputStream = httpURLConnection.getInputStream();
byte[] bs = new byte[1024]; byte[] bs = new byte[1024];
int len; int len;
while(-1 != (len = inputStream.read(bs))) { while (-1 != (len = inputStream.read(bs))) {
resp.getOutputStream().write(bs, 0, len); resp.getOutputStream().write(bs, 0, len);
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
if(inputStream != null) { if (inputStream != null) {
IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(inputStream);
} }
} }

View File

@ -1,8 +0,0 @@
env_base_config = {
server_base_url:'http://127.0.0.1:8012/',
}
env_config = {
server_base_url:env_base_config.server_base_url,
server_preview_url:env_base_config.server_base_url + 'onlinePreview?url=',
server_delete_url:env_base_config.server_base_url + 'deleteFile?fileName=',
}

View File

@ -69,7 +69,7 @@
fulls += ",resizable"; // 对于不支持screen属性的浏览器可以手工进行最大化。 manually fulls += ",resizable"; // 对于不支持screen属性的浏览器可以手工进行最大化。 manually
} }
window.open("onlinePreview?url=" window.open("onlinePreview?url="
+ encodeURIComponent("${baseUrl}" + treeNode.fileName), "_blank",fulls); + encodeURIComponent("${baseUrl}" + treeNode.fileName)+"&fileKey="+treeNode.fileKey, "_blank",fulls);
} }
} }
} }

View File

@ -23,7 +23,7 @@
</a> </a>
</h4> </h4>
</div> </div>
<div id="collapseOne" class="panel-collapse collapse in"> <div id="collapseOne" class="panel-collapse collapse">
<div class="panel-body"> <div class="panel-body">
<div> <div>
如果你的项目需要接入文件预览项目达到对docx、excel、ppt、jpg等文件的预览效果那么通过在你的项目中加入下面的代码就可以 如果你的项目需要接入文件预览项目达到对docx、excel、ppt、jpg等文件的预览效果那么通过在你的项目中加入下面的代码就可以
@ -37,10 +37,19 @@
}; };
</pre> </pre>
</div> </div>
<div>
新增多图片同时预览功能,接口如下:
<pre style="background-color: #2f332a;color: #cccccc">
var fileUrl =url1+"|"+"url2";//多文件使用“|”字符隔开
var url = "http://localhost:8012/picturesPreview?urls" + encodeURIComponent(fileUrl);
var winHeight = window.document.documentElement.clientHeight-10;
$window.open(url, "_blank", "height=" + winHeight
+ ",top=80,left=80,toolbar=no, menubar=no, scrollbars=yes, resizable=yes");
</pre>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h4 class="panel-title"> <h4 class="panel-title">
@ -65,6 +74,31 @@
</div> </div>
</div> </div>
</div> </div>
<div class="panel">
<div class="panel-heading">
<h4 class="panel-title">
<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>
2018年01月12日 <br>
1.新增多图片同时预览<br>
2.支持压缩包内图片轮番预览<br><br>
2018年01月02日 <br>
1.修复txt等文本编码问题导致预览乱码<br>
2.修复项目模块依赖引入不到的问题<br>
3.新增spring boot profile支持多环境配置<br>
4.引入pdf.js预览doc等文件支持doc标题生成pdf预览菜单支持手机端预览<br>
</div>
</div>
</div>
</div>
</div> </div>
<div class="loading_container"> <div class="loading_container">

View File

@ -12,25 +12,16 @@
</style> </style>
</head> </head>
<body> <body>
<h1>如果图片质量很好,首次加载图片时间可能会有点长,请耐心等待</h1>
<ul id="dowebok"> <ul id="dowebok">
<#--<li><img id="Imgbox" src="#" width="800px" height="550px"></li>--> <#list imgurls as img>
<li><img url="${img}" src="${img}" width="800px" height="auto"></li>
<li><img id="Imgbox" src="#" width="800px" height="auto"></li> </#list>
</ul> </ul>
<script src="js/viewer.min.js"></script> <script src="js/viewer.min.js"></script>
<script> <script>
//初始化图片地址
window.onload = function () {
// document.getElementById("Imgbox").src = getParameter("imgurl");
document.getElementById("Imgbox").src =document.getElementById("url").value;
}
var viewer = new Viewer(document.getElementById('dowebok'), {url: 'src'}); var viewer = new Viewer(document.getElementById('dowebok'), {url: 'src'});
viewer.show(); viewer.show();
</script> </script>
<input name="url" value="${imgurl}" type="hidden" id="url" >
</body> </body>
</html> </html>