response = new ReturnResponse<>(0, "下载成功!!!", "");
+ URL url = null;
+ try {
+ urlAddress = replacePlusMark(urlAddress);
+ urlAddress = encodeUrlParam(urlAddress);
+ // 因为tomcat不能处理'+'号,所以讲'+'号替换成'%20%'
+ urlAddress = urlAddress.replaceAll("\\+", "%20");
+ url = new URL(urlAddress);
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ 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();
+ }
+ try {
+ URLConnection connection = url.openConnection();
+ InputStream in = connection.getInputStream();
+
+ FileOutputStream os = new FileOutputStream(realPath);
+ byte[] buffer = new byte[4 * 1024];
+ int read;
+ while ((read = in.read(buffer)) > 0) {
+ os.write(buffer, 0, read);
+ }
+ os.close();
+ in.close();
+ response.setContent(realPath);
+ // 同样针对类txt文件,如果成功msg包含的是转换后的文件名
+ response.setMsg(fileName);
+
+ // txt转换文件编码为utf8
+ if("txt".equals(type)){
+ convertTextPlainFileCharsetToUtf8(realPath);
+ }
+
+ return response;
+ } catch (IOException e) {
+ e.printStackTrace();
+ response.setCode(1);
+ response.setContent(null);
+ if (e instanceof FileNotFoundException) {
+ response.setMsg("文件不存在!!!");
+ }else {
+ response.setMsg(e.getMessage());
+ }
+ return response;
+ }
+ }
+
+ /**
+ * 注:可能是原来因为前端通过encodeURI来编码的,因为通过encodeURI编码+会被转成+号(亦即没有转),
+ * 而通过encodeURIComponent则会转成%2B,这样URLDecoder是可以正确处理的,所以也就没有必要在这里替换了
+ * 转换url参数部分的空格为加号(因为在url编解码的过程中出现+转为空格的情况)
+ * @param urlAddress
+ * @return
+ */
+ private String replacePlusMark(String urlAddress) {
+ if (urlAddress.contains("?")) {
+ String nonParamStr = urlAddress.substring(0,urlAddress.indexOf("?") + 1);
+ String paramStr = urlAddress.substring(nonParamStr.length());
+ return nonParamStr + paramStr.replace(" ", "+");
+ }
+ return urlAddress;
+ }
+
+ /**
+ * 对最有一个路径进行转码
+ * @param urlAddress
+ * http://192.168.2.111:8013/demo/Handle中文.zip
+ * @return
+ */
+ private String encodeUrlParam(String urlAddress) {
+ String newUrl = "";
+ try {
+ String path = "";
+ String param = "";
+ if (urlAddress.contains("?")) {
+ path = urlAddress.substring(0, urlAddress.indexOf("?"));
+ param = urlAddress.substring(urlAddress.indexOf("?"));
+ }else {
+ path = urlAddress;
+ }
+ String lastPath = path.substring(path.lastIndexOf("/") + 1);
+ String leftPath = path.substring(0, path.lastIndexOf("/") + 1);
+ String encodeLastPath = URLEncoder.encode(lastPath, "UTF-8");
+ newUrl += leftPath + encodeLastPath;
+ if (urlAddress.contains("?")) {
+ newUrl += param;
+ }
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return newUrl;
+ }
+
+
+
+ /**
+ * 因为jodConvert2.1不支持ms2013版本的office转换,这里偷懒,尝试看改一下文件类型,让jodConvert2.1去
+ * 处理ms2013,看结果如何,如果问题很大的话只能采取其他方式,如果没有问题,暂时使用该版本来转换
+ * @param type
+ * @return
+ */
+ private String dealWithMS2013(String type) {
+ String newType = null;
+ switch (type){
+ case "docx":
+ newType = "doc";
+ break;
+ case "xlsx":
+ newType = "doc";
+ break;
+ case "pptx":
+ newType = "ppt";
+ break;
+ default:
+ newType = type;
+ break;
+ }
+ return newType;
+ }
+
+ /**
+ * 转换文本文件编码为utf8
+ * 探测源文件编码,探测到编码切不为utf8则进行转码
+ * @param filePath 文件路径
+ */
+ private static void convertTextPlainFileCharsetToUtf8(String filePath) throws IOException {
+ File sourceFile = new File(filePath);
+ if(sourceFile.exists() && sourceFile.isFile() && sourceFile.canRead()) {
+ String encoding = null;
+ try {
+ FileCharsetDetector.Observer observer = FileCharsetDetector.guessFileEncoding(sourceFile);
+ // 为准确探测到编码,不适用猜测的编码
+ encoding = observer.isFound()?observer.getEncoding():null;
+ // 为准确探测到编码,可以考虑使用GBK 大部分文件都是windows系统产生的
+ } catch (IOException e) {
+ // 编码探测失败,
+ e.printStackTrace();
+ }
+ if(encoding != null && !"UTF-8".equals(encoding)){
+ // 不为utf8,进行转码
+ File tmpUtf8File = new File(filePath+".utf8");
+ Writer writer = new OutputStreamWriter(new FileOutputStream(tmpUtf8File),"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();
+ // 删除源文件
+ sourceFile.delete();
+ // 重命名
+ tmpUtf8File.renameTo(sourceFile);
+ }
+ }
+ }
+}
diff --git a/jodconverter-web/src/main/java/cn/keking/utils/FileCharsetDetector.java b/jodconverter-web/src/main/java/cn/keking/utils/FileCharsetDetector.java
new file mode 100644
index 00000000..63bfbc6b
--- /dev/null
+++ b/jodconverter-web/src/main/java/cn/keking/utils/FileCharsetDetector.java
@@ -0,0 +1,157 @@
+package cn.keking.utils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.mozilla.intl.chardet.nsDetector;
+import org.mozilla.intl.chardet.nsICharsetDetectionObserver;
+
+/**
+ * 文本文件编码探测工具类
+ *
+ * @author HWliao
+ * @date 2017-12-24
+ */
+public class FileCharsetDetector {
+
+ /**
+ * 传入一个文件(File)对象,检查文件编码
+ *
+ * @param file File对象实例
+ * @return 文件编码,若无,则返回null
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public static Observer guessFileEncoding(File file)
+ throws FileNotFoundException, IOException {
+ return guessFileEncoding(file, new nsDetector());
+ }
+
+ /**
+ *
+ * 获取文件的编码
+ * @param file
+ * File对象实例
+ * @param languageHint
+ * 语言提示区域代码 @see #nsPSMDetector ,取值如下:
+ * 1 : Japanese
+ * 2 : Chinese
+ * 3 : Simplified Chinese
+ * 4 : Traditional Chinese
+ * 5 : Korean
+ * 6 : Dont know(default)
+ *
+ *
+ * @return 文件编码,eg:UTF-8,GBK,GB2312形式(不确定的时候,返回可能的字符编码序列);若无,则返回null
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public static Observer guessFileEncoding(File file, int languageHint)
+ throws FileNotFoundException, IOException {
+ return guessFileEncoding(file, new nsDetector(languageHint));
+ }
+
+ /**
+ * 获取文件的编码
+ *
+ * @param file
+ * @param det
+ * @return
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ private static Observer guessFileEncoding(File file, nsDetector det)
+ throws FileNotFoundException, IOException {
+ // new Observer
+ Observer observer = new Observer();
+ // set Observer
+ // The Notify() will be called when a matching charset is found.
+ det.Init(observer);
+
+ BufferedInputStream imp = new BufferedInputStream(new FileInputStream(
+ file));
+ byte[] buf = new byte[1024];
+ int len;
+ boolean done = false;
+ boolean isAscii = false;
+
+ while ((len = imp.read(buf, 0, buf.length)) != -1) {
+ // Check if the stream is only ascii.
+ isAscii = det.isAscii(buf, len);
+ if (isAscii) {
+ break;
+ }
+ // DoIt if non-ascii and not done yet.
+ done = det.DoIt(buf, len, false);
+ if (done) {
+ break;
+ }
+ }
+ imp.close();
+ det.DataEnd();
+
+ if (isAscii) {
+ observer.encoding = "ASCII";
+ observer.found = true;
+ }
+
+ if (!observer.isFound()) {
+ String[] prob = det.getProbableCharsets();
+ // // 这里将可能的字符集组合起来返回
+ // for (int i = 0; i < prob.length; i++) {
+ // if (i == 0) {
+ // encoding = prob[i];
+ // } else {
+ // encoding += "," + prob[i];
+ // }
+ // }
+ if (prob.length > 0) {
+ // 在没有发现情况下,去第一个可能的编码
+ observer.encoding = prob[0];
+ } else {
+ observer.encoding = null;
+ }
+ }
+ return observer;
+ }
+
+ /**
+ * @author liaohongwei
+ * @Description: 文件字符编码观察者, 但判断出字符编码时候调用
+ * @date 2016年6月20日 下午2:27:06
+ */
+ public static class Observer implements nsICharsetDetectionObserver {
+
+ /**
+ * @Fields encoding : 字符编码
+ */
+ private String encoding = null;
+ /**
+ * @Fields found : 是否找到字符集
+ */
+ private boolean found = false;
+
+ @Override
+ public void Notify(String charset) {
+ this.encoding = charset;
+ this.found = true;
+ }
+
+ public String getEncoding() {
+ return encoding;
+ }
+
+ public boolean isFound() {
+ return found;
+ }
+
+ @Override
+ public String toString() {
+ return "Observer [encoding=" + encoding + ", found=" + found + "]";
+ }
+ }
+
+}
diff --git a/jodconverter-web/src/main/java/cn/keking/utils/FileUtils.java b/jodconverter-web/src/main/java/cn/keking/utils/FileUtils.java
new file mode 100644
index 00000000..f7ad589b
--- /dev/null
+++ b/jodconverter-web/src/main/java/cn/keking/utils/FileUtils.java
@@ -0,0 +1,238 @@
+package cn.keking.utils;
+
+import com.google.common.collect.Lists;
+import org.redisson.api.RMapCache;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author yudian-it
+ * @date 2017/11/13
+ */
+@Component
+public class FileUtils {
+
+ final String REDIS_FILE_PREVIEW_PDF_KEY = "converted-preview-pdf-file";
+ final String REDIS_FILE_PREVIEW_IMGS_KEY = "converted-preview-imgs-file";//压缩包内图片文件集合
+ @Autowired
+ RedissonClient redissonClient;
+ @Value("${file.dir}")
+ String fileDir;
+
+ @Value("${converted.file.charset}")
+ String charset;
+
+ @Value("${simText}")
+ String[] simText;
+ /**
+ * 已转换过的文件集合(redis缓存)
+ * @return
+ */
+ public Map listConvertedFiles() {
+ RMapCache convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
+ return convertedList;
+ }
+
+ /**
+ * 已转换过的文件,根据文件名获取
+ * @return
+ */
+ public String getConvertedFile(String key) {
+ RMapCache convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_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中剥离出文件名
+ * @param url
+ * 格式如:http://keking.ufile.ucloud.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I D1NOFtAJSPT16E6imv6JWuq0k=
+ * @return
+ */
+ public String getFileNameFromURL(String url) {
+ // 因为url的参数中可能会存在/的情况,所以直接url.lastIndexOf("/")会有问题
+ // 所以先从?处将url截断,然后运用url.lastIndexOf("/")获取文件名
+ String noQueryUrl = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?"): url.length());
+ String fileName = noQueryUrl.substring(noQueryUrl.lastIndexOf("/") + 1);
+ return fileName;
+ }
+
+ /**
+ * 获取文件后缀
+ * @param fileName
+ * @return
+ */
+ public String getSuffixFromFileName(String fileName) {
+ String suffix = fileName.substring(fileName.lastIndexOf("."));
+ return suffix;
+ }
+
+ /**
+ * 从路径中获取
+ * @param path
+ * 类似这种:C:\Users\yudian-it\Downloads
+ * @return
+ */
+ public String getFileNameFromPath(String path) {
+ return path.substring(path.lastIndexOf(File.separator) + 1);
+ }
+
+ public List listPictureTypes(){
+ List list = Lists.newArrayList();
+ list.add("jpg");
+ list.add("jpeg");
+ list.add("png");
+ list.add("gif");
+ list.add("bmp");
+ return list;
+ }
+
+ public List listArchiveTypes(){
+ List list = Lists.newArrayList();
+ list.add("rar");
+ list.add("zip");
+ list.add("jar");
+ list.add("7-zip");
+ list.add("tar");
+ list.add("gzip");
+ list.add("7z");
+ return list;
+ }
+
+ public List listOfficeTypes() {
+ List list = Lists.newArrayList();
+ list.add("docx");
+ list.add("doc");
+ list.add("xls");
+ list.add("xlsx");
+ list.add("ppt");
+ list.add("pptx");
+ return list;
+ }
+
+ /**
+ * 获取相对路径
+ * @param absolutePath
+ * @return
+ */
+ public String getRelativePath(String absolutePath) {
+ return absolutePath.substring(fileDir.length());
+ }
+
+ public void addConvertedFile(String fileName, String value){
+ RMapCache convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
+ convertedList.fastPut(fileName, value);
+ }
+
+ /**
+ * 获取redis中压缩包内图片文件
+ * @param fileKey
+ * @return
+ */
+ public List getRedisImgUrls(String fileKey){
+ RMapCache 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 convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_IMGS_KEY);
+ convertedList.fastPut(fileKey,imgs);
+ }
+ /**
+ * 判断文件编码格式
+ * @param path
+ * @return
+ */
+ public String getFileEncodeUTFGBK(String path){
+ String enc = Charset.forName("GBK").name();
+ File file = new File(path);
+ InputStream in= null;
+ try {
+ in = new FileInputStream(file);
+ byte[] b = new byte[3];
+ in.read(b);
+ in.close();
+ if (b[0] == -17 && b[1] == -69 && b[2] == -65) {
+ enc = Charset.forName("UTF-8").name();
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ System.out.println("文件编码格式为:" + enc);
+ return enc;
+ }
+
+ /**
+ * 对转换后的文件进行操作(改变编码方式)
+ * @param outFilePath
+ */
+ public void doActionConvertedFile(String outFilePath) {
+ StringBuffer sb = new StringBuffer();
+ try (InputStream inputStream = new FileInputStream(outFilePath);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charset))){
+ String line;
+ while(null != (line = reader.readLine())){
+ if (line.contains("charset=gb2312")) {
+ line = line.replace("charset=gb2312", "charset=utf-8");
+ }
+ sb.append(line);
+ }
+ // 添加sheet控制头
+ sb.append("");
+ sb.append("");
+ sb.append("");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ // 重新写入文件
+ try(FileOutputStream fos = new FileOutputStream(outFilePath);
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos))){
+ writer.write(sb.toString());
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/jodconverter-web/src/main/java/cn/keking/utils/OfficeToPdf.java b/jodconverter-web/src/main/java/cn/keking/utils/OfficeToPdf.java
new file mode 100644
index 00000000..2e50026f
--- /dev/null
+++ b/jodconverter-web/src/main/java/cn/keking/utils/OfficeToPdf.java
@@ -0,0 +1,112 @@
+package cn.keking.utils;
+import org.artofsolving.jodconverter.OfficeDocumentConverter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import java.io.File;
+
+/**
+ * @author yudian-it
+ */
+@Component
+public class OfficeToPdf {
+ /**
+ * 获取OpenOffice.org 3的安装目录
+ *
+ * @return OpenOffice.org 3的安装目录
+ */
+ @Autowired
+ ConverterUtils converterUtils;
+ /**
+ * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件
+ *
+ * @param inputFilePath
+ * 源文件路径,如:"e:/test.docx"
+ * @param outputFilePath
+ * 目标文件路径,如:"e:/test_docx.pdf"
+ * @return
+ */
+ public boolean openOfficeToPDF(String inputFilePath, String outputFilePath) {
+ return office2pdf(inputFilePath, outputFilePath);
+ }
+
+
+ /**
+ * 转换文件
+ *
+ * @param inputFile
+ * @param outputFilePath_end
+ * @param inputFilePath
+ * @param outputFilePath
+ * @param converter
+ */
+ public static void converterFile(File inputFile, String outputFilePath_end,
+ String inputFilePath, String outputFilePath,
+ OfficeDocumentConverter converter) {
+ File outputFile = new File(outputFilePath_end);
+ // 假如目标路径不存在,则新建该路径
+ if (!outputFile.getParentFile().exists()) {
+ outputFile.getParentFile().mkdirs();
+ }
+ converter.convert(inputFile, outputFile);
+ }
+
+ /**
+ * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件
+ *
+ * @param inputFilePath
+ * 源文件路径,如:"e:/test.docx"
+ * @param outputFilePath
+ * 目标文件路径,如:"e:/test_docx.pdf"
+ * @return
+ */
+ public boolean office2pdf(String inputFilePath, String outputFilePath) {
+ boolean flag = false;
+ OfficeDocumentConverter converter = converterUtils.getDocumentConverter();
+ if (null != inputFilePath) {
+ File inputFile = new File(inputFilePath);
+ // 判断目标文件路径是否为空
+ if (null == outputFilePath) {
+ // 转换后的文件路径
+ String outputFilePath_end = getOutputFilePath(inputFilePath);
+ if (inputFile.exists()) {// 找不到源文件, 则返回
+ converterFile(inputFile, outputFilePath_end, inputFilePath,
+ outputFilePath, converter);
+ flag = true;
+ }
+ } else {
+ if (inputFile.exists()) {// 找不到源文件, 则返回
+ converterFile(inputFile, outputFilePath, inputFilePath,
+ outputFilePath, converter);
+ flag = true;
+ }
+ }
+// officeManager.stop();
+ } else {
+ flag = false;
+ }
+ return flag;
+ }
+
+ /**
+ * 获取输出文件
+ *
+ * @param inputFilePath
+ * @return
+ */
+ public static String getOutputFilePath(String inputFilePath) {
+ String outputFilePath = inputFilePath.replaceAll("."
+ + getPostfix(inputFilePath), ".pdf");
+ return outputFilePath;
+ }
+
+ /**
+ * 获取inputFilePath的后缀名,如:"e:/test.pptx"的后缀名为:"pptx"
+ *
+ * @param inputFilePath
+ * @return
+ */
+ public static String getPostfix(String inputFilePath) {
+ return inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1);
+ }
+
+}
diff --git a/jodconverter-web/src/main/java/cn/keking/utils/ShedulerClean.java b/jodconverter-web/src/main/java/cn/keking/utils/ShedulerClean.java
new file mode 100644
index 00000000..d345cff1
--- /dev/null
+++ b/jodconverter-web/src/main/java/cn/keking/utils/ShedulerClean.java
@@ -0,0 +1,16 @@
+package cn.keking.utils;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ShedulerClean {
+ @Value("${file.dir}")
+ String fileDir;
+
+// @Scheduled(cron = "0 0 23 * * ?") //每晚23点执行一次
+ public void clean(){
+ System.out.println("执行一次清空文件夹");
+ DeleteFileUtil.deleteDirectory(fileDir);
+ }
+}
diff --git a/jodconverter-web/src/main/java/cn/keking/utils/SimTextUtil.java b/jodconverter-web/src/main/java/cn/keking/utils/SimTextUtil.java
new file mode 100644
index 00000000..1eac8707
--- /dev/null
+++ b/jodconverter-web/src/main/java/cn/keking/utils/SimTextUtil.java
@@ -0,0 +1,24 @@
+package cn.keking.utils;
+
+import cn.keking.param.ReturnResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * 读取类文本文件
+ * @author yudian-it
+ * @date 2017/12/13
+ */
+@Component
+public class SimTextUtil {
+ @Value("${file.dir}")
+ String fileDir;
+ @Autowired
+ DownloadUtils downloadUtils;
+
+ public ReturnResponse readSimText(String url, String fileName){
+ ReturnResponse response = downloadUtils.downLoad(url, "txt", fileName);
+ return response;
+ }
+}
diff --git a/jodconverter-web/src/main/java/cn/keking/utils/ZipReader.java b/jodconverter-web/src/main/java/cn/keking/utils/ZipReader.java
new file mode 100644
index 00000000..1aba5201
--- /dev/null
+++ b/jodconverter-web/src/main/java/cn/keking/utils/ZipReader.java
@@ -0,0 +1,459 @@
+package cn.keking.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.junrar.Archive;
+import com.github.junrar.exception.RarException;
+import com.github.junrar.rarfile.FileHeader;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.text.CollationKey;
+import java.text.Collator;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * @author yudian-it
+ * @date 2017/11/27
+ */
+@Component
+public class ZipReader {
+ static Pattern pattern = Pattern.compile("^\\d+");
+
+ @Autowired
+ FileUtils fileUtils;
+ @Value("${file.dir}")
+ String fileDir;
+
+ ExecutorService executors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+
+ /**
+ * 读取压缩文件
+ * 文件压缩到统一目录fileDir下,并且命名使用压缩文件名+文件名因为文件名
+ * 可能会重复(在系统中对于同一种类型的材料压缩文件内的文件是一样的,如果文件名
+ * 重复,那么这里会被覆盖[同一个压缩文件中的不同目录中的相同文件名暂时不考虑])
+ * 注:
+ *
+ * 文件名命名中的参数的说明:
+ * 1.archiveName,为避免解压的文件中有重名的文件会彼此覆盖,所以加上了archiveName,因为在ufile中archiveName
+ * 是不会重复的。
+ * 2.level,这里层级结构的列表我是通过一个map来构造的,map的key是文件的名字,值是对应的文件,这样每次向map中
+ * 加入节点的时候都会获取父节点是否存在,存在则会获取父节点的value并将当前节点加入到父节点的childList中(这里利用
+ * 的是java语言的引用的特性)。
+ *
+ * @param filePath
+ */
+ public String readZipFile(String filePath,String fileKey) {
+ String archiveSeparator = "/";
+ Map appender = Maps.newHashMap();
+ List imgUrls=Lists.newArrayList();
+ String baseUrl= (String) RequestContextHolder.currentRequestAttributes().getAttribute("baseUrl",0);
+ String archiveFileName = fileUtils.getFileNameFromPath(filePath);
+ try {
+ ZipFile zipFile = new ZipFile(filePath, fileUtils.getFileEncodeUTFGBK(filePath));
+ Enumeration entries = zipFile.getEntries();
+ // 排序
+ entries = sortZipEntries(entries);
+ List