kl 8 лет назад
Родитель
Сommit
883830b642
54 измененных файлов с 5024 добавлено и 18 удалено
  1. 37 18
      .gitignore
  2. 172 0
      pom.xml
  3. 23 0
      src/main/java/com/yudianbank/FilePreviewApplication.java
  4. 242 0
      src/main/java/com/yudianbank/config/RedissonConfig.java
  5. 211 0
      src/main/java/com/yudianbank/extend/ControlDocumentFormatRegistry.java
  6. 28 0
      src/main/java/com/yudianbank/filters/ChinesePathFilter.java
  7. 23 0
      src/main/java/com/yudianbank/filters/FilterConfiguration.java
  8. 57 0
      src/main/java/com/yudianbank/param/ReturnResponse.java
  9. 68 0
      src/main/java/com/yudianbank/utils/ConverterUtils.java
  10. 74 0
      src/main/java/com/yudianbank/utils/DeleteFileUtil.java
  11. 151 0
      src/main/java/com/yudianbank/utils/DownloadUtils.java
  12. 192 0
      src/main/java/com/yudianbank/utils/FileUtils.java
  13. 129 0
      src/main/java/com/yudianbank/utils/OfficeToPdf.java
  14. 194 0
      src/main/java/com/yudianbank/utils/PoiExcelToHtml.java
  15. 19 0
      src/main/java/com/yudianbank/utils/ShedulerClean.java
  16. 61 0
      src/main/java/com/yudianbank/utils/WordToHtml.java
  17. 392 0
      src/main/java/com/yudianbank/utils/ZipReader.java
  18. 113 0
      src/main/java/com/yudianbank/web/controller/FileController.java
  19. 170 0
      src/main/java/com/yudianbank/web/controller/OnlinePreviewController.java
  20. 1 0
      src/main/resources/META-INF/app.properties
  21. 30 0
      src/main/resources/application.properties
  22. 18 0
      src/main/resources/logback.xml
  23. 8 0
      src/main/resources/static/config.js
  24. BIN
      src/main/resources/static/css/img/diy/1_close.png
  25. BIN
      src/main/resources/static/css/img/diy/1_open.png
  26. BIN
      src/main/resources/static/css/img/diy/2.png
  27. BIN
      src/main/resources/static/css/img/diy/3.png
  28. BIN
      src/main/resources/static/css/img/diy/4.png
  29. BIN
      src/main/resources/static/css/img/diy/5.png
  30. BIN
      src/main/resources/static/css/img/diy/6.png
  31. BIN
      src/main/resources/static/css/img/diy/7.png
  32. BIN
      src/main/resources/static/css/img/diy/8.png
  33. BIN
      src/main/resources/static/css/img/diy/9.png
  34. BIN
      src/main/resources/static/css/img/line_conn.gif
  35. BIN
      src/main/resources/static/css/img/loading.gif
  36. BIN
      src/main/resources/static/css/img/zTreeStandard.gif
  37. BIN
      src/main/resources/static/css/img/zTreeStandard.png
  38. 121 0
      src/main/resources/static/css/loading.css
  39. 8 0
      src/main/resources/static/css/viewer.min.css
  40. 97 0
      src/main/resources/static/css/zTreeStyle.css
  41. BIN
      src/main/resources/static/images/sorry.jpg
  42. 172 0
      src/main/resources/static/index.html
  43. 19 0
      src/main/resources/static/js/excel.header.js
  44. 1 0
      src/main/resources/static/js/jquery-3.0.0.min.js
  45. 1935 0
      src/main/resources/static/js/jquery.ztree.core.js
  46. 9 0
      src/main/resources/static/js/viewer.min.js
  47. 95 0
      src/main/resources/web/compress.ftl
  48. 9 0
      src/main/resources/web/doc.ftl
  49. 11 0
      src/main/resources/web/docxConvert.ftl
  50. 41 0
      src/main/resources/web/fileNotSupported.ftl
  51. 26 0
      src/main/resources/web/pdf.ftl
  52. 33 0
      src/main/resources/web/picture.ftl
  53. 18 0
      src/main/resources/web/txt.ftl
  54. 16 0
      src/test/java/com/yudianbank/FilePreviewApplicationTests.java

+ 37 - 18
.gitignore

@@ -1,22 +1,41 @@
-# Compiled class file
-*.class
+target/
+!.mvn/wrapper/maven-wrapper.jar
 
-# Log file
-*.log
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
 
-# BlueJ files
-*.ctxt
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
 
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+/*.iml
 
-# Package Files #
-*.jar
-*.war
-*.ear
-*.zip
-*.tar.gz
-*.rar
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
+**/target/
+.classpath
+.project
+**/.settings
+**/bin/
+**/build/
+**/.externalToolBuilders/
+*.iml
+**/.idea/
+**/disconf
+**/rpc.properties
+/producer/tmp
+/.temfile
+.temfile
+convertedFile/

+ 172 - 0
pom.xml

@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>com.yudianbank</groupId>
+	<artifactId>filepreview</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<packaging>jar</packaging>
+
+	<name>file-online-preview</name>
+	<description>Demo project for Spring Boot</description>
+
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>1.5.8.RELEASE</version>
+		<relativePath/> <!-- lookup parent from repository -->
+	</parent>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+		<java.version>1.8</java.version>
+		<ufile.sdk.verison>1.0-SNAPSHOT</ufile.sdk.verison>
+		<logging.path>${basedir}/target/classes/logs</logging.path>
+		<appName>file-preview</appName>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-freemarker</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<!--apollo client-->
+		<dependency>
+			<groupId>com.ctrip.framework.apollo</groupId>
+			<artifactId>apollo-client</artifactId>
+			<version>0.8.0</version>
+		</dependency>
+		<dependency>
+			<groupId>net.logstash.logback</groupId>
+			<artifactId>logstash-logback-encoder</artifactId>
+			<version>4.11</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<!-- REDISSON -->
+		<dependency>
+			<groupId>org.redisson</groupId>
+			<artifactId>redisson</artifactId>
+			<version>3.2.0</version>
+		</dependency>
+		<dependency>
+			<groupId> org.apache.poi</groupId>
+			<artifactId> poi </artifactId>
+			<version>3.12</version>
+		</dependency>
+		<dependency >
+			<groupId> org.apache.poi</groupId>
+			<artifactId>poi-scratchpad</artifactId>
+			<version > 3.12 </version>
+		</dependency>
+		<dependency>
+			<groupId>fr.opensagres.xdocreport</groupId>
+			<artifactId>org.apache.poi.xwpf.converter.core</artifactId>
+			<version>1.0.5</version>
+			<exclusions>
+				<exclusion>
+					<artifactId>poi</artifactId>
+					<groupId>org.apache.poi</groupId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>fr.opensagres.xdocreport</groupId>
+			<artifactId>org.apache.poi.xwpf.converter.xhtml</artifactId>
+			<version>1.0.5</version>
+		</dependency>
+		<dependency>
+			<groupId>fr.opensagres.xdocreport</groupId>
+			<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>
+            <artifactId>commons-compress</artifactId>
+            <version>1.9</version>
+        </dependency>
+		<!-- 解压(rar)-->
+        <dependency>
+            <groupId>com.github.junrar</groupId>
+            <artifactId>junrar</artifactId>
+            <version>0.7</version>
+        </dependency>
+		<dependency>
+			<groupId>net.sourceforge.jchardet</groupId>
+			<artifactId>jchardet</artifactId>
+			<version>1.0</version>
+		</dependency>
+		<dependency>
+			<groupId>antlr</groupId>
+			<artifactId>antlr</artifactId>
+			<version>2.7.7</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-httpclient</groupId>
+			<artifactId>commons-httpclient</artifactId>
+			<version>3.1</version>
+			<scope>test</scope>
+			<exclusions>
+				<exclusion>
+					<artifactId>commons-logging</artifactId>
+					<groupId>commons-logging</groupId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>org.artofsolving.jodconverter</groupId>
+			<artifactId>jodconverter-core</artifactId>
+			<version>3.0-SNAPSHOT</version>
+			<exclusions>
+				<exclusion>
+					<artifactId>commons-io</artifactId>
+					<groupId>commons-io</groupId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>commons-cli</groupId>
+			<artifactId>commons-cli</artifactId>
+			<version>1.2</version>
+		</dependency>
+		<dependency>
+			<groupId>com.thoughtworks.xstream</groupId>
+			<artifactId>xstream</artifactId>
+			<version>1.3.1</version>
+		</dependency>
+	</dependencies>
+	<build>
+		<resources>
+			<resource>
+				<directory>${basedir}/src/main/resources</directory>
+				<includes>
+					<include>**/*</include>
+				</includes>
+				<filtering>true</filtering>
+			</resource>
+		</resources>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+		</plugins>
+	</build>
+
+
+</project>

+ 23 - 0
src/main/java/com/yudianbank/FilePreviewApplication.java

@@ -0,0 +1,23 @@
+package com.yudianbank;
+
+import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+import java.util.Enumeration;
+import java.util.Properties;
+
+@SpringBootApplication
+@EnableScheduling
+@ComponentScan(value = "com.yudianbank.*")
+//@EnableApolloConfig
+public class FilePreviewApplication {
+	public static void main(String[] args) {
+        Properties properties = System.getProperties();
+        System.out.println(properties.get("user.dir"));
+        SpringApplication.run(FilePreviewApplication.class, args);
+	}
+}

+ 242 - 0
src/main/java/com/yudianbank/config/RedissonConfig.java

@@ -0,0 +1,242 @@
+package com.yudianbank.config;
+
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.client.codec.Codec;
+import org.redisson.config.Config;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Created by kl on 2017/09/26.
+ * redisson 客户端配置
+ */
+@ConfigurationProperties(prefix = "spring.redisson")
+@Configuration
+public class RedissonConfig {
+
+    private String address;
+    private int connectionMinimumIdleSize = 10;
+    private int idleConnectionTimeout=10000;
+    private int pingTimeout=1000;
+    private int connectTimeout=10000;
+    private int timeout=3000;
+    private int retryAttempts=3;
+    private int retryInterval=1500;
+    private int reconnectionTimeout=3000;
+    private int failedAttempts=3;
+    private String password = null;
+    private int subscriptionsPerConnection=5;
+    private String clientName=null;
+    private int subscriptionConnectionMinimumIdleSize = 1;
+    private int subscriptionConnectionPoolSize = 50;
+    private int connectionPoolSize = 64;
+    private int database = 0;
+    private boolean dnsMonitoring = false;
+    private int dnsMonitoringInterval = 5000;
+
+    private int thread; //当前处理核数量 * 2
+
+    private String codec="org.redisson.codec.JsonJacksonCodec";
+
+    @Bean(destroyMethod = "shutdown")
+    RedissonClient redisson() throws Exception {
+        Config config = new Config();
+        config.useSingleServer().setAddress(address)
+                .setConnectionMinimumIdleSize(connectionMinimumIdleSize)
+                .setConnectionPoolSize(connectionPoolSize)
+                .setDatabase(database)
+                .setDnsMonitoring(dnsMonitoring)
+                .setDnsMonitoringInterval(dnsMonitoringInterval)
+                .setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize)
+                .setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize)
+                .setSubscriptionsPerConnection(subscriptionsPerConnection)
+                .setClientName(clientName)
+                .setFailedAttempts(failedAttempts)
+                .setRetryAttempts(retryAttempts)
+                .setRetryInterval(retryInterval)
+                .setReconnectionTimeout(reconnectionTimeout)
+                .setTimeout(timeout)
+                .setConnectTimeout(connectTimeout)
+                .setIdleConnectionTimeout(idleConnectionTimeout)
+                .setPingTimeout(pingTimeout)
+                .setPassword(password);
+        Codec codec=(Codec) ClassUtils.forName(getCodec(), ClassUtils.getDefaultClassLoader()).newInstance();
+        config.setCodec(codec);
+        config.setThreads(thread);
+        config.setEventLoopGroup(new NioEventLoopGroup());
+        config.setUseLinuxNativeEpoll(false);
+        return Redisson.create(config);
+    }
+
+    public int getThread() {
+        return thread;
+    }
+
+    public void setThread(int thread) {
+        this.thread = thread;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public int getIdleConnectionTimeout() {
+        return idleConnectionTimeout;
+    }
+
+    public void setIdleConnectionTimeout(int idleConnectionTimeout) {
+        this.idleConnectionTimeout = idleConnectionTimeout;
+    }
+
+    public int getPingTimeout() {
+        return pingTimeout;
+    }
+
+    public void setPingTimeout(int pingTimeout) {
+        this.pingTimeout = pingTimeout;
+    }
+
+    public int getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    public void setConnectTimeout(int connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    public int getRetryAttempts() {
+        return retryAttempts;
+    }
+
+    public void setRetryAttempts(int retryAttempts) {
+        this.retryAttempts = retryAttempts;
+    }
+
+    public int getRetryInterval() {
+        return retryInterval;
+    }
+
+    public void setRetryInterval(int retryInterval) {
+        this.retryInterval = retryInterval;
+    }
+
+    public int getReconnectionTimeout() {
+        return reconnectionTimeout;
+    }
+
+    public void setReconnectionTimeout(int reconnectionTimeout) {
+        this.reconnectionTimeout = reconnectionTimeout;
+    }
+
+    public int getFailedAttempts() {
+        return failedAttempts;
+    }
+
+    public void setFailedAttempts(int failedAttempts) {
+        this.failedAttempts = failedAttempts;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public int getSubscriptionsPerConnection() {
+        return subscriptionsPerConnection;
+    }
+
+    public void setSubscriptionsPerConnection(int subscriptionsPerConnection) {
+        this.subscriptionsPerConnection = subscriptionsPerConnection;
+    }
+
+    public String getClientName() {
+        return clientName;
+    }
+
+    public void setClientName(String clientName) {
+        this.clientName = clientName;
+    }
+
+    public int getSubscriptionConnectionMinimumIdleSize() {
+        return subscriptionConnectionMinimumIdleSize;
+    }
+
+    public void setSubscriptionConnectionMinimumIdleSize(int subscriptionConnectionMinimumIdleSize) {
+        this.subscriptionConnectionMinimumIdleSize = subscriptionConnectionMinimumIdleSize;
+    }
+
+    public int getSubscriptionConnectionPoolSize() {
+        return subscriptionConnectionPoolSize;
+    }
+
+    public void setSubscriptionConnectionPoolSize(int subscriptionConnectionPoolSize) {
+        this.subscriptionConnectionPoolSize = subscriptionConnectionPoolSize;
+    }
+
+    public int getConnectionMinimumIdleSize() {
+        return connectionMinimumIdleSize;
+    }
+
+    public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) {
+        this.connectionMinimumIdleSize = connectionMinimumIdleSize;
+    }
+
+    public int getConnectionPoolSize() {
+        return connectionPoolSize;
+    }
+
+    public void setConnectionPoolSize(int connectionPoolSize) {
+        this.connectionPoolSize = connectionPoolSize;
+    }
+
+    public int getDatabase() {
+        return database;
+    }
+
+    public void setDatabase(int database) {
+        this.database = database;
+    }
+
+    public boolean isDnsMonitoring() {
+        return dnsMonitoring;
+    }
+
+    public void setDnsMonitoring(boolean dnsMonitoring) {
+        this.dnsMonitoring = dnsMonitoring;
+    }
+
+    public int getDnsMonitoringInterval() {
+        return dnsMonitoringInterval;
+    }
+
+    public void setDnsMonitoringInterval(int dnsMonitoringInterval) {
+        this.dnsMonitoringInterval = dnsMonitoringInterval;
+    }
+
+    public String getCodec() {
+        return codec;
+    }
+
+    public void setCodec(String codec) {
+        this.codec = codec;
+    }
+}

+ 211 - 0
src/main/java/com/yudianbank/extend/ControlDocumentFormatRegistry.java

@@ -0,0 +1,211 @@
+package com.yudianbank.extend;
+
+import com.google.common.collect.Maps;
+import com.sun.star.beans.PropertyValue;
+import org.artofsolving.jodconverter.document.DocumentFamily;
+import org.artofsolving.jodconverter.document.DocumentFormat;
+import org.artofsolving.jodconverter.document.SimpleDocumentFormatRegistry;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 重写了DefaultDocumentFormatRegistry类,因为要添加自定义行为,比如字符编码。。。
+ * @author yudian-it
+ * @date 2017/12/5
+ */
+public class ControlDocumentFormatRegistry extends SimpleDocumentFormatRegistry {
+
+    public ControlDocumentFormatRegistry() {
+        DocumentFormat pdf = new DocumentFormat("Portable Document Format", "pdf", "application/pdf");
+        pdf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer_pdf_Export"));
+        pdf.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc_pdf_Export"));
+        pdf.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_pdf_Export"));
+        pdf.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_pdf_Export"));
+        addFormat(pdf);
+
+        DocumentFormat swf = new DocumentFormat("Macromedia Flash", "swf", "application/x-shockwave-flash");
+        swf.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_flash_Export"));
+        swf.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_flash_Export"));
+        addFormat(swf);
+
+        // disabled because it's not always available
+        //DocumentFormat xhtml = new DocumentFormat("XHTML", "xhtml", "application/xhtml+xml");
+        //xhtml.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "XHTML Writer File"));
+        //xhtml.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "XHTML Calc File"));
+        //xhtml.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "XHTML Impress File"));
+        //addFormat(xhtml);
+
+        DocumentFormat html = new DocumentFormat("HTML", "html", "text/html");
+        // HTML is treated as Text when supplied as input, but as an output it is also
+        // available for exporting Spreadsheet and Presentation formats
+        html.setInputFamily(DocumentFamily.TEXT);
+        html.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "HTML (StarWriter)"));
+        Map<String,Object> htmlLoadAndStoreProperties = new LinkedHashMap<String,Object>();
+        htmlLoadAndStoreProperties.put("FilterName", "HTML (StarCalc)");
+        htmlLoadAndStoreProperties.put("FilterOptions", "utf8");
+        html.setStoreProperties(DocumentFamily.SPREADSHEET, htmlLoadAndStoreProperties);
+        html.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_html_Export"));
+        addFormat(html);
+
+        DocumentFormat odt = new DocumentFormat("OpenDocument Text", "odt", "application/vnd.oasis.opendocument.text");
+        odt.setInputFamily(DocumentFamily.TEXT);
+        odt.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer8"));
+        addFormat(odt);
+
+        DocumentFormat sxw = new DocumentFormat("OpenOffice.org 1.0 Text Document", "sxw", "application/vnd.sun.xml.writer");
+        sxw.setInputFamily(DocumentFamily.TEXT);
+        sxw.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "StarOffice XML (Writer)"));
+        addFormat(sxw);
+
+        DocumentFormat doc = new DocumentFormat("Microsoft Word", "doc", "application/msword");
+        doc.setInputFamily(DocumentFamily.TEXT);
+        doc.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "MS Word 97"));
+        addFormat(doc);
+
+        DocumentFormat docx = new DocumentFormat("Microsoft Word 2007 XML", "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+        docx.setInputFamily(DocumentFamily.TEXT);
+        addFormat(docx);
+
+        DocumentFormat rtf = new DocumentFormat("Rich Text Format", "rtf", "text/rtf");
+        rtf.setInputFamily(DocumentFamily.TEXT);
+        rtf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "Rich Text Format"));
+        addFormat(rtf);
+
+        DocumentFormat wpd = new DocumentFormat("WordPerfect", "wpd", "application/wordperfect");
+        wpd.setInputFamily(DocumentFamily.TEXT);
+        addFormat(wpd);
+
+        DocumentFormat txt = new DocumentFormat("Plain Text", "txt", "text/plain");
+        txt.setInputFamily(DocumentFamily.TEXT);
+        Map<String,Object> txtLoadAndStoreProperties = new LinkedHashMap<String,Object>();
+        txtLoadAndStoreProperties.put("FilterName", "Text (encoded)");
+        txtLoadAndStoreProperties.put("FilterOptions", "utf8");
+        txt.setLoadProperties(txtLoadAndStoreProperties);
+        txt.setStoreProperties(DocumentFamily.TEXT, txtLoadAndStoreProperties);
+        addFormat(txt);
+
+        DocumentFormat wikitext = new DocumentFormat("MediaWiki wikitext", "wiki", "text/x-wiki");
+        wikitext.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "MediaWiki"));
+        //addFormat(wikitext);
+
+        DocumentFormat ods = new DocumentFormat("OpenDocument Spreadsheet", "ods", "application/vnd.oasis.opendocument.spreadsheet");
+        ods.setInputFamily(DocumentFamily.SPREADSHEET);
+        ods.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc8"));
+        addFormat(ods);
+
+        DocumentFormat sxc = new DocumentFormat("OpenOffice.org 1.0 Spreadsheet", "sxc", "application/vnd.sun.xml.calc");
+        sxc.setInputFamily(DocumentFamily.SPREADSHEET);
+        sxc.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "StarOffice XML (Calc)"));
+        addFormat(sxc);
+
+        DocumentFormat xls = new DocumentFormat("Microsoft Excel", "xls", "application/vnd.ms-excel");
+        xls.setInputFamily(DocumentFamily.SPREADSHEET);
+        xls.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "MS Excel 97"));
+        addFormat(xls);
+
+        DocumentFormat xlsx = new DocumentFormat("Microsoft Excel 2007 XML", "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        xlsx.setInputFamily(DocumentFamily.SPREADSHEET);
+        addFormat(xlsx);
+
+        DocumentFormat csv = new DocumentFormat("Comma Separated Values", "csv", "text/csv");
+        csv.setInputFamily(DocumentFamily.SPREADSHEET);
+        Map<String,Object> csvLoadAndStoreProperties = new LinkedHashMap<String,Object>();
+        csvLoadAndStoreProperties.put("FilterName", "Text - txt - csv (StarCalc)");
+        csvLoadAndStoreProperties.put("FilterOptions", "44,34,0");  // Field Separator: ','; Text Delimiter: '"'
+        csv.setLoadProperties(csvLoadAndStoreProperties);
+        csv.setStoreProperties(DocumentFamily.SPREADSHEET, csvLoadAndStoreProperties);
+        addFormat(csv);
+
+        DocumentFormat tsv = new DocumentFormat("Tab Separated Values", "tsv", "text/tab-separated-values");
+        tsv.setInputFamily(DocumentFamily.SPREADSHEET);
+        Map<String,Object> tsvLoadAndStoreProperties = new LinkedHashMap<String,Object>();
+        tsvLoadAndStoreProperties.put("FilterName", "Text - txt - csv (StarCalc)");
+        tsvLoadAndStoreProperties.put("FilterOptions", "9,34,0");  // Field Separator: '\t'; Text Delimiter: '"'
+        tsv.setLoadProperties(tsvLoadAndStoreProperties);
+        tsv.setStoreProperties(DocumentFamily.SPREADSHEET, tsvLoadAndStoreProperties);
+        addFormat(tsv);
+
+        DocumentFormat odp = new DocumentFormat("OpenDocument Presentation", "odp", "application/vnd.oasis.opendocument.presentation");
+        odp.setInputFamily(DocumentFamily.PRESENTATION);
+        odp.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress8"));
+        addFormat(odp);
+
+        DocumentFormat sxi = new DocumentFormat("OpenOffice.org 1.0 Presentation", "sxi", "application/vnd.sun.xml.impress");
+        sxi.setInputFamily(DocumentFamily.PRESENTATION);
+        sxi.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "StarOffice XML (Impress)"));
+        addFormat(sxi);
+
+        DocumentFormat ppt = new DocumentFormat("Microsoft PowerPoint", "ppt", "application/vnd.ms-powerpoint");
+        ppt.setInputFamily(DocumentFamily.PRESENTATION);
+        ppt.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "MS PowerPoint 97"));
+        addFormat(ppt);
+
+        DocumentFormat pptx = new DocumentFormat("Microsoft PowerPoint 2007 XML", "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
+        pptx.setInputFamily(DocumentFamily.PRESENTATION);
+        addFormat(pptx);
+
+        DocumentFormat odg = new DocumentFormat("OpenDocument Drawing", "odg", "application/vnd.oasis.opendocument.graphics");
+        odg.setInputFamily(DocumentFamily.DRAWING);
+        odg.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw8"));
+        addFormat(odg);
+
+        DocumentFormat svg = new DocumentFormat("Scalable Vector Graphics", "svg", "image/svg+xml");
+        svg.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_svg_Export"));
+        addFormat(svg);
+    }
+
+    /**
+     * 创建默认的导出属性
+     * @return
+     */
+    private PropertyValue[] getCommonPropertyValue() {
+        PropertyValue[] aFilterData = new PropertyValue[11];
+        // 不显示文档标题
+        aFilterData[0] = new PropertyValue();
+        aFilterData[0].Name = "DisplayPDFDocumentTitle";
+        aFilterData[0].Value= true;
+        // 导出文件编码方式
+        aFilterData[1] = new PropertyValue();
+        aFilterData[1].Name = "Encoding";
+        aFilterData[1].Value= "UTF-8";
+        // 隐藏工具条
+        aFilterData[2] = new PropertyValue();
+        aFilterData[2].Name = "HideViewerToolbar";
+        aFilterData[2].Value= false;
+        // 隐藏窗口控制条
+        aFilterData[3] = new PropertyValue();
+        aFilterData[3].Name = "HideViewerWindowControls";
+        aFilterData[3].Value= true;
+        // 全屏展示
+        aFilterData[4] = new PropertyValue();
+        aFilterData[4].Name = "OpenInFullScreenMode";
+        aFilterData[4].Value= false;
+        // 第一页左边展示
+        aFilterData[5] = new PropertyValue();
+        aFilterData[5].Name = "MathToMathType";
+        aFilterData[5].Value= true;
+        // 文档标题内容
+        aFilterData[6] = new PropertyValue();
+        aFilterData[6].Name = "Watermark";
+        aFilterData[6].Value= "KEKING.CN";
+        // 导出文件编码方式
+        aFilterData[7] = new PropertyValue();
+        aFilterData[7].Name = "CharacterSet";
+        aFilterData[7].Value= "UTF-8";
+        // 导出文件编码方式
+        aFilterData[8] = new PropertyValue();
+        aFilterData[8].Name = "Encoding";
+        aFilterData[8].Value= "UTF-8";
+        // 导出文件编码方式
+        aFilterData[9] = new PropertyValue();
+        aFilterData[9].Name = "CharSet";
+        aFilterData[9].Value= "UTF-8";
+        // 导出文件编码方式
+        aFilterData[10] = new PropertyValue();
+        aFilterData[10].Name = "charset";
+        aFilterData[10].Value= "UTF-8";
+        return aFilterData;
+    }
+}

+ 28 - 0
src/main/java/com/yudianbank/filters/ChinesePathFilter.java

@@ -0,0 +1,28 @@
+package com.yudianbank.filters;
+
+import javax.servlet.*;
+import java.io.IOException;
+
+/**
+ *
+ * @author yudian-it
+ * @date 2017/11/30
+ */
+public class ChinesePathFilter implements Filter {
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        request.setCharacterEncoding("UTF-8");
+        response.setCharacterEncoding("UTF-8");
+        chain.doFilter(request, response);
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}

+ 23 - 0
src/main/java/com/yudianbank/filters/FilterConfiguration.java

@@ -0,0 +1,23 @@
+package com.yudianbank.filters;
+
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+/**
+ *
+ * @author yudian-it
+ * @date 2017/11/30
+ */
+@Configuration
+public class FilterConfiguration {
+
+    @Bean
+    public FilterRegistrationBean getChinesePathFilter(){
+        ChinesePathFilter filter = new ChinesePathFilter();
+        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+        registrationBean.setFilter(filter);
+        return registrationBean;
+    }
+}

+ 57 - 0
src/main/java/com/yudianbank/param/ReturnResponse.java

@@ -0,0 +1,57 @@
+package com.yudianbank.param;
+
+import java.io.Serializable;
+
+/**
+ * 接口返回值结构
+ * @author yudian-it
+ * @date 2017/11/17
+ */
+public class ReturnResponse<T> implements Serializable{
+    private static final long serialVersionUID = 313975329998789878L;
+    /**
+     * 返回状态
+     * 0. 成功
+     * 1. 失败
+     */
+    private int code;
+
+    /**
+     * 返回状态描述
+     * XXX成功
+     * XXX失败
+     */
+    private String msg;
+
+    private T content;
+
+    public ReturnResponse(int code, String msg, T content) {
+        this.code = code;
+        this.msg = msg;
+        this.content = content;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getContent() {
+        return content;
+    }
+
+    public void setContent(T content) {
+        this.content = content;
+    }
+}

+ 68 - 0
src/main/java/com/yudianbank/utils/ConverterUtils.java

@@ -0,0 +1,68 @@
+package com.yudianbank.utils;
+
+import com.sun.star.document.UpdateDocMode;
+import com.yudianbank.extend.ControlDocumentFormatRegistry;
+import org.artofsolving.jodconverter.OfficeDocumentConverter;
+import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
+import org.artofsolving.jodconverter.office.OfficeManager;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 创建文件转换器
+ *
+ * @author yudian-it
+ * @date 2017/11/13
+ */
+@Component
+public class ConverterUtils {
+
+    @Value("${office.home}")
+    String officeHome;
+//    OpenOfficeConnection connection;
+    OfficeManager officeManager;
+
+    @PostConstruct
+    public void initOfficeManager() {
+        ////            connection = new SocketOpenOfficeConnection(host,8100);
+////            connection.connect();
+        DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
+        configuration.setOfficeHome(officeHome);
+        configuration.setPortNumber(8100);
+        officeManager = configuration.buildOfficeManager();
+        officeManager.start();
+        // 设置任务执行超时为5分钟
+        // configuration.setTaskExecutionTimeout(1000 * 60 * 5L);//
+        // 设置任务队列超时为24小时
+        // configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);//
+    }
+
+    public OfficeDocumentConverter getDocumentConverter() {
+        OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager, new ControlDocumentFormatRegistry());
+        converter.setDefaultLoadProperties(getLoadProperties());
+        return converter;
+    }
+
+    private Map<String,?> getLoadProperties() {
+        Map<String,Object> loadProperties = new HashMap<>(10);
+        loadProperties.put("Hidden", true);
+        loadProperties.put("ReadOnly", true);
+        loadProperties.put("UpdateDocMode", UpdateDocMode.QUIET_UPDATE);
+        loadProperties.put("CharacterSet", Charset.forName("UTF-8").name());
+        return loadProperties;
+    }
+
+    @PreDestroy
+    public void destroyOfficeManager(){
+        if (null != officeManager && officeManager.isRunning()) {
+            officeManager.stop();
+        }
+    }
+
+}

+ 74 - 0
src/main/java/com/yudianbank/utils/DeleteFileUtil.java

@@ -0,0 +1,74 @@
+package com.yudianbank.utils;
+
+import java.io.File;
+
+public class DeleteFileUtil {
+    /**
+     * 删除单个文件
+     *
+     * @param fileName
+     *            要删除的文件的文件名
+     * @return 单个文件删除成功返回true,否则返回false
+     */
+    public static boolean deleteFile(String fileName) {
+        File file = new File(fileName);
+        // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
+        if (file.exists() && file.isFile()) {
+            if (file.delete()) {
+                System.out.println("删除单个文件" + fileName + "成功!");
+                return true;
+            } else {
+                System.out.println("删除单个文件" + fileName + "失败!");
+                return false;
+            }
+        } else {
+            System.out.println("删除单个文件失败:" + fileName + "不存在!");
+            return false;
+        }
+    }
+
+
+    /**
+     * 删除目录及目录下的文件
+     *
+     * @param dir
+     *            要删除的目录的文件路径
+     * @return 目录删除成功返回true,否则返回false
+     */
+    public static boolean deleteDirectory(String dir) {
+        // 如果dir不以文件分隔符结尾,自动添加文件分隔符
+        if (!dir.endsWith(File.separator)) {
+            dir = dir + File.separator;
+        }
+        File dirFile = new File(dir);
+        // 如果dir对应的文件不存在,或者不是一个目录,则退出
+        if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
+            System.out.println("删除目录失败:" + dir + "不存在!");
+            return false;
+        }
+        boolean flag = true;
+        // 删除文件夹中的所有文件包括子目录
+        File[] files = dirFile.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            // 删除子文件
+            if (files[i].isFile()) {
+                flag = DeleteFileUtil.deleteFile(files[i].getAbsolutePath());
+                if (!flag)
+                    break;
+            }
+            // 删除子目录
+            else if (files[i].isDirectory()) {
+                flag = DeleteFileUtil.deleteDirectory(files[i]
+                        .getAbsolutePath());
+                if (!flag)
+                    break;
+            }
+        }
+        if (!flag) {
+            System.out.println("删除目录失败!");
+            return false;
+        }
+        return true;
+    }
+
+}

+ 151 - 0
src/main/java/com/yudianbank/utils/DownloadUtils.java

@@ -0,0 +1,151 @@
+package com.yudianbank.utils;
+
+import com.yudianbank.param.ReturnResponse;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import java.io.*;
+import java.net.*;
+import java.util.UUID;
+
+/**
+ * @author yudian-it
+ */
+@Component
+public class DownloadUtils {
+
+    @Value("${file.dir}")
+    String fileDir;
+
+    /**
+     * 一开始测试的时候发现有些文件没有下载下来,而有些可以;当时也是郁闷了好一阵,但是最终还是不得解
+     * 再次测试的时候,通过前台对比url发现,原来参数中有+号特殊字符存在,但是到后之后却变成了空格,突然恍然大悟
+     * 应该是转义出了问题,url转义中会把+号当成空格来计算,所以才会出现这种情况,遂想要通过整体替换空格为加号,因为url
+     * 中的参数部分是不会出现空格的,但是文件名中就不好确定了,所以只对url参数部分做替换
+     * @param urlAddress
+     * @param type
+     * @param needEncode
+     *      在处理本地文件(测试预览界面的,非ufile)的时候要对中文进行转码,
+     *      因为tomcat对[英文字母(a-z,A-Z)、数字(0-9)、- _ . ~ 4个特殊字符以及所有保留字符]
+     *      以外的字符会处理不正常,导致失败
+     * @return
+     */
+    public ReturnResponse<String> downLoad(String urlAddress, String type, String fileName, String needEncode){
+//        type = dealWithMS2013(type);
+        ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
+        URL url = null;
+        try {
+            if (null != needEncode) {
+                urlAddress = encodeUrlParam(urlAddress);
+                // 因为tomcat不能处理'+'号,所以讲'+'号替换成'%20%'
+                urlAddress = urlAddress.replaceAll("\\+", "%20");
+            }else{
+                urlAddress = replacePlusMark(urlAddress);
+            }
+            url = new URL(urlAddress);
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+        UUID uuid = UUID.randomUUID();
+        if (null == fileName) {
+            fileName = uuid+ "."+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);
+            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;
+        }
+    }
+
+    /**
+     * 转换url参数部分的空格为加号(因为在url编解码的过程中出现+转为空格的情况)
+     * @param urlAddress
+     * @return
+     */
+    private String replacePlusMark(String urlAddress) {
+        String nonParamStr = urlAddress.substring(0,urlAddress.indexOf("?") + 1);
+        String paramStr = urlAddress.substring(nonParamStr.length());
+        return nonParamStr + paramStr.replace(" ", "+");
+    }
+
+    /**
+     * 对最有一个路径进行转码
+     * @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("?") + 1);
+            }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;
+    }
+}

+ 192 - 0
src/main/java/com/yudianbank/utils/FileUtils.java

@@ -0,0 +1,192 @@
+package com.yudianbank.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.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";
+
+    @Autowired
+    RedissonClient redissonClient;
+    @Value("${file.dir}")
+    String fileDir;
+
+    @Value("${converted.file.charset}")
+    String charset;
+
+    /**
+     * 已转换过的文件集合(redis缓存)
+     * @return
+     */
+    public Map<String, String> listConvertedFiles() {
+        RMapCache<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
+        return convertedList;
+    }
+
+    /**
+     * 已转换过的文件,根据文件名获取
+     * @return
+     */
+    public String getConvertedFile(String key) {
+        RMapCache<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
+        return convertedList.get(key);
+    }
+
+    /**
+     * 从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<String> listPictureTypes(){
+        List<String> list = Lists.newArrayList();
+        list.add("jpg");
+        list.add("jpeg");
+        list.add("png");
+        list.add("gif");
+        list.add("bmp");
+        return list;
+    }
+
+    public List<String> listArchiveTypes(){
+        List<String> 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<String> listOfficeTypes() {
+        List<String> 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<String, String> convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY);
+        convertedList.fastPut(fileName, value);
+    }
+
+    /**
+     * 判断文件编码格式
+     * @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("<script src=\"js/jquery-3.0.0.min.js\" type=\"text/javascript\"></script>");
+            sb.append("<script src=\"js/excel.header.js\" type=\"text/javascript\"></script>");
+            sb.append("<link rel=\"stylesheet\" href=\"http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css\">");
+        } 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();
+        }
+    }
+}

+ 129 - 0
src/main/java/com/yudianbank/utils/OfficeToPdf.java

@@ -0,0 +1,129 @@
+package com.yudianbank.utils;
+import org.artofsolving.jodconverter.OfficeDocumentConverter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+@Component
+public class OfficeToPdf {
+    /**
+     * 获取OpenOffice.org 3的安装目录
+     *
+     * @return OpenOffice.org 3的安装目录
+     */
+    @Value("${openOfficePath}")
+    private String openOfficePath;
+    @Autowired
+    ConverterUtils converterUtils;
+    /**
+     * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件<br>
+     *
+     * @param inputFilePath
+     *            源文件路径,如:"e:/test.docx"
+     * @param outputFilePath
+     *            目标文件路径,如:"e:/test_docx.pdf"
+     * @return
+     */
+    public  boolean openOfficeToPDF(String inputFilePath, String outputFilePath) {
+        return office2pdf(inputFilePath, outputFilePath);
+    }
+
+
+
+    /**
+     * 连接OpenOffice.org 并且启动OpenOffice.org
+     *
+     * @return
+     */
+    /*public  OfficeManager getOfficeManager() {
+        DefaultOfficeManagerConfiguration config = new DefaultOfficeManagerConfiguration();
+        // 获取OpenOffice.org 3的安装目录
+        String officeHome = openOfficePath;
+        config.setOfficeHome(officeHome);
+        // 启动OpenOffice的服务
+        OfficeManager officeManager = config.buildOfficeManager();
+        officeManager.start();
+        return officeManager;
+    }*/
+
+    /**
+     * 转换文件
+     *
+     * @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);
+    }
+
+}

+ 194 - 0
src/main/java/com/yudianbank/utils/PoiExcelToHtml.java

@@ -0,0 +1,194 @@
+package com.yudianbank.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.poi.hssf.converter.ExcelToHtmlConverter;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.converter.PicturesManager;
+import org.apache.poi.hwpf.converter.WordToHtmlConverter;
+import org.apache.poi.hwpf.usermodel.Picture;
+import org.apache.poi.hwpf.usermodel.PictureType;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.w3c.dom.Document;
+
+
+public  class PoiExcelToHtml {
+//    String  path = getClass().getClassLoader().getResource(".").getPath()+File.separator+"static"+File.separator;
+    public static  void excelConvert(URL url) {
+        try {
+            String path = "";
+
+//            http://keking.ufile.ucloud.com.cn/20171101152525_左晓晖2017年9.xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=1n8ASiYMcfiF30YHxwpzwfqmlM0=
+//            URL url = new URL("http://keking.ufile.ucloud.com.cn/20171101150322_运费贷信审资料(给予客户收集版).xlsx?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=RRVFIICITMNFed1LQgB10WdKHiE=");
+            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+            //设置超时间为3秒
+            conn.setConnectTimeout(3*1000);
+            //防止屏蔽程序抓取而返回403错误
+            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+            //得到输入流
+            InputStream inputStream = conn.getInputStream();
+            HSSFWorkbook excelBook = new HSSFWorkbook(inputStream);
+            ExcelToHtmlConverter excelToHtmlConverter = new ExcelToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
+            excelToHtmlConverter.processWorkbook(excelBook);
+            List pics = excelBook.getAllPictures();
+            if (pics != null) {
+                for (int i = 0; i < pics.size(); i++) {
+                    Picture pic = (Picture) pics.get(i);
+                    try {
+                        pic.writeImageContent(new FileOutputStream(path + pic.suggestFullFileName()));
+                    } catch (FileNotFoundException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+            Document htmlDocument = excelToHtmlConverter.getDocument();
+            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+            DOMSource domSource = new DOMSource(htmlDocument);
+            StreamResult streamResult = new StreamResult(outStream);
+            TransformerFactory tf = TransformerFactory.newInstance();
+            Transformer serializer = tf.newTransformer();
+            serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
+            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+            serializer.setOutputProperty(OutputKeys.METHOD, "html");
+            serializer.transform(domSource, streamResult);
+            outStream.close();
+
+            String content = new String(outStream.toByteArray());
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (ParserConfigurationException e) {
+            e.printStackTrace();
+        } catch (TransformerException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * excel07转html
+     * filename:要读取的文件所在文件夹
+     * filepath:文件名
+     * htmlname:生成html名称
+     * path:html存放路径
+     * */
+    public static void excelToHtml () throws Exception{
+        String htmlname="exportExcel"+"07Test"+".html";
+
+
+        URL url = new URL("http://keking.ufile.ucloud.com.cn/20171101150322_运费贷信审资料(给予客户收集版).xlsx?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=RRVFIICITMNFed1LQgB10WdKHiE=");
+        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+        //设置超时间为3秒
+        conn.setConnectTimeout(3*1000);
+        //防止屏蔽程序抓取而返回403错误
+        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+        //得到输入流
+        InputStream is = conn.getInputStream();
+
+        Workbook workbook = null;
+//        InputStream is = new FileInputStream(filename+"/"+filepath);
+        try {
+            String html="";
+            workbook =  new XSSFWorkbook(is);
+            for (int numSheet = 0; numSheet < workbook.getNumberOfSheets(); numSheet++) {
+                Sheet sheet = workbook.getSheetAt(numSheet);
+                if (sheet == null) {
+                    continue;
+                }
+                html+="=======================" + sheet.getSheetName() + "=========================<br><br>";
+
+                int firstRowIndex = sheet.getFirstRowNum();
+                int lastRowIndex = sheet.getLastRowNum();
+                html+="<table border='1' align='left'>";
+                Row firstRow = sheet.getRow(firstRowIndex);
+                for (int i = firstRow.getFirstCellNum(); i <= firstRow.getLastCellNum(); i++) {
+                    Cell cell = firstRow.getCell(i);
+                    String cellValue = getCellValue(cell, true);
+                    html+="<th>" + cellValue + "</th>";
+                }
+
+
+                //行
+                for (int rowIndex = firstRowIndex + 1; rowIndex <= lastRowIndex; rowIndex++) {
+                    Row currentRow = sheet.getRow(rowIndex);
+                    html+="<tr>";
+                    if(currentRow!=null){
+
+                        int firstColumnIndex = currentRow.getFirstCellNum();
+                        int lastColumnIndex = currentRow.getLastCellNum();
+                        //列
+                        for (int columnIndex = firstColumnIndex; columnIndex <= lastColumnIndex; columnIndex++) {
+                            Cell currentCell = currentRow.getCell(columnIndex);
+                            String currentCellValue = getCellValue(currentCell, true);
+                            html+="<td>"+currentCellValue + "</td>";
+                        }
+                    }else{
+                        html+=" ";
+                    }
+                    html+="</tr>";
+                }
+                html+="</table>";
+
+
+                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+                DOMSource domSource = new DOMSource ();
+                StreamResult streamResult = new StreamResult (outStream);
+
+                TransformerFactory tf = TransformerFactory.newInstance();
+                Transformer serializer = tf.newTransformer();
+                serializer.setOutputProperty (OutputKeys.ENCODING, "utf-8");
+                serializer.setOutputProperty (OutputKeys.INDENT, "yes");
+                serializer.setOutputProperty (OutputKeys.METHOD, "html");
+                serializer.transform (domSource, streamResult);
+                outStream.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    /**
+     * 读取单元格
+     *
+     */
+    private static String getCellValue(Cell cell, boolean treatAsStr) {
+        if (cell == null) {
+            return "";
+        }
+
+        if (treatAsStr) {
+            cell.setCellType(Cell.CELL_TYPE_STRING);
+        }
+
+        if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
+            return String.valueOf(cell.getBooleanCellValue());
+        } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
+            return String.valueOf(cell.getNumericCellValue());
+        } else {
+            return String.valueOf(cell.getStringCellValue());
+        }
+    }
+}

+ 19 - 0
src/main/java/com/yudianbank/utils/ShedulerClean.java

@@ -0,0 +1,19 @@
+package com.yudianbank.utils;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+
+@Component
+public class ShedulerClean {
+    @Value("${file.dir}")
+    String fileDir;
+
+    @Scheduled(cron = "0 0 23 * * ?")   //每晚23点执行一次
+    public void clean(){
+        System.out.println("执行一次清空文件夹");
+        DeleteFileUtil.deleteDirectory(fileDir);
+    }
+}

+ 61 - 0
src/main/java/com/yudianbank/utils/WordToHtml.java

@@ -0,0 +1,61 @@
+package com.yudianbank.utils;
+
+import java.io.*;
+import java.util.*;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import com.github.junrar.Archive;
+import com.github.junrar.exception.RarException;
+import com.github.junrar.rarfile.FileHeader;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.poi.xwpf.converter.core.FileImageExtractor;
+import org.apache.poi.xwpf.converter.core.FileURIResolver;
+import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
+import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+public class WordToHtml {
+    /**          这是2007版本 转html 已测试成功的代码  07和03版要用两种代码转 但因为后面说要用
+     * 38      * 2007版本word转换成html
+     * 39      * @throws IOException
+     * 40
+     */
+
+    public static String Word2007ToHtml(InputStream inputStream) throws IOException {
+        // 1) 加载word文档生成 XWPFDocument对象
+        XWPFDocument document = new XWPFDocument(inputStream);
+
+        // 2) 解析 XHTML配置 (这里设置IURIResolver来设置图片存放的目录)
+//        File imageFolderFile = new File("/Users/zuoxiaohui/IdeaProjects/yudian-preview-boot/yudian-preview-boot/src/main/resources/picture/");
+        File imageFolderFile = new File("/Users/zuoxiaohui/IdeaProjects/yudian-preview-boot/yudian-preview-boot/src/main/resources/static/");
+        XHTMLOptions options = XHTMLOptions.create().URIResolver(new FileURIResolver(imageFolderFile));
+        options.setExtractor(new FileImageExtractor(imageFolderFile));
+        options.setIgnoreStylesIfUnused(false);
+        options.setFragment(true);
+
+        File file = new File("/Users/zuoxiaohui/Test/" + "test.html");
+        // 3) 将 XWPFDocument转换成XHTML
+        OutputStream out = new FileOutputStream(file);
+        XHTMLConverter.getInstance().convert(document, out, options);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        XHTMLConverter.getInstance().convert(document, baos, options);
+        String content = baos.toString();
+        System.out.println(content);
+        baos.close();
+        return content;
+
+
+    }
+
+    public static void main(String[] args) throws IOException, ArchiveException, RarException {
+        File file = new File("C:\\Users\\yudian-it\\Downloads\\Downloads.zip");
+        System.out.println("Objects.equals(new Integer(1000), new Integer(1000)) :" + Objects.equals(new Integer(1000), new Integer(1000)));
+        System.out.println(Integer.valueOf("-129") == Integer.valueOf("-129"));
+    }
+
+}

+ 392 - 0
src/main/java/com/yudianbank/utils/ZipReader.java

@@ -0,0 +1,392 @@
+package com.yudianbank.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 java.io.*;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ *
+ * @author yudian-it
+ * @date 2017/11/27
+ */
+@Component
+public class ZipReader {
+
+    @Autowired
+    FileUtils fileUtils;
+    @Value("${file.dir}")
+    String fileDir;
+
+    ExecutorService executors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+
+    /**
+     * 读取压缩文件
+     * 文件压缩到统一目录fileDir下,并且命名使用压缩文件名+文件名因为文件名
+     * 可能会重复(在系统中对于同一种类型的材料压缩文件内的文件是一样的,如果文件名
+     * 重复,那么这里会被覆盖[同一个压缩文件中的不同目录中的相同文件名暂时不考虑])
+     * <b>注:</b>
+     * <p>
+     *     文件名命名中的参数的说明:
+     *     1.archiveName,为避免解压的文件中有重名的文件会彼此覆盖,所以加上了archiveName,因为在ufile中archiveName
+     *     是不会重复的。
+     *     2.level,这里层级结构的列表我是通过一个map来构造的,map的key是文件的名字,值是对应的文件,这样每次向map中
+     *     加入节点的时候都会获取父节点是否存在,存在则会获取父节点的value并将当前节点加入到父节点的childList中(这里利用
+     *     的是java语言的引用的特性)。
+     * </p>
+     * @param filePath
+     */
+    public String readZipFile(String filePath) {
+        String archiveSeparator = "/";
+        Map<String, FileNode> appender = Maps.newHashMap();
+        String archiveFileName = fileUtils.getFileNameFromPath(filePath);
+        try {
+            ZipFile zipFile = new ZipFile(filePath, fileUtils.getFileEncodeUTFGBK(filePath));
+            Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
+            // 排序
+            entries = sortZipEntries(entries);
+            List<Map<String, ZipArchiveEntry>> entriesToBeExtracted = Lists.newArrayList();
+            while (entries.hasMoreElements()){
+                ZipArchiveEntry entry = entries.nextElement();
+                String fullName = entry.getName();
+                int level = fullName.split(archiveSeparator).length;
+                // 展示名
+                String originName = getLastFileName(fullName, archiveSeparator);
+                String childName = level + "_" + originName;
+                boolean directory = entry.isDirectory();
+                if (!directory) {
+                    childName = archiveFileName + "_" + originName;
+                    entriesToBeExtracted.add(Collections.singletonMap(childName, entry));
+                }
+                String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName);
+                parentName = (level-1) + "_" + parentName;
+                FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory);
+                addNodes(appender, parentName, node);
+                appender.put(childName, node);
+            }
+            // 开启新的线程处理文件解压
+            executors.submit(new ZipExtractorWorker(entriesToBeExtracted, zipFile, filePath));
+            return new ObjectMapper().writeValueAsString(appender.get(""));
+        } catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 排序zipEntries(对原来列表倒序)
+     * @param entries
+     */
+    private Enumeration<ZipArchiveEntry> sortZipEntries(Enumeration<ZipArchiveEntry> entries) {
+        List<ZipArchiveEntry> sortedEntries = Lists.newArrayList();
+        while(entries.hasMoreElements()){
+            sortedEntries.add(entries.nextElement());
+        }
+        Collections.sort(sortedEntries, Comparator.comparingInt(o -> o.getName().length()));
+        return Collections.enumeration(sortedEntries);
+    }
+
+    public String unRar(String filePath){
+        Map<String, FileNode> appender = Maps.newHashMap();
+        try {
+            Archive archive = new Archive(new File(filePath));
+            List<FileHeader> headers = archive.getFileHeaders();
+            headers = sortedHeaders(headers);
+            String archiveFileName = fileUtils.getFileNameFromPath(filePath);
+            List<Map<String, FileHeader>> headersToBeExtracted = Lists.newArrayList();
+            for (FileHeader header : headers) {
+                String fullName;
+                if (header.isUnicode()) {
+                    fullName = header.getFileNameW();
+                }else {
+                    fullName = header.getFileNameString();
+                }
+                // 展示名
+                String originName = getLastFileName(fullName, "\\");
+                String childName = originName;
+                boolean directory = header.isDirectory();
+                if (!directory) {
+                    childName = archiveFileName + "_" + originName;
+                    headersToBeExtracted.add(Collections.singletonMap(childName, header));
+                }
+                String parentName = getLast2FileName(fullName, "\\", archiveFileName);
+                FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory);
+                addNodes(appender, parentName, node);
+                appender.put(childName, node);
+            }
+            executors.submit(new RarExtractorWorker(headersToBeExtracted, archive, filePath));
+            return new ObjectMapper().writeValueAsString(appender.get(""));
+        } catch (RarException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private void addNodes(Map<String, FileNode> appender, String parentName, FileNode node) {
+        if (appender.containsKey(parentName)) {
+            appender.get(parentName).getChildList().add(node);
+        }else { // 根节点
+            FileNode nodeRoot = new FileNode(parentName, parentName, "", new ArrayList<>(), true);
+            nodeRoot.getChildList().add(node);
+            appender.put("", nodeRoot);
+            appender.put(parentName, nodeRoot);
+        }
+    }
+
+    private List<FileHeader> sortedHeaders(List<FileHeader> headers) {
+        List<FileHeader> sortedHeaders = new ArrayList<>();
+        Map<Integer, FileHeader> mapHeaders = new TreeMap<>();
+        headers.forEach(header -> mapHeaders.put(header.getFileNameW().length(), header));
+        for (Map.Entry<Integer, FileHeader> entry : mapHeaders.entrySet()){
+            for (FileHeader header : headers) {
+                if (entry.getKey().intValue() == header.getFileNameW().length()) {
+                    sortedHeaders.add(header);
+                }
+            }
+        }
+        return sortedHeaders;
+    }
+
+    /**
+     * 获取倒数第二个文件(夹)名
+     * @param fullName
+     * @param seperator
+     *       压缩文件解压后,不同的压缩格式分隔符不一样zip是/,而rar是\
+     * @param rootName
+     *      根目录名:如果倒数第二个路径为空,那么赋值为rootName
+     * @return
+     */
+    private static String getLast2FileName(String fullName, String seperator, String rootName) {
+        if (fullName.endsWith(seperator)) {
+            fullName = fullName.substring(0, fullName.length()-1);
+        }
+        // 1.获取剩余部分
+        int endIndex = fullName.lastIndexOf(seperator);
+        String leftPath = fullName.substring(0, endIndex == -1 ? 0 : endIndex);
+        if (null != leftPath && leftPath.length() > 1) {
+            // 2.获取倒数第二个
+            return getLastFileName(leftPath, seperator);
+        }else {
+            return rootName;
+        }
+    }
+
+    /**
+     * 获取最后一个文件(夹)的名字
+     * @param fullName
+     * @param seperator
+     *       压缩文件解压后,不同的压缩格式分隔符不一样zip是/,而rar是\
+     * @return
+     */
+    private static String getLastFileName(String fullName, String seperator) {
+        if (fullName.endsWith(seperator)) {
+            fullName = fullName.substring(0, fullName.length()-1);
+        }
+        String newName = fullName;
+        if (null != fullName && fullName.contains(seperator)) {
+            newName = fullName.substring(fullName.lastIndexOf(seperator) + 1);
+        }
+        return newName;
+    }
+
+    /**
+     * 文件节点(区分文件上下级)
+     */
+    public class FileNode{
+
+        private String originName;
+        private String fileName;
+        private String parentFileName;
+        private boolean directory;
+
+        private List<FileNode> childList;
+
+        public FileNode(String originName, String fileName, String parentFileName, List<FileNode> childList, boolean directory) {
+            this.originName = originName;
+            this.fileName = fileName;
+            this.parentFileName = parentFileName;
+            this.childList = childList;
+            this.directory = directory;
+        }
+
+        public String getFileName() {
+            return fileName;
+        }
+
+        public void setFileName(String fileName) {
+            this.fileName = fileName;
+        }
+
+        public String getParentFileName() {
+            return parentFileName;
+        }
+
+        public void setParentFileName(String parentFileName) {
+            this.parentFileName = parentFileName;
+        }
+
+        public List<FileNode> getChildList() {
+            return childList;
+        }
+
+        public void setChildList(List<FileNode> childList) {
+            this.childList = childList;
+        }
+
+        @Override
+        public String toString() {
+            try {
+                return new ObjectMapper().writeValueAsString(this);
+            } catch (JsonProcessingException e) {
+                e.printStackTrace();
+                return "";
+            }
+        }
+
+        public String getOriginName() {
+            return originName;
+        }
+
+        public void setOriginName(String originName) {
+            this.originName = originName;
+        }
+
+        public boolean isDirectory() {
+            return directory;
+        }
+
+        public void setDirectory(boolean directory) {
+            this.directory = directory;
+        }
+    }
+
+    /**
+     * Zip文件抽取线程
+     */
+    class ZipExtractorWorker implements Runnable {
+
+        private List<Map<String, ZipArchiveEntry>> entriesToBeExtracted;
+        private ZipFile zipFile;
+        private String filePath;
+
+        public ZipExtractorWorker(List<Map<String, ZipArchiveEntry>> entriesToBeExtracted, ZipFile zipFile, String filePath) {
+            this.entriesToBeExtracted = entriesToBeExtracted;
+            this.zipFile = zipFile;
+            this.filePath = filePath;
+        }
+
+        @Override
+        public void run() {
+            System.out.println("解析压缩文件开始《《《《《《《《《《《《《《《《《《《《《《《");
+            for (Map<String, ZipArchiveEntry> entryMap : entriesToBeExtracted) {
+                String childName = entryMap.keySet().iterator().next();
+                ZipArchiveEntry entry = entryMap.values().iterator().next();
+                try {
+                    extractZipFile(childName, zipFile.getInputStream(entry));
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            try {
+                zipFile.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            if (new File(filePath).exists()) {
+                new File(filePath).delete();
+            }
+            System.out.println("解析压缩文件结束《《《《《《《《《《《《《《《《《《《《《《《");
+        }
+
+
+        /**
+         * 读取压缩文件并写入到fileDir文件夹下
+         * @param childName
+         * @param zipFile
+         */
+        private void extractZipFile(String childName, InputStream zipFile) {
+            String outPath = fileDir + childName;
+            try (OutputStream ot = new FileOutputStream(outPath)){
+                byte[] inByte = new byte[1024];
+                int len;
+                while ((-1 != (len = zipFile.read(inByte)))){
+                    ot.write(inByte, 0, len);
+                }
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Rar文件抽取
+     */
+    class RarExtractorWorker implements Runnable {
+        private List<Map<String, FileHeader>> headersToBeExtracted;
+        private Archive archive;
+        /**
+         * 用以删除源文件
+         */
+        private String filePath;
+
+        public RarExtractorWorker(List<Map<String, FileHeader>> headersToBeExtracted, Archive archive, String filePath) {
+            this.headersToBeExtracted = headersToBeExtracted;
+            this.archive = archive;
+            this.filePath = filePath;
+        }
+
+        @Override
+        public void run() {
+            System.out.println("解析压缩文件开始《《《《《《《《《《《《《《《《《《《《《《《");
+            for (Map<String, FileHeader> entryMap : headersToBeExtracted) {
+                String childName = entryMap.keySet().iterator().next();
+                extractRarFile(childName, entryMap.values().iterator().next(), archive);
+            }
+            try {
+                archive.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            if (new File(filePath).exists()) {
+                new File(filePath).delete();
+            }
+            System.out.println("解析压缩文件结束《《《《《《《《《《《《《《《《《《《《《《《");
+        }
+
+        /**
+         * 抽取rar文件到指定目录下
+         * @param childName
+         * @param header
+         * @param archive
+         */
+        private void extractRarFile(String childName, FileHeader header, Archive archive) {
+            String outPath = fileDir + childName;
+            try(OutputStream ot = new FileOutputStream(outPath)) {
+                archive.extractFile(header, ot);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (RarException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 113 - 0
src/main/java/com/yudianbank/web/controller/FileController.java

@@ -0,0 +1,113 @@
+package com.yudianbank.web.controller;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.yudianbank.param.ReturnResponse;
+import com.yudianbank.utils.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ *
+ * @author yudian-it
+ * @date 2017/12/1
+ */
+@RestController
+public class FileController {
+    @Value("${file.dir}")
+    String fileDir;
+    @Autowired
+    FileUtils fileUtils;
+    String demoDir = "demo";
+    String demoPath = demoDir + File.separator;
+
+    @RequestMapping(value = "fileUpload", method = RequestMethod.POST)
+    public String fileUpload(@RequestParam("file") MultipartFile file,
+                             HttpServletRequest request) throws JsonProcessingException {
+        String fileName = file.getOriginalFilename();
+        // 判断该文件类型是否有上传过,如果上传过则提示不允许再次上传
+        if (existsTypeFile(fileName)) {
+            return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "每一种类型只可以上传一个文件,请先删除原有文件再次上传", null));
+        }
+        File outFile = new File(fileDir + demoPath);
+        if (!outFile.exists()) {
+            outFile.mkdirs();
+        }
+        try(InputStream in = file.getInputStream();
+            OutputStream ot = new FileOutputStream(fileDir + demoPath + fileName)){
+            byte[] buffer = new byte[1024];
+            int len;
+            while ((-1 != (len = in.read(buffer)))) {
+                ot.write(buffer, 0, len);
+            }
+            return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(0, "SUCCESS", null));
+        } catch (IOException e) {
+            e.printStackTrace();
+            return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(1, "FAILURE", null));
+        }
+    }
+
+    @RequestMapping(value = "deleteFile", method = RequestMethod.GET)
+    public String deleteFile(String fileName) throws JsonProcessingException {
+        if (fileName.contains("/")) {
+            fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
+        }
+        File file = new File(fileDir + demoPath + fileName);
+        if (file.exists()) {
+            file.delete();
+        }
+        return new ObjectMapper().writeValueAsString(new ReturnResponse<String>(0, "SUCCESS", null));
+    }
+
+    @RequestMapping(value = "listFiles", method = RequestMethod.GET)
+    public String getFiles() throws JsonProcessingException {
+        List<Map<String, String>> list = Lists.newArrayList();
+        File file = new File(fileDir + demoPath);
+        if (file.exists()) {
+            Arrays.stream(file.listFiles()).forEach(file1 -> list.add(ImmutableMap.of("fileName", demoDir + "/" + file1.getName())));
+        }
+        return new ObjectMapper().writeValueAsString(list);
+    }
+
+    private String getFileName(String name) {
+        String suffix = name.substring(name.lastIndexOf("."));
+        String nameNoSuffix = name.substring(0, name.lastIndexOf("."));
+        String uuid = UUID.randomUUID().toString();
+        return uuid + "-" + nameNoSuffix + suffix;
+    }
+
+    /**
+     * 是否存在该类型的文件
+     * @return
+     * @param fileName
+     */
+    private boolean existsTypeFile(String fileName) {
+        boolean result = false;
+        String suffix = fileUtils.getSuffixFromFileName(fileName);
+        File file = new File(fileDir + demoPath);
+        if (file.exists()) {
+            for(File file1 : file.listFiles()){
+                String existsFileSuffix = fileUtils.getSuffixFromFileName(file1.getName());
+                if (suffix.equals(existsFileSuffix)) {
+                    result = true;
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+}

+ 170 - 0
src/main/java/com/yudianbank/web/controller/OnlinePreviewController.java

@@ -0,0 +1,170 @@
+package com.yudianbank.web.controller;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yudianbank.param.ReturnResponse;
+import com.yudianbank.utils.DownloadUtils;
+import com.yudianbank.utils.FileUtils;
+import com.yudianbank.utils.OfficeToPdf;
+import com.yudianbank.utils.ZipReader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+/**
+ * @author yudian-it
+ */
+@Controller
+public class OnlinePreviewController {
+    @Autowired
+    private OfficeToPdf officeToPdf;
+    @Autowired
+    FileUtils fileUtils;
+    @Autowired
+    DownloadUtils downloadUtils;
+    @Autowired
+    ZipReader zipReader;
+
+    @Value("${file.dir}")
+    String fileDir;
+
+    /**
+     * xls:http://keking.ufile.ucloud.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I+D1NOFtAJSPT16E6imv6JWuq0k=
+     * img:http://keking.ufile.ucloud.com.cn/ufile-a703a5a2-788f-488c-a9bf-f36878d5e308.JPG?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=W9TKj5Kp9oxg85fn5/0zgwF2PL4=
+     * doc:http://keking.ufile.ucloud.com.cn/20171113173342_凯京新员工试用期评估与转正确认表.doc?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=v1fC5ijYs8WnPzbSYa/bb0Z2Jf4=
+     * docx:http://keking.ufile.ucloud.com.cn/20171103180053_财产线索类需求20170920(1).docx?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=p7/L1W3iwktzRtkY5Ef2vK7kn3o=
+     * @param url
+     * @param model
+     * @return
+     */
+    @RequestMapping(value = "onlinePreview",method = RequestMethod.GET)
+    public String onlinePreview(String url, String needEncode, Model model) throws UnsupportedEncodingException {
+        // 路径转码
+        url = URLDecoder.decode(url, "utf-8");
+        String type = typeFromUrl(url);
+        String suffix = suffixFromUrl(url);
+        model.addAttribute("fileType", suffix);
+        if (type.equalsIgnoreCase("picture")) {
+            model.addAttribute("imgurl", url);
+            return "picture";
+        } else if (type.equalsIgnoreCase("txt")
+                || type.equalsIgnoreCase("html")
+                || type.equalsIgnoreCase("xml")
+                || type.equalsIgnoreCase("java")
+                || type.equalsIgnoreCase("properties")
+                || type.equalsIgnoreCase("mp3")){
+            model.addAttribute("ordinaryUrl",url);
+            return "txt";
+        } else if(type.equalsIgnoreCase("pdf")){
+            model.addAttribute("pdfUrl",url);
+            return "pdf";
+        } else if(type.equalsIgnoreCase("compress")){
+            // 抽取文件并返回文件列表
+            String fileName = fileUtils.getFileNameFromURL(url);
+            String fileTree = null;
+            // 判断文件名是否存在(redis缓存读取)
+            if (!StringUtils.hasText(fileUtils.getConvertedFile(fileName))) {
+                ReturnResponse<String> response = downloadUtils.downLoad(url, suffix, fileName, needEncode);
+                if (0 != response.getCode()) {
+                    model.addAttribute("msg", response.getMsg());
+                    return "fileNotSupported";
+                }
+                String filePath = response.getContent();
+                if ("zip".equalsIgnoreCase(suffix)
+                        || "jar".equalsIgnoreCase(suffix)
+                        || "gzip".equalsIgnoreCase(suffix)) {
+                    fileTree = zipReader.readZipFile(filePath);
+                } else if ("rar".equalsIgnoreCase(suffix)) {
+                    fileTree = zipReader.unRar(filePath);
+                }
+                fileUtils.addConvertedFile(fileName, fileTree);
+            }else {
+                fileTree = fileUtils.getConvertedFile(fileName);
+            }
+            System.out.println("返回文件tree》》》》》》》》》》》》》》》》》》》");
+            if (null != fileTree) {
+                model.addAttribute("fileTree",fileTree);
+                return "compress";
+            }else {
+                model.addAttribute("msg", "压缩文件类型不受支持,尝试在压缩的时候选择RAR4格式");
+                return "fileNotSupported";
+            }
+        } else if ("office".equalsIgnoreCase(type)) {
+            String fileName = fileUtils.getFileNameFromURL(url);
+            String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1)
+                    + ((suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx")) ?
+                    "html" : "pdf");
+            // 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
+            if (!fileUtils.listConvertedFiles().containsKey(pdfName)) {
+                String filePath = fileDir + fileName;
+                if (!new File(filePath).exists()) {
+                    ReturnResponse<String> response = downloadUtils.downLoad(url, suffix, null, needEncode);
+                    if (0 != response.getCode()) {
+                        model.addAttribute("msg", response.getMsg());
+                        return "fileNotSupported";
+                    }
+                    filePath = response.getContent();
+                }
+                String outFilePath = fileDir + pdfName;
+                if (StringUtils.hasText(outFilePath)) {
+                    officeToPdf.openOfficeToPDF(filePath, outFilePath);
+                    File f = new File(filePath);
+                    if (f.exists()) {
+                        f.delete();
+                    }
+                    if (suffix.equalsIgnoreCase("xls")
+                            || suffix.equalsIgnoreCase("xlsx")) {
+                        // 对转换后的文件进行操作(改变编码方式)
+                        fileUtils.doActionConvertedFile(outFilePath);
+                    }
+                    // 加入缓存
+                    fileUtils.addConvertedFile(pdfName, fileUtils.getRelativePath(outFilePath));
+                }
+            }
+            model.addAttribute("pdfUrl", pdfName);
+            return "pdf";
+        }else {
+            model.addAttribute("msg", "系统还不支持该格式文件的在线预览," + "如有需要请按下方显示的邮箱地址联系系统维护人员");
+            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);
+        return fileType;
+    }
+
+    /**
+     * 查看文件类型(防止参数中存在.点号或者其他特殊字符,所以先抽取文件名,然后再获取文件类型)
+     * @param url
+     * @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 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";
+        }
+        return fileType;
+    }
+
+
+}

+ 1 - 0
src/main/resources/META-INF/app.properties

@@ -0,0 +1 @@
+app.id=file-preview

+ 30 - 0
src/main/resources/application.properties

@@ -0,0 +1,30 @@
+server.port = 8012
+spring.http.encoding.charset = utf8
+
+## Freemarker 配置
+## 文件配置路径
+spring.freemarker.template-loader-path = classpath:/web/
+spring.freemarker.cache = false
+spring.freemarker.charset = UTF-8
+spring.freemarker.check-template-location = true
+spring.freemarker.content-type = text/html
+spring.freemarker.expose-request-attributes = true
+spring.freemarker.expose-session-attributes = true
+spring.freemarker.request-context-attribute = request
+spring.freemarker.suffix = .ftl
+
+#=============================================#spring Redisson配置#===================================#
+spring.redisson.address = 192.168.1.204:6379
+#Redisson配置end
+
+##资源映射路径(因为jar方式运行的原因)
+file.dir = C:\\Users\\yudian\\Desktop\\dev\\
+spring.resources.static-locations = classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${file.dir}
+
+## openoffice相关配置
+openOfficePath = /Applications/OpenOffice.app/Contents
+office.home = C:\\Program Files (x86)\\OpenOffice 4
+server.tomcat.uri-encoding = UTF-8
+converted.file.charset = GBK
+#======================================#文件上传限制#======================================#
+spring.http.multipart.max-file-size=100MB

+ 18 - 0
src/main/resources/logback.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <property name="LOG_FILE" value="@logging.path@/app.log"></property>
+    <include resource="org/springframework/boot/logging/logback/base.xml"/>
+    <jmxConfigurator/>
+    <logger name="org.springframework.web" level="info"/>
+    <appender name="stash" class="net.logstash.logback.appender.LogstashSocketAppender">
+        <port>10800</port>
+        <host>192.168.1.109</host>
+        <includeCallerData>true</includeCallerData>
+        <customFields>{"app_name":"@appName@"}</customFields>
+    </appender>
+    <root level="INFO">
+        <!--<appender-ref ref="dailyRollingFile"/>
+        <appender-ref ref="consoleRolling"/>-->
+        <appender-ref ref="stash"/>
+    </root>
+</configuration>

+ 8 - 0
src/main/resources/static/config.js

@@ -0,0 +1,8 @@
+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=',
+}

BIN
src/main/resources/static/css/img/diy/1_close.png


BIN
src/main/resources/static/css/img/diy/1_open.png


BIN
src/main/resources/static/css/img/diy/2.png


BIN
src/main/resources/static/css/img/diy/3.png


BIN
src/main/resources/static/css/img/diy/4.png


BIN
src/main/resources/static/css/img/diy/5.png


BIN
src/main/resources/static/css/img/diy/6.png


BIN
src/main/resources/static/css/img/diy/7.png


BIN
src/main/resources/static/css/img/diy/8.png


BIN
src/main/resources/static/css/img/diy/9.png


BIN
src/main/resources/static/css/img/line_conn.gif


BIN
src/main/resources/static/css/img/loading.gif


BIN
src/main/resources/static/css/img/zTreeStandard.gif


BIN
src/main/resources/static/css/img/zTreeStandard.png


+ 121 - 0
src/main/resources/static/css/loading.css

@@ -0,0 +1,121 @@
+.loading_container{
+    margin:0;
+    padding:0;
+    position: absolute;
+    left:0;
+    top:0;
+    width:100%;
+    display: none;
+    opacity: 0.5;
+    background-color: black;
+}
+.spinner {
+    margin: 245px auto;
+    width: 60px;
+    height: 60px;
+    position: relative;
+}
+
+.container1 > div, .container2 > div, .container3 > div {
+    width: 16px;
+    height: 16px;
+    background-color: #67CF22;
+
+    border-radius: 100%;
+    position: absolute;
+    -webkit-animation: bouncedelay 1.2s infinite ease-in-out;
+    animation: bouncedelay 1.2s infinite ease-in-out;
+    -webkit-animation-fill-mode: both;
+    animation-fill-mode: both;
+}
+
+.spinner .spinner-container {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+}
+
+.container2 {
+    -webkit-transform: rotateZ(45deg);
+    transform: rotateZ(45deg);
+}
+
+.container3 {
+    -webkit-transform: rotateZ(90deg);
+    transform: rotateZ(90deg);
+}
+
+.circle1 { top: 0; left: 0; }
+.circle2 { top: 0; right: 0; }
+.circle3 { right: 0; bottom: 0; }
+.circle4 { left: 0; bottom: 0; }
+
+.container2 .circle1 {
+    -webkit-animation-delay: -1.1s;
+    animation-delay: -1.1s;
+}
+
+.container3 .circle1 {
+    -webkit-animation-delay: -1.0s;
+    animation-delay: -1.0s;
+}
+
+.container1 .circle2 {
+    -webkit-animation-delay: -0.9s;
+    animation-delay: -0.9s;
+}
+
+.container2 .circle2 {
+    -webkit-animation-delay: -0.8s;
+    animation-delay: -0.8s;
+}
+
+.container3 .circle2 {
+    -webkit-animation-delay: -0.7s;
+    animation-delay: -0.7s;
+}
+
+.container1 .circle3 {
+    -webkit-animation-delay: -0.6s;
+    animation-delay: -0.6s;
+}
+
+.container2 .circle3 {
+    -webkit-animation-delay: -0.5s;
+    animation-delay: -0.5s;
+}
+
+.container3 .circle3 {
+    -webkit-animation-delay: -0.4s;
+    animation-delay: -0.4s;
+}
+
+.container1 .circle4 {
+    -webkit-animation-delay: -0.3s;
+    animation-delay: -0.3s;
+}
+
+.container2 .circle4 {
+    -webkit-animation-delay: -0.2s;
+    animation-delay: -0.2s;
+}
+
+.container3 .circle4 {
+    -webkit-animation-delay: -0.1s;
+    animation-delay: -0.1s;
+}
+
+@-webkit-keyframes bouncedelay {
+    0%, 80%, 100% { -webkit-transform: scale(0.0) }
+    40% { -webkit-transform: scale(1.0) }
+}
+
+@keyframes bouncedelay {
+    0%, 80%, 100% {
+        transform: scale(0.0);
+        -webkit-transform: scale(0.0);
+    } 40% {
+          transform: scale(1.0);
+          -webkit-transform: scale(1.0);
+      }
+}

Разница между файлами не показана из-за своего большого размера
+ 8 - 0
src/main/resources/static/css/viewer.min.css


+ 97 - 0
src/main/resources/static/css/zTreeStyle.css

@@ -0,0 +1,97 @@
+/*-------------------------------------
+zTree Style
+
+version:	3.5.19
+author:		Hunter.z
+email:		hunter.z@263.net
+website:	http://code.google.com/p/jquerytree/
+
+-------------------------------------*/
+
+.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}
+.ztree {margin:0; padding:5px; color:#333}
+.ztree li{padding:0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0}
+.ztree li ul{ margin:0; padding:0 0 0 18px}
+.ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;}
+
+.ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:17px; color:#333; background-color: transparent;
+	text-decoration:none; vertical-align:top; display: inline-block}
+.ztree li a:hover {text-decoration:underline}
+.ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}
+.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}
+.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid;
+	opacity:0.8; filter:alpha(opacity=80)}
+.ztree li a.tmpTargetNode_prev {}
+.ztree li a.tmpTargetNode_next {}
+.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;
+	font-size:12px; border:1px #7EC4CC solid; *border:0px}
+.ztree li span {line-height:16px; margin-right:2px}
+.ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle;
+	border:0 none; cursor: pointer;outline:none;
+	background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
+	background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")}
+
+.ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto}
+.ztree li span.button.chk.checkbox_false_full {background-position:0 0}
+.ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px}
+.ztree li span.button.chk.checkbox_false_part {background-position:0 -28px}
+.ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px}
+.ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px}
+.ztree li span.button.chk.checkbox_true_full {background-position:-14px 0}
+.ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px}
+.ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px}
+.ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px}
+.ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px}
+.ztree li span.button.chk.radio_false_full {background-position:-28px 0}
+.ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px}
+.ztree li span.button.chk.radio_false_part {background-position:-28px -28px}
+.ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px}
+.ztree li span.button.chk.radio_false_disable {background-position:-28px -56px}
+.ztree li span.button.chk.radio_true_full {background-position:-42px 0}
+.ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px}
+.ztree li span.button.chk.radio_true_part {background-position:-42px -28px}
+.ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px}
+.ztree li span.button.chk.radio_true_disable {background-position:-42px -56px}
+
+.ztree li span.button.switch {width:18px; height:18px}
+.ztree li span.button.root_open{background-position:-92px -54px}
+.ztree li span.button.root_close{background-position:-74px -54px}
+.ztree li span.button.roots_open{background-position:-92px 0}
+.ztree li span.button.roots_close{background-position:-74px 0}
+.ztree li span.button.center_open{background-position:-92px -18px}
+.ztree li span.button.center_close{background-position:-74px -18px}
+.ztree li span.button.bottom_open{background-position:-92px -36px}
+.ztree li span.button.bottom_close{background-position:-74px -36px}
+.ztree li span.button.noline_open{background-position:-92px -72px}
+.ztree li span.button.noline_close{background-position:-74px -72px}
+.ztree li span.button.root_docu{ background:none;}
+.ztree li span.button.roots_docu{background-position:-56px 0}
+.ztree li span.button.center_docu{background-position:-56px -18px}
+.ztree li span.button.bottom_docu{background-position:-56px -36px}
+.ztree li span.button.noline_docu{ background:none;}
+
+.ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle}
+.ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle}
+.ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; vertical-align:top; *vertical-align:middle}
+.ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle}
+.ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle}
+
+.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}
+
+ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}
+
+span.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;
+	background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
+	background-position:-110px -80px; background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")}
+
+ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}
+.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}
+
+/* level style*/
+/*.ztree li span.button.level0 {
+	display:none;
+}
+.ztree li ul.level0 {
+	padding:0;
+	background:none;
+}*/

BIN
src/main/resources/static/images/sorry.jpg


+ 172 - 0
src/main/resources/static/index.html

@@ -0,0 +1,172 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+    <title>图片预览图</title>
+    <link rel="stylesheet" href="css/viewer.min.css">
+    <link rel="stylesheet" href="css/loading.css">
+    <link rel="stylesheet" href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css">
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.11.1/bootstrap-table.css" />
+    <style type="text/css">
+    </style>
+</head>
+
+<body>
+<h1>文件预览项目接入和测试界面</h1>
+<div class="panel-group" id="accordion">
+    <div class="panel panel-default">
+        <div class="panel-heading">
+            <h4 class="panel-title">
+                <a data-toggle="collapse" data-parent="#accordion"
+                   href="#collapseOne">
+                    接入说明
+                </a>
+            </h4>
+        </div>
+        <div id="collapseOne" class="panel-collapse collapse in">
+            <div class="panel-body">
+                <div>
+                    如果你的项目需要接入文件预览项目,达到对docx、excel、ppt、jpg等文件的预览效果,那么通过在你的项目中加入下面的代码就可以
+                    成功实现:
+                    <pre style="background-color: #2f332a;color: #cccccc">
+                        $scope.openWin = function (fileUrl) {
+                            var url = configuration.previewUrl + 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>
+                    <b>说明:</b>
+                    <p>1.这里的fileUrl即是需要预览的服务器文件,一般是ufile文件</p>
+                    <p>2.只所以使用encodeURIComponent转码是因为ufile文件中可能会存在&等特殊字符,那么如果不转码会被浏览器处理成多参数
+                        这样后台获取的就不是需要预览的文件的全路径了。</p>
+                    <p>3.configuration.previewUrl是需要接入项目中配置文件预览项目的地址的配置
+                        现在开发和测试地址都是:
+                        http://106.75.31.215:8012/onlinePreview?url=服务器(ufile)文件路径</p>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="panel panel-default">
+        <div class="panel-heading">
+            <h4 class="panel-title">
+                <a data-toggle="collapse" data-parent="#accordion"
+                   href="#collapseTwo">
+                    预览测试
+                </a>
+            </h4>
+        </div>
+        <div id="collapseTwo" class="panel-collapse collapse">
+            <div class="panel-body">
+                <p style="color: red;">因为是测试所以一种文件只允许上传一个</p>
+                <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>
+</div>
+
+<div class="loading_container">
+    <div class="spinner">
+        <div class="spinner-container container1">
+            <div class="circle1"></div>
+            <div class="circle2"></div>
+            <div class="circle3"></div>
+            <div class="circle4"></div>
+        </div>
+        <div class="spinner-container container2">
+            <div class="circle1"></div>
+            <div class="circle2"></div>
+            <div class="circle3"></div>
+            <div class="circle4"></div>
+        </div>
+        <div class="spinner-container container3">
+            <div class="circle1"></div>
+            <div class="circle2"></div>
+            <div class="circle3"></div>
+            <div class="circle4"></div>
+        </div>
+    </div>
+</div>
+<script type="text/javascript" src="config.js"></script>
+<script src="js/jquery-3.0.0.min.js" type="text/javascript"></script>
+<script src="https://cdn.bootcss.com/jquery.form/3.09/jquery.form.min.js" type="text/javascript"></script>
+<script src="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/js/bootstrap.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.11.1/bootstrap-table.js"></script>
+<script>
+    function deleteFile(fileName) {
+        $.ajax({
+            url: env_config.server_delete_url + encodeURIComponent(fileName),
+            success: function (data) {
+                // 删除完成,刷新table
+                if (1 == data.code) {
+                    alert(data.msg);
+                }else{
+                    $('#table').bootstrapTable('refresh', {});
+                }
+            },
+            error: function (data) {
+                console.log(data);
+            }
+        })
+    }
+    $(function () {
+        $('#table').bootstrapTable({
+            url: 'listFiles',
+            columns: [{
+                field: 'fileName',
+                title: '文件名'
+            }, {
+                field: 'action',
+                title: '操作'
+            },]
+        }).on('pre-body.bs.table', function (e,data) {
+            // 每个data添加一列用来操作
+            $(data).each(function (index, item) {
+                item.action = "<a class='btn btn-default' target='_blank' href='"+env_config.server_preview_url
+                    + encodeURIComponent(env_config.server_base_url + item.fileName ) +"&needEncode=1'>预览</a>" +
+                    "<a class='btn btn-default' target='_blank' href='javascript:void(0);' onclick='deleteFile(\""+item.fileName+"\")'>删除</a>";
+            });
+            return data;
+        }).on('post-body.bs.table', function (e,data) {
+            return data;
+        });
+
+        /**
+         *
+         */
+        function showLoadingDiv() {
+            var height = window.document.documentElement.clientHeight - 1;
+            $(".loading_container").css("height", height).show();
+        }
+
+        $("#btnsubmit").click(function () {
+            showLoadingDiv();
+            $("#fileUpload").ajaxSubmit({
+                success: function (data) {
+                    // 上传完成,刷新table
+                    if (1 == data.code) {
+                        alert(data.msg);
+                    }else{
+                        $('#table').bootstrapTable('refresh', {});
+                    }
+                    $(".loading_container").hide();
+                },
+                error: function (error) { alert(error); $(".loading_container").hide();},
+                url: 'fileUpload', /*设置post提交到的页面*/
+                type: "post", /*设置表单以post方法提交*/
+                dataType: "json" /*设置返回值类型为文本*/
+            });
+        });
+    });
+</script>
+</body>
+</html>

+ 19 - 0
src/main/resources/static/js/excel.header.js

@@ -0,0 +1,19 @@
+/**创建一个div并固定在底部,将center中的所有a标签放在改div中**/
+$("body").append($("<div>").css({"width":"100%","height":"30px","position":"fixed","top":"0","left":"0"
+    ,"background-color":"rgba(53, 53, 53, 1)","line-height":"30px","font-size":"13px"}).attr("id","excel-header-nav"));
+$("center").css("display", "none");
+var centerChildrenA = $("center").children("a");
+if (centerChildrenA.length === 0) {
+    $("#excel-header-nav").hide();
+}
+$(centerChildrenA).each(function (a, b) {
+    // 获取a标签对应的target的name值,并设置name对应标签的样式以避免锚点标签标题被覆盖
+    var href = $(b).attr("href");
+    var name = href.substr(1);
+    console.log(href + ":" + name);
+    $("[name=" + name + "]").css({"display":"block","padding-top":"14.01px"});
+    $(b).css({"padding":"5px","border-right":"1px solid white","color":"#f9f9f9"});
+    $("#excel-header-nav").append(b);
+});
+/**给所有的table添加class=table table-striped样式**/
+$("table").addClass("table table-striped");

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
src/main/resources/static/js/jquery-3.0.0.min.js


+ 1935 - 0
src/main/resources/static/js/jquery.ztree.core.js

@@ -0,0 +1,1935 @@
+/*
+ * JQuery zTree core v3.5.30
+ * http://treejs.cn/
+ *
+ * Copyright (c) 2010 Hunter.z
+ *
+ * Licensed same as jquery - MIT License
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * email: hunter.z@263.net
+ * Date: 2017-11-11
+ */
+(function ($) {
+    var settings = {}, roots = {}, caches = {},
+        //default consts of core
+        _consts = {
+            className: {
+                BUTTON: "button",
+                LEVEL: "level",
+                ICO_LOADING: "ico_loading",
+                SWITCH: "switch",
+                NAME: 'node_name'
+            },
+            event: {
+                NODECREATED: "ztree_nodeCreated",
+                CLICK: "ztree_click",
+                EXPAND: "ztree_expand",
+                COLLAPSE: "ztree_collapse",
+                ASYNC_SUCCESS: "ztree_async_success",
+                ASYNC_ERROR: "ztree_async_error",
+                REMOVE: "ztree_remove",
+                SELECTED: "ztree_selected",
+                UNSELECTED: "ztree_unselected"
+            },
+            id: {
+                A: "_a",
+                ICON: "_ico",
+                SPAN: "_span",
+                SWITCH: "_switch",
+                UL: "_ul"
+            },
+            line: {
+                ROOT: "root",
+                ROOTS: "roots",
+                CENTER: "center",
+                BOTTOM: "bottom",
+                NOLINE: "noline",
+                LINE: "line"
+            },
+            folder: {
+                OPEN: "open",
+                CLOSE: "close",
+                DOCU: "docu"
+            },
+            node: {
+                CURSELECTED: "curSelectedNode"
+            }
+        },
+        //default setting of core
+        _setting = {
+            treeId: "",
+            treeObj: null,
+            view: {
+                addDiyDom: null,
+                autoCancelSelected: true,
+                dblClickExpand: true,
+                expandSpeed: "fast",
+                fontCss: {},
+                nameIsHTML: false,
+                selectedMulti: true,
+                showIcon: true,
+                showLine: true,
+                showTitle: true,
+                txtSelectedEnable: false
+            },
+            data: {
+                key: {
+                    children: "children",
+                    name: "name",
+                    title: "",
+                    url: "url",
+                    icon: "icon"
+                },
+                simpleData: {
+                    enable: false,
+                    idKey: "id",
+                    pIdKey: "pId",
+                    rootPId: null
+                },
+                keep: {
+                    parent: false,
+                    leaf: false
+                }
+            },
+            async: {
+                enable: false,
+                contentType: "application/x-www-form-urlencoded",
+                type: "post",
+                dataType: "text",
+                url: "",
+                autoParam: [],
+                otherParam: [],
+                dataFilter: null
+            },
+            callback: {
+                beforeAsync: null,
+                beforeClick: null,
+                beforeDblClick: null,
+                beforeRightClick: null,
+                beforeMouseDown: null,
+                beforeMouseUp: null,
+                beforeExpand: null,
+                beforeCollapse: null,
+                beforeRemove: null,
+
+                onAsyncError: null,
+                onAsyncSuccess: null,
+                onNodeCreated: null,
+                onClick: null,
+                onDblClick: null,
+                onRightClick: null,
+                onMouseDown: null,
+                onMouseUp: null,
+                onExpand: null,
+                onCollapse: null,
+                onRemove: null
+            }
+        },
+        //default root of core
+        //zTree use root to save full data
+        _initRoot = function (setting) {
+            var r = data.getRoot(setting);
+            if (!r) {
+                r = {};
+                data.setRoot(setting, r);
+            }
+            r[setting.data.key.children] = [];
+            r.expandTriggerFlag = false;
+            r.curSelectedList = [];
+            r.noSelection = true;
+            r.createdNodes = [];
+            r.zId = 0;
+            r._ver = (new Date()).getTime();
+        },
+        //default cache of core
+        _initCache = function (setting) {
+            var c = data.getCache(setting);
+            if (!c) {
+                c = {};
+                data.setCache(setting, c);
+            }
+            c.nodes = [];
+            c.doms = [];
+        },
+        //default bindEvent of core
+        _bindEvent = function (setting) {
+            var o = setting.treeObj,
+                c = consts.event;
+            o.bind(c.NODECREATED, function (event, treeId, node) {
+                tools.apply(setting.callback.onNodeCreated, [event, treeId, node]);
+            });
+
+            o.bind(c.CLICK, function (event, srcEvent, treeId, node, clickFlag) {
+                tools.apply(setting.callback.onClick, [srcEvent, treeId, node, clickFlag]);
+            });
+
+            o.bind(c.EXPAND, function (event, treeId, node) {
+                tools.apply(setting.callback.onExpand, [event, treeId, node]);
+            });
+
+            o.bind(c.COLLAPSE, function (event, treeId, node) {
+                tools.apply(setting.callback.onCollapse, [event, treeId, node]);
+            });
+
+            o.bind(c.ASYNC_SUCCESS, function (event, treeId, node, msg) {
+                tools.apply(setting.callback.onAsyncSuccess, [event, treeId, node, msg]);
+            });
+
+            o.bind(c.ASYNC_ERROR, function (event, treeId, node, XMLHttpRequest, textStatus, errorThrown) {
+                tools.apply(setting.callback.onAsyncError, [event, treeId, node, XMLHttpRequest, textStatus, errorThrown]);
+            });
+
+            o.bind(c.REMOVE, function (event, treeId, treeNode) {
+                tools.apply(setting.callback.onRemove, [event, treeId, treeNode]);
+            });
+
+            o.bind(c.SELECTED, function (event, treeId, node) {
+                tools.apply(setting.callback.onSelected, [treeId, node]);
+            });
+            o.bind(c.UNSELECTED, function (event, treeId, node) {
+                tools.apply(setting.callback.onUnSelected, [treeId, node]);
+            });
+        },
+        _unbindEvent = function (setting) {
+            var o = setting.treeObj,
+                c = consts.event;
+            o.unbind(c.NODECREATED)
+                .unbind(c.CLICK)
+                .unbind(c.EXPAND)
+                .unbind(c.COLLAPSE)
+                .unbind(c.ASYNC_SUCCESS)
+                .unbind(c.ASYNC_ERROR)
+                .unbind(c.REMOVE)
+                .unbind(c.SELECTED)
+                .unbind(c.UNSELECTED);
+        },
+        //default event proxy of core
+        _eventProxy = function (event) {
+            var target = event.target,
+                setting = data.getSetting(event.data.treeId),
+                tId = "", node = null,
+                nodeEventType = "", treeEventType = "",
+                nodeEventCallback = null, treeEventCallback = null,
+                tmp = null;
+
+            if (tools.eqs(event.type, "mousedown")) {
+                treeEventType = "mousedown";
+            } else if (tools.eqs(event.type, "mouseup")) {
+                treeEventType = "mouseup";
+            } else if (tools.eqs(event.type, "contextmenu")) {
+                treeEventType = "contextmenu";
+            } else if (tools.eqs(event.type, "click")) {
+                if (tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.SWITCH) !== null) {
+                    tId = tools.getNodeMainDom(target).id;
+                    nodeEventType = "switchNode";
+                } else {
+                    tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]);
+                    if (tmp) {
+                        tId = tools.getNodeMainDom(tmp).id;
+                        nodeEventType = "clickNode";
+                    }
+                }
+            } else if (tools.eqs(event.type, "dblclick")) {
+                treeEventType = "dblclick";
+                tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]);
+                if (tmp) {
+                    tId = tools.getNodeMainDom(tmp).id;
+                    nodeEventType = "switchNode";
+                }
+            }
+            if (treeEventType.length > 0 && tId.length == 0) {
+                tmp = tools.getMDom(setting, target, [{tagName: "a", attrName: "treeNode" + consts.id.A}]);
+                if (tmp) {
+                    tId = tools.getNodeMainDom(tmp).id;
+                }
+            }
+            // event to node
+            if (tId.length > 0) {
+                node = data.getNodeCache(setting, tId);
+                switch (nodeEventType) {
+                    case "switchNode" :
+                        if (!node.isParent) {
+                            nodeEventType = "";
+                        } else if (tools.eqs(event.type, "click")
+                            || (tools.eqs(event.type, "dblclick") && tools.apply(setting.view.dblClickExpand, [setting.treeId, node], setting.view.dblClickExpand))) {
+                            nodeEventCallback = handler.onSwitchNode;
+                        } else {
+                            nodeEventType = "";
+                        }
+                        break;
+                    case "clickNode" :
+                        nodeEventCallback = handler.onClickNode;
+                        break;
+                }
+            }
+            // event to zTree
+            switch (treeEventType) {
+                case "mousedown" :
+                    treeEventCallback = handler.onZTreeMousedown;
+                    break;
+                case "mouseup" :
+                    treeEventCallback = handler.onZTreeMouseup;
+                    break;
+                case "dblclick" :
+                    treeEventCallback = handler.onZTreeDblclick;
+                    break;
+                case "contextmenu" :
+                    treeEventCallback = handler.onZTreeContextmenu;
+                    break;
+            }
+            var proxyResult = {
+                stop: false,
+                node: node,
+                nodeEventType: nodeEventType,
+                nodeEventCallback: nodeEventCallback,
+                treeEventType: treeEventType,
+                treeEventCallback: treeEventCallback
+            };
+            return proxyResult
+        },
+        //default init node of core
+        _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {
+            if (!n) return;
+            var r = data.getRoot(setting),
+                childKey = setting.data.key.children;
+            n.level = level;
+            n.tId = setting.treeId + "_" + (++r.zId);
+            n.parentTId = parentNode ? parentNode.tId : null;
+            n.open = (typeof n.open == "string") ? tools.eqs(n.open, "true") : !!n.open;
+            if (n[childKey] && n[childKey].length > 0) {
+                n.isParent = true;
+                n.zAsync = true;
+            } else {
+                n.isParent = (typeof n.isParent == "string") ? tools.eqs(n.isParent, "true") : !!n.isParent;
+                n.open = (n.isParent && !setting.async.enable) ? n.open : false;
+                n.zAsync = !n.isParent;
+            }
+            n.isFirstNode = isFirstNode;
+            n.isLastNode = isLastNode;
+            n.getParentNode = function () {
+                return data.getNodeCache(setting, n.parentTId);
+            };
+            n.getPreNode = function () {
+                return data.getPreNode(setting, n);
+            };
+            n.getNextNode = function () {
+                return data.getNextNode(setting, n);
+            };
+            n.getIndex = function () {
+                return data.getNodeIndex(setting, n);
+            };
+            n.getPath = function () {
+                return data.getNodePath(setting, n);
+            };
+            n.isAjaxing = false;
+            data.fixPIdKeyValue(setting, n);
+        },
+        _init = {
+            bind: [_bindEvent],
+            unbind: [_unbindEvent],
+            caches: [_initCache],
+            nodes: [_initNode],
+            proxys: [_eventProxy],
+            roots: [_initRoot],
+            beforeA: [],
+            afterA: [],
+            innerBeforeA: [],
+            innerAfterA: [],
+            zTreeTools: []
+        },
+        //method of operate data
+        data = {
+            addNodeCache: function (setting, node) {
+                data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = node;
+            },
+            getNodeCacheId: function (tId) {
+                return tId.substring(tId.lastIndexOf("_") + 1);
+            },
+            addAfterA: function (afterA) {
+                _init.afterA.push(afterA);
+            },
+            addBeforeA: function (beforeA) {
+                _init.beforeA.push(beforeA);
+            },
+            addInnerAfterA: function (innerAfterA) {
+                _init.innerAfterA.push(innerAfterA);
+            },
+            addInnerBeforeA: function (innerBeforeA) {
+                _init.innerBeforeA.push(innerBeforeA);
+            },
+            addInitBind: function (bindEvent) {
+                _init.bind.push(bindEvent);
+            },
+            addInitUnBind: function (unbindEvent) {
+                _init.unbind.push(unbindEvent);
+            },
+            addInitCache: function (initCache) {
+                _init.caches.push(initCache);
+            },
+            addInitNode: function (initNode) {
+                _init.nodes.push(initNode);
+            },
+            addInitProxy: function (initProxy, isFirst) {
+                if (!!isFirst) {
+                    _init.proxys.splice(0, 0, initProxy);
+                } else {
+                    _init.proxys.push(initProxy);
+                }
+            },
+            addInitRoot: function (initRoot) {
+                _init.roots.push(initRoot);
+            },
+            addNodesData: function (setting, parentNode, index, nodes) {
+                var childKey = setting.data.key.children, params;
+                if (!parentNode[childKey]) {
+                    parentNode[childKey] = [];
+                    index = -1;
+                } else if (index >= parentNode[childKey].length) {
+                    index = -1;
+                }
+
+                if (parentNode[childKey].length > 0 && index === 0) {
+                    parentNode[childKey][0].isFirstNode = false;
+                    view.setNodeLineIcos(setting, parentNode[childKey][0]);
+                } else if (parentNode[childKey].length > 0 && index < 0) {
+                    parentNode[childKey][parentNode[childKey].length - 1].isLastNode = false;
+                    view.setNodeLineIcos(setting, parentNode[childKey][parentNode[childKey].length - 1]);
+                }
+                parentNode.isParent = true;
+
+                if (index < 0) {
+                    parentNode[childKey] = parentNode[childKey].concat(nodes);
+                } else {
+                    params = [index, 0].concat(nodes);
+                    parentNode[childKey].splice.apply(parentNode[childKey], params);
+                }
+            },
+            addSelectedNode: function (setting, node) {
+                var root = data.getRoot(setting);
+                if (!data.isSelectedNode(setting, node)) {
+                    root.curSelectedList.push(node);
+                }
+            },
+            addCreatedNode: function (setting, node) {
+                if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {
+                    var root = data.getRoot(setting);
+                    root.createdNodes.push(node);
+                }
+            },
+            addZTreeTools: function (zTreeTools) {
+                _init.zTreeTools.push(zTreeTools);
+            },
+            exSetting: function (s) {
+                $.extend(true, _setting, s);
+            },
+            fixPIdKeyValue: function (setting, node) {
+                if (setting.data.simpleData.enable) {
+                    node[setting.data.simpleData.pIdKey] = node.parentTId ? node.getParentNode()[setting.data.simpleData.idKey] : setting.data.simpleData.rootPId;
+                }
+            },
+            getAfterA: function (setting, node, array) {
+                for (var i = 0, j = _init.afterA.length; i < j; i++) {
+                    _init.afterA[i].apply(this, arguments);
+                }
+            },
+            getBeforeA: function (setting, node, array) {
+                for (var i = 0, j = _init.beforeA.length; i < j; i++) {
+                    _init.beforeA[i].apply(this, arguments);
+                }
+            },
+            getInnerAfterA: function (setting, node, array) {
+                for (var i = 0, j = _init.innerAfterA.length; i < j; i++) {
+                    _init.innerAfterA[i].apply(this, arguments);
+                }
+            },
+            getInnerBeforeA: function (setting, node, array) {
+                for (var i = 0, j = _init.innerBeforeA.length; i < j; i++) {
+                    _init.innerBeforeA[i].apply(this, arguments);
+                }
+            },
+            getCache: function (setting) {
+                return caches[setting.treeId];
+            },
+            getNodeIndex: function (setting, node) {
+                if (!node) return null;
+                var childKey = setting.data.key.children,
+                    p = node.parentTId ? node.getParentNode() : data.getRoot(setting);
+                for (var i = 0, l = p[childKey].length - 1; i <= l; i++) {
+                    if (p[childKey][i] === node) {
+                        return i;
+                    }
+                }
+                return -1;
+            },
+            getNextNode: function (setting, node) {
+                if (!node) return null;
+                var childKey = setting.data.key.children,
+                    p = node.parentTId ? node.getParentNode() : data.getRoot(setting);
+                for (var i = 0, l = p[childKey].length - 1; i <= l; i++) {
+                    if (p[childKey][i] === node) {
+                        return (i == l ? null : p[childKey][i + 1]);
+                    }
+                }
+                return null;
+            },
+            getNodeByParam: function (setting, nodes, key, value) {
+                if (!nodes || !key) return null;
+                var childKey = setting.data.key.children;
+                for (var i = 0, l = nodes.length; i < l; i++) {
+                    if (nodes[i][key] == value) {
+                        return nodes[i];
+                    }
+                    var tmp = data.getNodeByParam(setting, nodes[i][childKey], key, value);
+                    if (tmp) return tmp;
+                }
+                return null;
+            },
+            getNodeCache: function (setting, tId) {
+                if (!tId) return null;
+                var n = caches[setting.treeId].nodes[data.getNodeCacheId(tId)];
+                return n ? n : null;
+            },
+            getNodeName: function (setting, node) {
+                var nameKey = setting.data.key.name;
+                return "" + node[nameKey];
+            },
+            getNodePath: function (setting, node) {
+                if (!node) return null;
+
+                var path;
+                if (node.parentTId) {
+                    path = node.getParentNode().getPath();
+                } else {
+                    path = [];
+                }
+
+                if (path) {
+                    path.push(node);
+                }
+
+                return path;
+            },
+            getNodeTitle: function (setting, node) {
+                var t = setting.data.key.title === "" ? setting.data.key.name : setting.data.key.title;
+                return "" + node[t];
+            },
+            getNodes: function (setting) {
+                return data.getRoot(setting)[setting.data.key.children];
+            },
+            getNodesByParam: function (setting, nodes, key, value) {
+                if (!nodes || !key) return [];
+                var childKey = setting.data.key.children,
+                    result = [];
+                for (var i = 0, l = nodes.length; i < l; i++) {
+                    if (nodes[i][key] == value) {
+                        result.push(nodes[i]);
+                    }
+                    result = result.concat(data.getNodesByParam(setting, nodes[i][childKey], key, value));
+                }
+                return result;
+            },
+            getNodesByParamFuzzy: function (setting, nodes, key, value) {
+                if (!nodes || !key) return [];
+                var childKey = setting.data.key.children,
+                    result = [];
+                value = value.toLowerCase();
+                for (var i = 0, l = nodes.length; i < l; i++) {
+                    if (typeof nodes[i][key] == "string" && nodes[i][key].toLowerCase().indexOf(value) > -1) {
+                        result.push(nodes[i]);
+                    }
+                    result = result.concat(data.getNodesByParamFuzzy(setting, nodes[i][childKey], key, value));
+                }
+                return result;
+            },
+            getNodesByFilter: function (setting, nodes, filter, isSingle, invokeParam) {
+                if (!nodes) return (isSingle ? null : []);
+                var childKey = setting.data.key.children,
+                    result = isSingle ? null : [];
+                for (var i = 0, l = nodes.length; i < l; i++) {
+                    if (tools.apply(filter, [nodes[i], invokeParam], false)) {
+                        if (isSingle) {
+                            return nodes[i];
+                        }
+                        result.push(nodes[i]);
+                    }
+                    var tmpResult = data.getNodesByFilter(setting, nodes[i][childKey], filter, isSingle, invokeParam);
+                    if (isSingle && !!tmpResult) {
+                        return tmpResult;
+                    }
+                    result = isSingle ? tmpResult : result.concat(tmpResult);
+                }
+                return result;
+            },
+            getPreNode: function (setting, node) {
+                if (!node) return null;
+                var childKey = setting.data.key.children,
+                    p = node.parentTId ? node.getParentNode() : data.getRoot(setting);
+                for (var i = 0, l = p[childKey].length; i < l; i++) {
+                    if (p[childKey][i] === node) {
+                        return (i == 0 ? null : p[childKey][i - 1]);
+                    }
+                }
+                return null;
+            },
+            getRoot: function (setting) {
+                return setting ? roots[setting.treeId] : null;
+            },
+            getRoots: function () {
+                return roots;
+            },
+            getSetting: function (treeId) {
+                return settings[treeId];
+            },
+            getSettings: function () {
+                return settings;
+            },
+            getZTreeTools: function (treeId) {
+                var r = this.getRoot(this.getSetting(treeId));
+                return r ? r.treeTools : null;
+            },
+            initCache: function (setting) {
+                for (var i = 0, j = _init.caches.length; i < j; i++) {
+                    _init.caches[i].apply(this, arguments);
+                }
+            },
+            initNode: function (setting, level, node, parentNode, preNode, nextNode) {
+                for (var i = 0, j = _init.nodes.length; i < j; i++) {
+                    _init.nodes[i].apply(this, arguments);
+                }
+            },
+            initRoot: function (setting) {
+                for (var i = 0, j = _init.roots.length; i < j; i++) {
+                    _init.roots[i].apply(this, arguments);
+                }
+            },
+            isSelectedNode: function (setting, node) {
+                var root = data.getRoot(setting);
+                for (var i = 0, j = root.curSelectedList.length; i < j; i++) {
+                    if (node === root.curSelectedList[i]) return true;
+                }
+                return false;
+            },
+            removeNodeCache: function (setting, node) {
+                var childKey = setting.data.key.children;
+                if (node[childKey]) {
+                    for (var i = 0, l = node[childKey].length; i < l; i++) {
+                        data.removeNodeCache(setting, node[childKey][i]);
+                    }
+                }
+                data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = null;
+            },
+            removeSelectedNode: function (setting, node) {
+                var root = data.getRoot(setting);
+                for (var i = 0, j = root.curSelectedList.length; i < j; i++) {
+                    if (node === root.curSelectedList[i] || !data.getNodeCache(setting, root.curSelectedList[i].tId)) {
+                        root.curSelectedList.splice(i, 1);
+                        setting.treeObj.trigger(consts.event.UNSELECTED, [setting.treeId, node]);
+                        i--;
+                        j--;
+                    }
+                }
+            },
+            setCache: function (setting, cache) {
+                caches[setting.treeId] = cache;
+            },
+            setRoot: function (setting, root) {
+                roots[setting.treeId] = root;
+            },
+            setZTreeTools: function (setting, zTreeTools) {
+                for (var i = 0, j = _init.zTreeTools.length; i < j; i++) {
+                    _init.zTreeTools[i].apply(this, arguments);
+                }
+            },
+            transformToArrayFormat: function (setting, nodes) {
+                if (!nodes) return [];
+                var childKey = setting.data.key.children,
+                    r = [];
+                if (tools.isArray(nodes)) {
+                    for (var i = 0, l = nodes.length; i < l; i++) {
+                        r.push(nodes[i]);
+                        if (nodes[i][childKey])
+                            r = r.concat(data.transformToArrayFormat(setting, nodes[i][childKey]));
+                    }
+                } else {
+                    r.push(nodes);
+                    if (nodes[childKey])
+                        r = r.concat(data.transformToArrayFormat(setting, nodes[childKey]));
+                }
+                return r;
+            },
+            transformTozTreeFormat: function (setting, sNodes) {
+                var i, l,
+                    key = setting.data.simpleData.idKey,
+                    parentKey = setting.data.simpleData.pIdKey,
+                    childKey = setting.data.key.children;
+                if (!key || key == "" || !sNodes) return [];
+
+                if (tools.isArray(sNodes)) {
+                    var r = [];
+                    var tmpMap = {};
+                    for (i = 0, l = sNodes.length; i < l; i++) {
+                        tmpMap[sNodes[i][key]] = sNodes[i];
+                    }
+                    for (i = 0, l = sNodes.length; i < l; i++) {
+                        if (tmpMap[sNodes[i][parentKey]] && sNodes[i][key] != sNodes[i][parentKey]) {
+                            if (!tmpMap[sNodes[i][parentKey]][childKey])
+                                tmpMap[sNodes[i][parentKey]][childKey] = [];
+                            tmpMap[sNodes[i][parentKey]][childKey].push(sNodes[i]);
+                        } else {
+                            r.push(sNodes[i]);
+                        }
+                    }
+                    return r;
+                } else {
+                    return [sNodes];
+                }
+            }
+        },
+        //method of event proxy
+        event = {
+            bindEvent: function (setting) {
+                for (var i = 0, j = _init.bind.length; i < j; i++) {
+                    _init.bind[i].apply(this, arguments);
+                }
+            },
+            unbindEvent: function (setting) {
+                for (var i = 0, j = _init.unbind.length; i < j; i++) {
+                    _init.unbind[i].apply(this, arguments);
+                }
+            },
+            bindTree: function (setting) {
+                var eventParam = {
+                        treeId: setting.treeId
+                    },
+                    o = setting.treeObj;
+                if (!setting.view.txtSelectedEnable) {
+                    // for can't select text
+                    o.bind('selectstart', handler.onSelectStart).css({
+                        "-moz-user-select": "-moz-none"
+                    });
+                }
+                o.bind('click', eventParam, event.proxy);
+                o.bind('dblclick', eventParam, event.proxy);
+                o.bind('mouseover', eventParam, event.proxy);
+                o.bind('mouseout', eventParam, event.proxy);
+                o.bind('mousedown', eventParam, event.proxy);
+                o.bind('mouseup', eventParam, event.proxy);
+                o.bind('contextmenu', eventParam, event.proxy);
+            },
+            unbindTree: function (setting) {
+                var o = setting.treeObj;
+                o.unbind('selectstart', handler.onSelectStart)
+                    .unbind('click', event.proxy)
+                    .unbind('dblclick', event.proxy)
+                    .unbind('mouseover', event.proxy)
+                    .unbind('mouseout', event.proxy)
+                    .unbind('mousedown', event.proxy)
+                    .unbind('mouseup', event.proxy)
+                    .unbind('contextmenu', event.proxy);
+            },
+            doProxy: function (e) {
+                var results = [];
+                for (var i = 0, j = _init.proxys.length; i < j; i++) {
+                    var proxyResult = _init.proxys[i].apply(this, arguments);
+                    results.push(proxyResult);
+                    if (proxyResult.stop) {
+                        break;
+                    }
+                }
+                return results;
+            },
+            proxy: function (e) {
+                var setting = data.getSetting(e.data.treeId);
+                if (!tools.uCanDo(setting, e)) return true;
+                var results = event.doProxy(e),
+                    r = true, x = false;
+                for (var i = 0, l = results.length; i < l; i++) {
+                    var proxyResult = results[i];
+                    if (proxyResult.nodeEventCallback) {
+                        x = true;
+                        r = proxyResult.nodeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;
+                    }
+                    if (proxyResult.treeEventCallback) {
+                        x = true;
+                        r = proxyResult.treeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;
+                    }
+                }
+                return r;
+            }
+        },
+        //method of event handler
+        handler = {
+            onSwitchNode: function (event, node) {
+                var setting = data.getSetting(event.data.treeId);
+                if (node.open) {
+                    if (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false) return true;
+                    data.getRoot(setting).expandTriggerFlag = true;
+                    view.switchNode(setting, node);
+                } else {
+                    if (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false) return true;
+                    data.getRoot(setting).expandTriggerFlag = true;
+                    view.switchNode(setting, node);
+                }
+                return true;
+            },
+            onClickNode: function (event, node) {
+                var setting = data.getSetting(event.data.treeId),
+                    clickFlag = ( (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey)) && data.isSelectedNode(setting, node)) ? 0 : (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey) && setting.view.selectedMulti) ? 2 : 1;
+                if (tools.apply(setting.callback.beforeClick, [setting.treeId, node, clickFlag], true) == false) return true;
+                if (clickFlag === 0) {
+                    view.cancelPreSelectedNode(setting, node);
+                } else {
+                    view.selectNode(setting, node, clickFlag === 2);
+                }
+                setting.treeObj.trigger(consts.event.CLICK, [event, setting.treeId, node, clickFlag]);
+                return true;
+            },
+            onZTreeMousedown: function (event, node) {
+                var setting = data.getSetting(event.data.treeId);
+                if (tools.apply(setting.callback.beforeMouseDown, [setting.treeId, node], true)) {
+                    tools.apply(setting.callback.onMouseDown, [event, setting.treeId, node]);
+                }
+                return true;
+            },
+            onZTreeMouseup: function (event, node) {
+                var setting = data.getSetting(event.data.treeId);
+                if (tools.apply(setting.callback.beforeMouseUp, [setting.treeId, node], true)) {
+                    tools.apply(setting.callback.onMouseUp, [event, setting.treeId, node]);
+                }
+                return true;
+            },
+            onZTreeDblclick: function (event, node) {
+                var setting = data.getSetting(event.data.treeId);
+                if (tools.apply(setting.callback.beforeDblClick, [setting.treeId, node], true)) {
+                    tools.apply(setting.callback.onDblClick, [event, setting.treeId, node]);
+                }
+                return true;
+            },
+            onZTreeContextmenu: function (event, node) {
+                var setting = data.getSetting(event.data.treeId);
+                if (tools.apply(setting.callback.beforeRightClick, [setting.treeId, node], true)) {
+                    tools.apply(setting.callback.onRightClick, [event, setting.treeId, node]);
+                }
+                return (typeof setting.callback.onRightClick) != "function";
+            },
+            onSelectStart: function (e) {
+                var n = e.originalEvent.srcElement.nodeName.toLowerCase();
+                return (n === "input" || n === "textarea" );
+            }
+        },
+        //method of tools for zTree
+        tools = {
+            apply: function (fun, param, defaultValue) {
+                if ((typeof fun) == "function") {
+                    return fun.apply(zt, param ? param : []);
+                }
+                return defaultValue;
+            },
+            canAsync: function (setting, node) {
+                var childKey = setting.data.key.children;
+                return (setting.async.enable && node && node.isParent && !(node.zAsync || (node[childKey] && node[childKey].length > 0)));
+            },
+            clone: function (obj) {
+                if (obj === null) return null;
+                var o = tools.isArray(obj) ? [] : {};
+                for (var i in obj) {
+                    o[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === "object" ? tools.clone(obj[i]) : obj[i]);
+                }
+                return o;
+            },
+            eqs: function (str1, str2) {
+                return str1.toLowerCase() === str2.toLowerCase();
+            },
+            isArray: function (arr) {
+                return Object.prototype.toString.apply(arr) === "[object Array]";
+            },
+            isElement: function (o) {
+                return (
+                    typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
+                        o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string"
+                );
+            },
+            $: function (node, exp, setting) {
+                if (!!exp && typeof exp != "string") {
+                    setting = exp;
+                    exp = "";
+                }
+                if (typeof node == "string") {
+                    return $(node, setting ? setting.treeObj.get(0).ownerDocument : null);
+                } else {
+                    return $("#" + node.tId + exp, setting ? setting.treeObj : null);
+                }
+            },
+            getMDom: function (setting, curDom, targetExpr) {
+                if (!curDom) return null;
+                while (curDom && curDom.id !== setting.treeId) {
+                    for (var i = 0, l = targetExpr.length; curDom.tagName && i < l; i++) {
+                        if (tools.eqs(curDom.tagName, targetExpr[i].tagName) && curDom.getAttribute(targetExpr[i].attrName) !== null) {
+                            return curDom;
+                        }
+                    }
+                    curDom = curDom.parentNode;
+                }
+                return null;
+            },
+            getNodeMainDom: function (target) {
+                return ($(target).parent("li").get(0) || $(target).parentsUntil("li").parent().get(0));
+            },
+            isChildOrSelf: function (dom, parentId) {
+                return ( $(dom).closest("#" + parentId).length > 0 );
+            },
+            uCanDo: function (setting, e) {
+                return true;
+            }
+        },
+        //method of operate ztree dom
+        view = {
+            addNodes: function (setting, parentNode, index, newNodes, isSilent) {
+                if (setting.data.keep.leaf && parentNode && !parentNode.isParent) {
+                    return;
+                }
+                if (!tools.isArray(newNodes)) {
+                    newNodes = [newNodes];
+                }
+                if (setting.data.simpleData.enable) {
+                    newNodes = data.transformTozTreeFormat(setting, newNodes);
+                }
+                if (parentNode) {
+                    var target_switchObj = $$(parentNode, consts.id.SWITCH, setting),
+                        target_icoObj = $$(parentNode, consts.id.ICON, setting),
+                        target_ulObj = $$(parentNode, consts.id.UL, setting);
+
+                    if (!parentNode.open) {
+                        view.replaceSwitchClass(parentNode, target_switchObj, consts.folder.CLOSE);
+                        view.replaceIcoClass(parentNode, target_icoObj, consts.folder.CLOSE);
+                        parentNode.open = false;
+                        target_ulObj.css({
+                            "display": "none"
+                        });
+                    }
+
+                    data.addNodesData(setting, parentNode, index, newNodes);
+                    view.createNodes(setting, parentNode.level + 1, newNodes, parentNode, index);
+                    if (!isSilent) {
+                        view.expandCollapseParentNode(setting, parentNode, true);
+                    }
+                } else {
+                    data.addNodesData(setting, data.getRoot(setting), index, newNodes);
+                    view.createNodes(setting, 0, newNodes, null, index);
+                }
+            },
+            appendNodes: function (setting, level, nodes, parentNode, index, initFlag, openFlag) {
+                if (!nodes) return [];
+                var html = [],
+                    childKey = setting.data.key.children;
+
+                var tmpPNode = (parentNode) ? parentNode : data.getRoot(setting),
+                    tmpPChild = tmpPNode[childKey],
+                    isFirstNode, isLastNode;
+
+                if (!tmpPChild || index >= tmpPChild.length - nodes.length) {
+                    index = -1;
+                }
+
+                for (var i = 0, l = nodes.length; i < l; i++) {
+                    var node = nodes[i];
+                    if (initFlag) {
+                        isFirstNode = ((index === 0 || tmpPChild.length == nodes.length) && (i == 0));
+                        isLastNode = (index < 0 && i == (nodes.length - 1));
+                        data.initNode(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag);
+                        data.addNodeCache(setting, node);
+                    }
+
+                    var childHtml = [];
+                    if (node[childKey] && node[childKey].length > 0) {
+                        //make child html first, because checkType
+                        childHtml = view.appendNodes(setting, level + 1, node[childKey], node, -1, initFlag, openFlag && node.open);
+                    }
+                    if (openFlag) {
+
+                        view.makeDOMNodeMainBefore(html, setting, node);
+                        view.makeDOMNodeLine(html, setting, node);
+                        data.getBeforeA(setting, node, html);
+                        view.makeDOMNodeNameBefore(html, setting, node);
+                        data.getInnerBeforeA(setting, node, html);
+                        view.makeDOMNodeIcon(html, setting, node);
+                        data.getInnerAfterA(setting, node, html);
+                        view.makeDOMNodeNameAfter(html, setting, node);
+                        data.getAfterA(setting, node, html);
+                        if (node.isParent && node.open) {
+                            view.makeUlHtml(setting, node, html, childHtml.join(''));
+                        }
+                        view.makeDOMNodeMainAfter(html, setting, node);
+                        data.addCreatedNode(setting, node);
+                    }
+                }
+                return html;
+            },
+            appendParentULDom: function (setting, node) {
+                var html = [],
+                    nObj = $$(node, setting);
+                if (!nObj.get(0) && !!node.parentTId) {
+                    view.appendParentULDom(setting, node.getParentNode());
+                    nObj = $$(node, setting);
+                }
+                var ulObj = $$(node, consts.id.UL, setting);
+                if (ulObj.get(0)) {
+                    ulObj.remove();
+                }
+                var childKey = setting.data.key.children,
+                    childHtml = view.appendNodes(setting, node.level + 1, node[childKey], node, -1, false, true);
+                view.makeUlHtml(setting, node, html, childHtml.join(''));
+                nObj.append(html.join(''));
+            },
+            asyncNode: function (setting, node, isSilent, callback) {
+                var i, l;
+                if (node && !node.isParent) {
+                    tools.apply(callback);
+                    return false;
+                } else if (node && node.isAjaxing) {
+                    return false;
+                } else if (tools.apply(setting.callback.beforeAsync, [setting.treeId, node], true) == false) {
+                    tools.apply(callback);
+                    return false;
+                }
+                if (node) {
+                    node.isAjaxing = true;
+                    var icoObj = $$(node, consts.id.ICON, setting);
+                    icoObj.attr({"style": "", "class": consts.className.BUTTON + " " + consts.className.ICO_LOADING});
+                }
+
+                var tmpParam = {};
+                for (i = 0, l = setting.async.autoParam.length; node && i < l; i++) {
+                    var pKey = setting.async.autoParam[i].split("="), spKey = pKey;
+                    if (pKey.length > 1) {
+                        spKey = pKey[1];
+                        pKey = pKey[0];
+                    }
+                    tmpParam[spKey] = node[pKey];
+                }
+                if (tools.isArray(setting.async.otherParam)) {
+                    for (i = 0, l = setting.async.otherParam.length; i < l; i += 2) {
+                        tmpParam[setting.async.otherParam[i]] = setting.async.otherParam[i + 1];
+                    }
+                } else {
+                    for (var p in setting.async.otherParam) {
+                        tmpParam[p] = setting.async.otherParam[p];
+                    }
+                }
+
+                var _tmpV = data.getRoot(setting)._ver;
+                $.ajax({
+                    contentType: setting.async.contentType,
+                    cache: false,
+                    type: setting.async.type,
+                    url: tools.apply(setting.async.url, [setting.treeId, node], setting.async.url),
+                    data: setting.async.contentType.indexOf('application/json') > -1 ? JSON.stringify(tmpParam) : tmpParam,
+                    dataType: setting.async.dataType,
+                    success: function (msg) {
+                        if (_tmpV != data.getRoot(setting)._ver) {
+                            return;
+                        }
+                        var newNodes = [];
+                        try {
+                            if (!msg || msg.length == 0) {
+                                newNodes = [];
+                            } else if (typeof msg == "string") {
+                                newNodes = eval("(" + msg + ")");
+                            } else {
+                                newNodes = msg;
+                            }
+                        } catch (err) {
+                            newNodes = msg;
+                        }
+
+                        if (node) {
+                            node.isAjaxing = null;
+                            node.zAsync = true;
+                        }
+                        view.setNodeLineIcos(setting, node);
+                        if (newNodes && newNodes !== "") {
+                            newNodes = tools.apply(setting.async.dataFilter, [setting.treeId, node, newNodes], newNodes);
+                            view.addNodes(setting, node, -1, !!newNodes ? tools.clone(newNodes) : [], !!isSilent);
+                        } else {
+                            view.addNodes(setting, node, -1, [], !!isSilent);
+                        }
+                        setting.treeObj.trigger(consts.event.ASYNC_SUCCESS, [setting.treeId, node, msg]);
+                        tools.apply(callback);
+                    },
+                    error: function (XMLHttpRequest, textStatus, errorThrown) {
+                        if (_tmpV != data.getRoot(setting)._ver) {
+                            return;
+                        }
+                        if (node) node.isAjaxing = null;
+                        view.setNodeLineIcos(setting, node);
+                        setting.treeObj.trigger(consts.event.ASYNC_ERROR, [setting.treeId, node, XMLHttpRequest, textStatus, errorThrown]);
+                    }
+                });
+                return true;
+            },
+            cancelPreSelectedNode: function (setting, node, excludeNode) {
+                var list = data.getRoot(setting).curSelectedList,
+                    i, n;
+                for (i = list.length - 1; i >= 0; i--) {
+                    n = list[i];
+                    if (node === n || (!node && (!excludeNode || excludeNode !== n))) {
+                        $$(n, consts.id.A, setting).removeClass(consts.node.CURSELECTED);
+                        if (node) {
+                            data.removeSelectedNode(setting, node);
+                            break;
+                        } else {
+                            list.splice(i, 1);
+                            setting.treeObj.trigger(consts.event.UNSELECTED, [setting.treeId, n]);
+                        }
+                    }
+                }
+            },
+            createNodeCallback: function (setting) {
+                if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {
+                    var root = data.getRoot(setting);
+                    while (root.createdNodes.length > 0) {
+                        var node = root.createdNodes.shift();
+                        tools.apply(setting.view.addDiyDom, [setting.treeId, node]);
+                        if (!!setting.callback.onNodeCreated) {
+                            setting.treeObj.trigger(consts.event.NODECREATED, [setting.treeId, node]);
+                        }
+                    }
+                }
+            },
+            createNodes: function (setting, level, nodes, parentNode, index) {
+                if (!nodes || nodes.length == 0) return;
+                var root = data.getRoot(setting),
+                    childKey = setting.data.key.children,
+                    openFlag = !parentNode || parentNode.open || !!$$(parentNode[childKey][0], setting).get(0);
+                root.createdNodes = [];
+                var zTreeHtml = view.appendNodes(setting, level, nodes, parentNode, index, true, openFlag),
+                    parentObj, nextObj;
+
+                if (!parentNode) {
+                    parentObj = setting.treeObj;
+                    //setting.treeObj.append(zTreeHtml.join(''));
+                } else {
+                    var ulObj = $$(parentNode, consts.id.UL, setting);
+                    if (ulObj.get(0)) {
+                        parentObj = ulObj;
+                        //ulObj.append(zTreeHtml.join(''));
+                    }
+                }
+                if (parentObj) {
+                    if (index >= 0) {
+                        nextObj = parentObj.children()[index];
+                    }
+                    if (index >= 0 && nextObj) {
+                        $(nextObj).before(zTreeHtml.join(''));
+                    } else {
+                        parentObj.append(zTreeHtml.join(''));
+                    }
+                }
+
+                view.createNodeCallback(setting);
+            },
+            destroy: function (setting) {
+                if (!setting) return;
+                data.initCache(setting);
+                data.initRoot(setting);
+                event.unbindTree(setting);
+                event.unbindEvent(setting);
+                setting.treeObj.empty();
+                delete settings[setting.treeId];
+            },
+            expandCollapseNode: function (setting, node, expandFlag, animateFlag, callback) {
+                var root = data.getRoot(setting),
+                    childKey = setting.data.key.children;
+                var tmpCb, _callback;
+                if (!node) {
+                    tools.apply(callback, []);
+                    return;
+                }
+                if (root.expandTriggerFlag) {
+                    _callback = callback;
+                    tmpCb = function () {
+                        if (_callback) _callback();
+                        if (node.open) {
+                            setting.treeObj.trigger(consts.event.EXPAND, [setting.treeId, node]);
+                        } else {
+                            setting.treeObj.trigger(consts.event.COLLAPSE, [setting.treeId, node]);
+                        }
+                    };
+                    callback = tmpCb;
+                    root.expandTriggerFlag = false;
+                }
+                if (!node.open && node.isParent && ((!$$(node, consts.id.UL, setting).get(0)) || (node[childKey] && node[childKey].length > 0 && !$$(node[childKey][0], setting).get(0)))) {
+                    view.appendParentULDom(setting, node);
+                    view.createNodeCallback(setting);
+                }
+                if (node.open == expandFlag) {
+                    tools.apply(callback, []);
+                    return;
+                }
+                var ulObj = $$(node, consts.id.UL, setting),
+                    switchObj = $$(node, consts.id.SWITCH, setting),
+                    icoObj = $$(node, consts.id.ICON, setting);
+
+                if (node.isParent) {
+                    node.open = !node.open;
+                    if (node.iconOpen && node.iconClose) {
+                        icoObj.attr("style", view.makeNodeIcoStyle(setting, node));
+                    }
+
+                    if (node.open) {
+                        view.replaceSwitchClass(node, switchObj, consts.folder.OPEN);
+                        view.replaceIcoClass(node, icoObj, consts.folder.OPEN);
+                        if (animateFlag == false || setting.view.expandSpeed == "") {
+                            ulObj.show();
+                            tools.apply(callback, []);
+                        } else {
+                            if (node[childKey] && node[childKey].length > 0) {
+                                ulObj.slideDown(setting.view.expandSpeed, callback);
+                            } else {
+                                ulObj.show();
+                                tools.apply(callback, []);
+                            }
+                        }
+                    } else {
+                        view.replaceSwitchClass(node, switchObj, consts.folder.CLOSE);
+                        view.replaceIcoClass(node, icoObj, consts.folder.CLOSE);
+                        if (animateFlag == false || setting.view.expandSpeed == "" || !(node[childKey] && node[childKey].length > 0)) {
+                            ulObj.hide();
+                            tools.apply(callback, []);
+                        } else {
+                            ulObj.slideUp(setting.view.expandSpeed, callback);
+                        }
+                    }
+                } else {
+                    tools.apply(callback, []);
+                }
+            },
+            expandCollapseParentNode: function (setting, node, expandFlag, animateFlag, callback) {
+                if (!node) return;
+                if (!node.parentTId) {
+                    view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback);
+                    return;
+                } else {
+                    view.expandCollapseNode(setting, node, expandFlag, animateFlag);
+                }
+                if (node.parentTId) {
+                    view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, animateFlag, callback);
+                }
+            },
+            expandCollapseSonNode: function (setting, node, expandFlag, animateFlag, callback) {
+                var root = data.getRoot(setting),
+                    childKey = setting.data.key.children,
+                    treeNodes = (node) ? node[childKey] : root[childKey],
+                    selfAnimateSign = (node) ? false : animateFlag,
+                    expandTriggerFlag = data.getRoot(setting).expandTriggerFlag;
+                data.getRoot(setting).expandTriggerFlag = false;
+                if (treeNodes) {
+                    for (var i = 0, l = treeNodes.length; i < l; i++) {
+                        if (treeNodes[i]) view.expandCollapseSonNode(setting, treeNodes[i], expandFlag, selfAnimateSign);
+                    }
+                }
+                data.getRoot(setting).expandTriggerFlag = expandTriggerFlag;
+                view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback);
+            },
+            isSelectedNode: function (setting, node) {
+                if (!node) {
+                    return false;
+                }
+                var list = data.getRoot(setting).curSelectedList,
+                    i;
+                for (i = list.length - 1; i >= 0; i--) {
+                    if (node === list[i]) {
+                        return true;
+                    }
+                }
+                return false;
+            },
+            makeDOMNodeIcon: function (html, setting, node) {
+                var nameStr = data.getNodeName(setting, node),
+                    name = setting.view.nameIsHTML ? nameStr : nameStr.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+                html.push("<span id='", node.tId, consts.id.ICON,
+                    "' title='' treeNode", consts.id.ICON, " class='", view.makeNodeIcoClass(setting, node),
+                    "' style='", view.makeNodeIcoStyle(setting, node), "'></span><span id='", node.tId, consts.id.SPAN,
+                    "' class='", consts.className.NAME,
+                    "'>", name, "</span>");
+            },
+            makeDOMNodeLine: function (html, setting, node) {
+                html.push("<span id='", node.tId, consts.id.SWITCH, "' title='' class='", view.makeNodeLineClass(setting, node), "' treeNode", consts.id.SWITCH, "></span>");
+            },
+            makeDOMNodeMainAfter: function (html, setting, node) {
+                html.push("</li>");
+            },
+            makeDOMNodeMainBefore: function (html, setting, node) {
+                html.push("<li id='", node.tId, "' class='", consts.className.LEVEL, node.level, "' tabindex='0' hidefocus='true' treenode>");
+            },
+            makeDOMNodeNameAfter: function (html, setting, node) {
+                html.push("</a>");
+            },
+            makeDOMNodeNameBefore: function (html, setting, node) {
+                var title = data.getNodeTitle(setting, node),
+                    url = view.makeNodeUrl(setting, node),
+                    fontcss = view.makeNodeFontCss(setting, node),
+                    fontStyle = [];
+                for (var f in fontcss) {
+                    fontStyle.push(f, ":", fontcss[f], ";");
+                }
+                html.push("<a id='", node.tId, consts.id.A, "' class='", consts.className.LEVEL, node.level, "' treeNode", consts.id.A, " onclick=\"", (node.click || ''),
+                    "\" ", ((url != null && url.length > 0) ? "href='" + url + "'" : ""), " target='", view.makeNodeTarget(node), "' style='", fontStyle.join(''),
+                    "'");
+                if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle) && title) {
+                    html.push("title='", title.replace(/'/g, "&#39;").replace(/</g, '&lt;').replace(/>/g, '&gt;'), "'");
+                }
+                html.push(">");
+            },
+            makeNodeFontCss: function (setting, node) {
+                var fontCss = tools.apply(setting.view.fontCss, [setting.treeId, node], setting.view.fontCss);
+                return (fontCss && ((typeof fontCss) != "function")) ? fontCss : {};
+            },
+            makeNodeIcoClass: function (setting, node) {
+                var icoCss = ["ico"];
+                if (!node.isAjaxing) {
+                    icoCss[0] = (node.iconSkin ? node.iconSkin + "_" : "") + icoCss[0];
+                    if (node.isParent) {
+                        icoCss.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);
+                    } else {
+                        icoCss.push(consts.folder.DOCU);
+                    }
+                }
+                return consts.className.BUTTON + " " + icoCss.join('_');
+            },
+            makeNodeIcoStyle: function (setting, node) {
+                var icoStyle = [];
+                if (!node.isAjaxing) {
+                    var icon = (node.isParent && node.iconOpen && node.iconClose) ? (node.open ? node.iconOpen : node.iconClose) : node[setting.data.key.icon];
+                    if (icon) icoStyle.push("background:url(", icon, ") 0 0 no-repeat;");
+                    if (setting.view.showIcon == false || !tools.apply(setting.view.showIcon, [setting.treeId, node], true)) {
+                        icoStyle.push("width:0px;height:0px;");
+                    }
+                }
+                return icoStyle.join('');
+            },
+            makeNodeLineClass: function (setting, node) {
+                var lineClass = [];
+                if (setting.view.showLine) {
+                    if (node.level == 0 && node.isFirstNode && node.isLastNode) {
+                        lineClass.push(consts.line.ROOT);
+                    } else if (node.level == 0 && node.isFirstNode) {
+                        lineClass.push(consts.line.ROOTS);
+                    } else if (node.isLastNode) {
+                        lineClass.push(consts.line.BOTTOM);
+                    } else {
+                        lineClass.push(consts.line.CENTER);
+                    }
+                } else {
+                    lineClass.push(consts.line.NOLINE);
+                }
+                if (node.isParent) {
+                    lineClass.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);
+                } else {
+                    lineClass.push(consts.folder.DOCU);
+                }
+                return view.makeNodeLineClassEx(node) + lineClass.join('_');
+            },
+            makeNodeLineClassEx: function (node) {
+                return consts.className.BUTTON + " " + consts.className.LEVEL + node.level + " " + consts.className.SWITCH + " ";
+            },
+            makeNodeTarget: function (node) {
+                return (node.target || "_blank");
+            },
+            makeNodeUrl: function (setting, node) {
+                var urlKey = setting.data.key.url;
+                return node[urlKey] ? node[urlKey] : null;
+            },
+            makeUlHtml: function (setting, node, html, content) {
+                html.push("<ul id='", node.tId, consts.id.UL, "' class='", consts.className.LEVEL, node.level, " ", view.makeUlLineClass(setting, node), "' style='display:", (node.open ? "block" : "none"), "'>");
+                html.push(content);
+                html.push("</ul>");
+            },
+            makeUlLineClass: function (setting, node) {
+                return ((setting.view.showLine && !node.isLastNode) ? consts.line.LINE : "");
+            },
+            removeChildNodes: function (setting, node) {
+                if (!node) return;
+                var childKey = setting.data.key.children,
+                    nodes = node[childKey];
+                if (!nodes) return;
+
+                for (var i = 0, l = nodes.length; i < l; i++) {
+                    data.removeNodeCache(setting, nodes[i]);
+                }
+                data.removeSelectedNode(setting);
+                delete node[childKey];
+
+                if (!setting.data.keep.parent) {
+                    node.isParent = false;
+                    node.open = false;
+                    var tmp_switchObj = $$(node, consts.id.SWITCH, setting),
+                        tmp_icoObj = $$(node, consts.id.ICON, setting);
+                    view.replaceSwitchClass(node, tmp_switchObj, consts.folder.DOCU);
+                    view.replaceIcoClass(node, tmp_icoObj, consts.folder.DOCU);
+                    $$(node, consts.id.UL, setting).remove();
+                } else {
+                    $$(node, consts.id.UL, setting).empty();
+                }
+            },
+            scrollIntoView: function (setting, dom) {
+                if (!dom) {
+                    return;
+                }
+                // support IE 7
+                if (typeof Element === 'undefined') {
+                  var contRect = setting.treeObj.get(0).getBoundingClientRect(),
+                    findMeRect = dom.getBoundingClientRect();
+                  if (findMeRect.top < contRect.top || findMeRect.bottom > contRect.bottom
+                    || findMeRect.right > contRect.right || findMeRect.left < contRect.left) {
+                    dom.scrollIntoView();
+                  }
+                  return;
+                }
+                // code src: http://jsfiddle.net/08u6cxwj/
+                if (!Element.prototype.scrollIntoViewIfNeeded) {
+                    Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) {
+                        function withinBounds(value, min, max, extent) {
+                            if (false === centerIfNeeded || max <= value + extent && value <= min + extent) {
+                                return Math.min(max, Math.max(min, value));
+                            } else {
+                                return (min + max) / 2;
+                            }
+                        }
+
+                        function makeArea(left, top, width, height) {
+                            return {
+                                "left": left, "top": top, "width": width, "height": height
+                                , "right": left + width, "bottom": top + height
+                                , "translate": function (x, y) {
+                                    return makeArea(x + left, y + top, width, height);
+                                }
+                                , "relativeFromTo": function (lhs, rhs) {
+                                    var newLeft = left, newTop = top;
+                                    lhs = lhs.offsetParent;
+                                    rhs = rhs.offsetParent;
+                                    if (lhs === rhs) {
+                                        return area;
+                                    }
+                                    for (; lhs; lhs = lhs.offsetParent) {
+                                        newLeft += lhs.offsetLeft + lhs.clientLeft;
+                                        newTop += lhs.offsetTop + lhs.clientTop;
+                                    }
+                                    for (; rhs; rhs = rhs.offsetParent) {
+                                        newLeft -= rhs.offsetLeft + rhs.clientLeft;
+                                        newTop -= rhs.offsetTop + rhs.clientTop;
+                                    }
+                                    return makeArea(newLeft, newTop, width, height);
+                                }
+                            };
+                        }
+
+                        var parent, elem = this, area = makeArea(
+                            this.offsetLeft, this.offsetTop,
+                            this.offsetWidth, this.offsetHeight);
+                        while (tools.isElement(parent = elem.parentNode)) {
+                            var clientLeft = parent.offsetLeft + parent.clientLeft;
+                            var clientTop = parent.offsetTop + parent.clientTop;
+
+                            // Make area relative to parent's client area.
+                            area = area.relativeFromTo(elem, parent).translate(-clientLeft, -clientTop);
+
+                            parent.scrollLeft = withinBounds(
+                                parent.scrollLeft,
+                                area.right - parent.clientWidth, area.left,
+                                parent.clientWidth);
+
+                            parent.scrollTop = withinBounds(
+                                parent.scrollTop,
+                                area.bottom - parent.clientHeight, area.top,
+                                parent.clientHeight);
+
+                            // Determine actual scroll amount by reading back scroll properties.
+                            area = area.translate(clientLeft - parent.scrollLeft,
+                                clientTop - parent.scrollTop);
+                            elem = parent;
+                        }
+                    };
+                }
+                dom.scrollIntoViewIfNeeded();
+            },
+            setFirstNode: function (setting, parentNode) {
+                var childKey = setting.data.key.children, childLength = parentNode[childKey].length;
+                if (childLength > 0) {
+                    parentNode[childKey][0].isFirstNode = true;
+                }
+            },
+            setLastNode: function (setting, parentNode) {
+                var childKey = setting.data.key.children, childLength = parentNode[childKey].length;
+                if (childLength > 0) {
+                    parentNode[childKey][childLength - 1].isLastNode = true;
+                }
+            },
+            removeNode: function (setting, node) {
+                var root = data.getRoot(setting),
+                    childKey = setting.data.key.children,
+                    parentNode = (node.parentTId) ? node.getParentNode() : root;
+
+                node.isFirstNode = false;
+                node.isLastNode = false;
+                node.getPreNode = function () {
+                    return null;
+                };
+                node.getNextNode = function () {
+                    return null;
+                };
+
+                if (!data.getNodeCache(setting, node.tId)) {
+                    return;
+                }
+
+                $$(node, setting).remove();
+                data.removeNodeCache(setting, node);
+                data.removeSelectedNode(setting, node);
+
+                for (var i = 0, l = parentNode[childKey].length; i < l; i++) {
+                    if (parentNode[childKey][i].tId == node.tId) {
+                        parentNode[childKey].splice(i, 1);
+                        break;
+                    }
+                }
+                view.setFirstNode(setting, parentNode);
+                view.setLastNode(setting, parentNode);
+
+                var tmp_ulObj, tmp_switchObj, tmp_icoObj,
+                    childLength = parentNode[childKey].length;
+
+                //repair nodes old parent
+                if (!setting.data.keep.parent && childLength == 0) {
+                    //old parentNode has no child nodes
+                    parentNode.isParent = false;
+                    parentNode.open = false;
+                    tmp_ulObj = $$(parentNode, consts.id.UL, setting);
+                    tmp_switchObj = $$(parentNode, consts.id.SWITCH, setting);
+                    tmp_icoObj = $$(parentNode, consts.id.ICON, setting);
+                    view.replaceSwitchClass(parentNode, tmp_switchObj, consts.folder.DOCU);
+                    view.replaceIcoClass(parentNode, tmp_icoObj, consts.folder.DOCU);
+                    tmp_ulObj.css("display", "none");
+
+                } else if (setting.view.showLine && childLength > 0) {
+                    //old parentNode has child nodes
+                    var newLast = parentNode[childKey][childLength - 1];
+                    tmp_ulObj = $$(newLast, consts.id.UL, setting);
+                    tmp_switchObj = $$(newLast, consts.id.SWITCH, setting);
+                    tmp_icoObj = $$(newLast, consts.id.ICON, setting);
+                    if (parentNode == root) {
+                        if (parentNode[childKey].length == 1) {
+                            //node was root, and ztree has only one root after move node
+                            view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.ROOT);
+                        } else {
+                            var tmp_first_switchObj = $$(parentNode[childKey][0], consts.id.SWITCH, setting);
+                            view.replaceSwitchClass(parentNode[childKey][0], tmp_first_switchObj, consts.line.ROOTS);
+                            view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);
+                        }
+                    } else {
+                        view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);
+                    }
+                    tmp_ulObj.removeClass(consts.line.LINE);
+                }
+            },
+            replaceIcoClass: function (node, obj, newName) {
+                if (!obj || node.isAjaxing) return;
+                var tmpName = obj.attr("class");
+                if (tmpName == undefined) return;
+                var tmpList = tmpName.split("_");
+                switch (newName) {
+                    case consts.folder.OPEN:
+                    case consts.folder.CLOSE:
+                    case consts.folder.DOCU:
+                        tmpList[tmpList.length - 1] = newName;
+                        break;
+                }
+                obj.attr("class", tmpList.join("_"));
+            },
+            replaceSwitchClass: function (node, obj, newName) {
+                if (!obj) return;
+                var tmpName = obj.attr("class");
+                if (tmpName == undefined) return;
+                var tmpList = tmpName.split("_");
+                switch (newName) {
+                    case consts.line.ROOT:
+                    case consts.line.ROOTS:
+                    case consts.line.CENTER:
+                    case consts.line.BOTTOM:
+                    case consts.line.NOLINE:
+                        tmpList[0] = view.makeNodeLineClassEx(node) + newName;
+                        break;
+                    case consts.folder.OPEN:
+                    case consts.folder.CLOSE:
+                    case consts.folder.DOCU:
+                        tmpList[1] = newName;
+                        break;
+                }
+                obj.attr("class", tmpList.join("_"));
+                if (newName !== consts.folder.DOCU) {
+                    obj.removeAttr("disabled");
+                } else {
+                    obj.attr("disabled", "disabled");
+                }
+            },
+            selectNode: function (setting, node, addFlag) {
+                if (!addFlag) {
+                    view.cancelPreSelectedNode(setting, null, node);
+                }
+                $$(node, consts.id.A, setting).addClass(consts.node.CURSELECTED);
+                data.addSelectedNode(setting, node);
+                setting.treeObj.trigger(consts.event.SELECTED, [setting.treeId, node]);
+            },
+            setNodeFontCss: function (setting, treeNode) {
+                var aObj = $$(treeNode, consts.id.A, setting),
+                    fontCss = view.makeNodeFontCss(setting, treeNode);
+                if (fontCss) {
+                    aObj.css(fontCss);
+                }
+            },
+            setNodeLineIcos: function (setting, node) {
+                if (!node) return;
+                var switchObj = $$(node, consts.id.SWITCH, setting),
+                    ulObj = $$(node, consts.id.UL, setting),
+                    icoObj = $$(node, consts.id.ICON, setting),
+                    ulLine = view.makeUlLineClass(setting, node);
+                if (ulLine.length == 0) {
+                    ulObj.removeClass(consts.line.LINE);
+                } else {
+                    ulObj.addClass(ulLine);
+                }
+                switchObj.attr("class", view.makeNodeLineClass(setting, node));
+                if (node.isParent) {
+                    switchObj.removeAttr("disabled");
+                } else {
+                    switchObj.attr("disabled", "disabled");
+                }
+                icoObj.removeAttr("style");
+                icoObj.attr("style", view.makeNodeIcoStyle(setting, node));
+                icoObj.attr("class", view.makeNodeIcoClass(setting, node));
+            },
+            setNodeName: function (setting, node) {
+                var title = data.getNodeTitle(setting, node),
+                    nObj = $$(node, consts.id.SPAN, setting);
+                nObj.empty();
+                if (setting.view.nameIsHTML) {
+                    nObj.html(data.getNodeName(setting, node));
+                } else {
+                    nObj.text(data.getNodeName(setting, node));
+                }
+                if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle)) {
+                    var aObj = $$(node, consts.id.A, setting);
+                    aObj.attr("title", !title ? "" : title);
+                }
+            },
+            setNodeTarget: function (setting, node) {
+                var aObj = $$(node, consts.id.A, setting);
+                aObj.attr("target", view.makeNodeTarget(node));
+            },
+            setNodeUrl: function (setting, node) {
+                var aObj = $$(node, consts.id.A, setting),
+                    url = view.makeNodeUrl(setting, node);
+                if (url == null || url.length == 0) {
+                    aObj.removeAttr("href");
+                } else {
+                    aObj.attr("href", url);
+                }
+            },
+            switchNode: function (setting, node) {
+                if (node.open || !tools.canAsync(setting, node)) {
+                    view.expandCollapseNode(setting, node, !node.open);
+                } else if (setting.async.enable) {
+                    if (!view.asyncNode(setting, node)) {
+                        view.expandCollapseNode(setting, node, !node.open);
+                        return;
+                    }
+                } else if (node) {
+                    view.expandCollapseNode(setting, node, !node.open);
+                }
+            }
+        };
+    // zTree defind
+    $.fn.zTree = {
+        consts: _consts,
+        _z: {
+            tools: tools,
+            view: view,
+            event: event,
+            data: data
+        },
+        getZTreeObj: function (treeId) {
+            var o = data.getZTreeTools(treeId);
+            return o ? o : null;
+        },
+        destroy: function (treeId) {
+            if (!!treeId && treeId.length > 0) {
+                view.destroy(data.getSetting(treeId));
+            } else {
+                for (var s in settings) {
+                    view.destroy(settings[s]);
+                }
+            }
+        },
+        init: function (obj, zSetting, zNodes) {
+            var setting = tools.clone(_setting);
+            $.extend(true, setting, zSetting);
+            setting.treeId = obj.attr("id");
+            setting.treeObj = obj;
+            setting.treeObj.empty();
+            settings[setting.treeId] = setting;
+            //For some older browser,(e.g., ie6)
+            if (typeof document.body.style.maxHeight === "undefined") {
+                setting.view.expandSpeed = "";
+            }
+            data.initRoot(setting);
+            var root = data.getRoot(setting),
+                childKey = setting.data.key.children;
+            zNodes = zNodes ? tools.clone(tools.isArray(zNodes) ? zNodes : [zNodes]) : [];
+            if (setting.data.simpleData.enable) {
+                root[childKey] = data.transformTozTreeFormat(setting, zNodes);
+            } else {
+                root[childKey] = zNodes;
+            }
+
+            data.initCache(setting);
+            event.unbindTree(setting);
+            event.bindTree(setting);
+            event.unbindEvent(setting);
+            event.bindEvent(setting);
+
+            var zTreeTools = {
+                setting: setting,
+                addNodes: function (parentNode, index, newNodes, isSilent) {
+                    if (!parentNode) parentNode = null;
+                    if (parentNode && !parentNode.isParent && setting.data.keep.leaf) return null;
+
+                    var i = parseInt(index, 10);
+                    if (isNaN(i)) {
+                        isSilent = !!newNodes;
+                        newNodes = index;
+                        index = -1;
+                    } else {
+                        index = i;
+                    }
+                    if (!newNodes) return null;
+
+
+                    var xNewNodes = tools.clone(tools.isArray(newNodes) ? newNodes : [newNodes]);
+
+                    function addCallback() {
+                        view.addNodes(setting, parentNode, index, xNewNodes, (isSilent == true));
+                    }
+
+                    if (tools.canAsync(setting, parentNode)) {
+                        view.asyncNode(setting, parentNode, isSilent, addCallback);
+                    } else {
+                        addCallback();
+                    }
+                    return xNewNodes;
+                },
+                cancelSelectedNode: function (node) {
+                    view.cancelPreSelectedNode(setting, node);
+                },
+                destroy: function () {
+                    view.destroy(setting);
+                },
+                expandAll: function (expandFlag) {
+                    expandFlag = !!expandFlag;
+                    view.expandCollapseSonNode(setting, null, expandFlag, true);
+                    return expandFlag;
+                },
+                expandNode: function (node, expandFlag, sonSign, focus, callbackFlag) {
+                    if (!node || !node.isParent) return null;
+                    if (expandFlag !== true && expandFlag !== false) {
+                        expandFlag = !node.open;
+                    }
+                    callbackFlag = !!callbackFlag;
+
+                    if (callbackFlag && expandFlag && (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false)) {
+                        return null;
+                    } else if (callbackFlag && !expandFlag && (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false)) {
+                        return null;
+                    }
+                    if (expandFlag && node.parentTId) {
+                        view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, false);
+                    }
+                    if (expandFlag === node.open && !sonSign) {
+                        return null;
+                    }
+
+                    data.getRoot(setting).expandTriggerFlag = callbackFlag;
+                    if (!tools.canAsync(setting, node) && sonSign) {
+                        view.expandCollapseSonNode(setting, node, expandFlag, true, showNodeFocus);
+                    } else {
+                        node.open = !expandFlag;
+                        view.switchNode(this.setting, node);
+                        showNodeFocus();
+                    }
+                    return expandFlag;
+
+                    function showNodeFocus() {
+                        var a = $$(node, setting).get(0);
+                        if (a && focus !== false) {
+                            view.scrollIntoView(setting, a);
+                        }
+                    }
+                },
+                getNodes: function () {
+                    return data.getNodes(setting);
+                },
+                getNodeByParam: function (key, value, parentNode) {
+                    if (!key) return null;
+                    return data.getNodeByParam(setting, parentNode ? parentNode[setting.data.key.children] : data.getNodes(setting), key, value);
+                },
+                getNodeByTId: function (tId) {
+                    return data.getNodeCache(setting, tId);
+                },
+                getNodesByParam: function (key, value, parentNode) {
+                    if (!key) return null;
+                    return data.getNodesByParam(setting, parentNode ? parentNode[setting.data.key.children] : data.getNodes(setting), key, value);
+                },
+                getNodesByParamFuzzy: function (key, value, parentNode) {
+                    if (!key) return null;
+                    return data.getNodesByParamFuzzy(setting, parentNode ? parentNode[setting.data.key.children] : data.getNodes(setting), key, value);
+                },
+                getNodesByFilter: function (filter, isSingle, parentNode, invokeParam) {
+                    isSingle = !!isSingle;
+                    if (!filter || (typeof filter != "function")) return (isSingle ? null : []);
+                    return data.getNodesByFilter(setting, parentNode ? parentNode[setting.data.key.children] : data.getNodes(setting), filter, isSingle, invokeParam);
+                },
+                getNodeIndex: function (node) {
+                    if (!node) return null;
+                    var childKey = setting.data.key.children,
+                        parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);
+                    for (var i = 0, l = parentNode[childKey].length; i < l; i++) {
+                        if (parentNode[childKey][i] == node) return i;
+                    }
+                    return -1;
+                },
+                getSelectedNodes: function () {
+                    var r = [], list = data.getRoot(setting).curSelectedList;
+                    for (var i = 0, l = list.length; i < l; i++) {
+                        r.push(list[i]);
+                    }
+                    return r;
+                },
+                isSelectedNode: function (node) {
+                    return data.isSelectedNode(setting, node);
+                },
+                reAsyncChildNodesPromise: function (parentNode, reloadType, isSilent) {
+                    var promise = new Promise(function(resolve, reject) {
+                        try {
+                            zTreeTools.reAsyncChildNodes(parentNode, reloadType, isSilent, function() {
+                                resolve(parentNode);
+                            });
+                        } catch(e) {
+                            reject(e);
+                        }
+                    });
+                    return promise;
+                },
+                reAsyncChildNodes: function (parentNode, reloadType, isSilent, callback) {
+                    if (!this.setting.async.enable) return;
+                    var isRoot = !parentNode;
+                    if (isRoot) {
+                        parentNode = data.getRoot(setting);
+                    }
+                    if (reloadType == "refresh") {
+                        var childKey = this.setting.data.key.children;
+                        for (var i = 0, l = parentNode[childKey] ? parentNode[childKey].length : 0; i < l; i++) {
+                            data.removeNodeCache(setting, parentNode[childKey][i]);
+                        }
+                        data.removeSelectedNode(setting);
+                        parentNode[childKey] = [];
+                        if (isRoot) {
+                            this.setting.treeObj.empty();
+                        } else {
+                            var ulObj = $$(parentNode, consts.id.UL, setting);
+                            ulObj.empty();
+                        }
+                    }
+                    view.asyncNode(this.setting, isRoot ? null : parentNode, !!isSilent, callback);
+                },
+                refresh: function () {
+                    this.setting.treeObj.empty();
+                    var root = data.getRoot(setting),
+                        nodes = root[setting.data.key.children]
+                    data.initRoot(setting);
+                    root[setting.data.key.children] = nodes
+                    data.initCache(setting);
+                    view.createNodes(setting, 0, root[setting.data.key.children], null, -1);
+                },
+                removeChildNodes: function (node) {
+                    if (!node) return null;
+                    var childKey = setting.data.key.children,
+                        nodes = node[childKey];
+                    view.removeChildNodes(setting, node);
+                    return nodes ? nodes : null;
+                },
+                removeNode: function (node, callbackFlag) {
+                    if (!node) return;
+                    callbackFlag = !!callbackFlag;
+                    if (callbackFlag && tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return;
+                    view.removeNode(setting, node);
+                    if (callbackFlag) {
+                        this.setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]);
+                    }
+                },
+                selectNode: function (node, addFlag, isSilent) {
+                    if (!node) return;
+                    if (tools.uCanDo(setting)) {
+                        addFlag = setting.view.selectedMulti && addFlag;
+                        if (node.parentTId) {
+                            view.expandCollapseParentNode(setting, node.getParentNode(), true, false, showNodeFocus);
+                        } else if (!isSilent) {
+                            try {
+                                $$(node, setting).focus().blur();
+                            } catch (e) {
+                            }
+                        }
+                        view.selectNode(setting, node, addFlag);
+                    }
+
+                    function showNodeFocus() {
+                        if (isSilent) {
+                            return;
+                        }
+                        var a = $$(node, setting).get(0);
+                        view.scrollIntoView(setting, a);
+                    }
+                },
+                transformTozTreeNodes: function (simpleNodes) {
+                    return data.transformTozTreeFormat(setting, simpleNodes);
+                },
+                transformToArray: function (nodes) {
+                    return data.transformToArrayFormat(setting, nodes);
+                },
+                updateNode: function (node, checkTypeFlag) {
+                    if (!node) return;
+                    var nObj = $$(node, setting);
+                    if (nObj.get(0) && tools.uCanDo(setting)) {
+                        view.setNodeName(setting, node);
+                        view.setNodeTarget(setting, node);
+                        view.setNodeUrl(setting, node);
+                        view.setNodeLineIcos(setting, node);
+                        view.setNodeFontCss(setting, node);
+                    }
+                }
+            }
+            root.treeTools = zTreeTools;
+            data.setZTreeTools(setting, zTreeTools);
+
+            if (root[childKey] && root[childKey].length > 0) {
+                view.createNodes(setting, 0, root[childKey], null, -1);
+            } else if (setting.async.enable && setting.async.url && setting.async.url !== '') {
+                view.asyncNode(setting);
+            }
+            return zTreeTools;
+        }
+    };
+
+    var zt = $.fn.zTree,
+        $$ = tools.$,
+        consts = zt.consts;
+})(jQuery);

Разница между файлами не показана из-за своего большого размера
+ 9 - 0
src/main/resources/static/js/viewer.min.js


+ 95 - 0
src/main/resources/web/compress.ftl

@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+    <link href="css/zTreeStyle.css" rel="stylesheet" type="text/css">
+    <style type="text/css">
+        html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
+            margin: 0;padding: 0;border: 0;outline: 0;font-weight: inherit;font-style: inherit;font-size: 100%;font-family: inherit;vertical-align: baseline;}
+        body {color: #2f332a;font: 15px/21px Arial, Helvetica, simsun, sans-serif;background: #f0f6e4 \9;}
+        body{
+            margin:0 auto;
+            width: 600px;
+            background-color: #333333;
+            font-size: 4em;
+        }
+        h1, h2, h3, h4, h5, h6 {color: #2f332a;font-weight: bold;font-family: Helvetica, Arial, sans-serif;padding-bottom: 5px;}
+        h1 {font-size: 24px;line-height: 34px;text-align: center;}
+        h2 {font-size: 14px;line-height: 24px;padding-top: 5px;}
+        h6 {font-weight: normal;font-size: 12px;letter-spacing: 1px;line-height: 24px;text-align: center;}
+        a {color:#3C6E31;text-decoration: underline;}
+        a:hover {background-color:#3C6E31;color:white;}
+        input.radio {margin: 0 2px 0 8px;}
+        input.radio.first {margin-left:0;}
+        input.empty {color: lightgray;}
+        code {color: #2f332a;}
+        div.zTreeDemoBackground {width:600px;text-align:center;background-color: #ffffff;}
+    </style>
+</head>
+<body>
+
+<div class="zTreeDemoBackground left">
+    <ul id="treeDemo" class="ztree"></ul>
+</div>
+</body>
+<script type="text/javascript" src="config.js"></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">
+    var data = JSON.parse('${fileTree}');
+    var setting = {
+        view: {
+            fontCss : {"color":"blue"},
+            showLine: true
+        },
+        data: {
+            key: {
+                children: 'childList',
+                name: 'originName'
+            }
+        },
+        callback:{
+            beforeClick:function (treeId, treeNode, clickFlag) {
+                console.log("节点参数:treeId-" + treeId + "treeNode-"
+                        + JSON.stringify(treeNode) + "clickFlag-" + clickFlag);
+            },
+            onClick:function (event, treeId, treeNode) {
+                if (!treeNode.directory) {
+                    var winHeight = window.document.documentElement.clientHeight-10;
+                    window.open(env_config.server_preview_url + encodeURIComponent(env_config.server_base_url + treeNode.fileName) + "&needEncode=1",
+                            "_blank", "height=" + winHeight + ",top=80,left=80,toolbar=no, menubar=no, scrollbars=yes, resizable=yes");
+                }
+            }
+        }
+    };
+    var height = 0;
+    $(document).ready(function(){
+        var treeObj = $.fn.zTree.init($("#treeDemo"), setting, data);
+        treeObj.expandAll(true);
+        height = getZtreeDomHeight();
+        $(".zTreeDemoBackground").css("height", height);
+    });
+
+    /**
+     *  计算ztreedom的高度
+     */
+    function getZtreeDomHeight() {
+        return $("#treeDemo").height() > window.document.documentElement.clientHeight - 1
+                ? $("#treeDemo").height() : window.document.documentElement.clientHeight - 1;
+    }
+    /**
+     * 页面变化调整高度
+     */
+    window.onresize = function(){
+        height = getZtreeDomHeight();
+        $(".zTreeDemoBackground").css("height", height);
+    }
+    /**
+     * 滚动时调整高度
+     */
+    window.onscroll = function(){
+        height = getZtreeDomHeight();
+        $(".zTreeDemoBackground").css("height", height);
+    }
+</script>
+</html>

+ 9 - 0
src/main/resources/web/doc.ftl

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+<body>
+${doc}
+</body>
+
+</html>

+ 11 - 0
src/main/resources/web/docxConvert.ftl

@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+<body>
+
+${docxConvert}
+
+</body>
+
+</html>

+ 41 - 0
src/main/resources/web/fileNotSupported.ftl

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+    <style type="text/css">
+        body{
+            margin: 0 auto;
+            width:900px;
+            background-color: #CCB;
+        }
+        .container{
+            width: 700px;
+            height: 700px;
+            margin: 0 auto;
+        }
+        img{
+            width:auto;
+            height:auto;
+            max-width:100%;
+            max-height:100%;
+            padding-bottom: 36px;
+        }
+        span{
+            display: block;
+            font-size:20px;
+            color:blue;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <img src="images/sorry.jpg" />
+    <span>
+        该文件类型(${fileType})系统暂时不支持在线预览,<b>说明</b>:
+        <p>${msg}</p>
+        如有需要请联系<a href="mailto:1210893441@qq.com">@HappyPig</a>
+    </span>
+</div>
+</body>
+
+</html>

+ 26 - 0
src/main/resources/web/pdf.ftl

@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+    <style type="text/css">
+        body{
+            margin: 0;
+            padding:0;
+            border:0;
+        }
+    </style>
+</head>
+<body>
+    <iframe src="${pdfUrl}" width="100%" frameborder="0"></iframe>
+</body>
+<script type="text/javascript">
+    document.getElementsByTagName('iframe')[0].height = document.documentElement.clientHeight-10;
+    /**
+     * 页面变化调整高度
+     */
+    window.onresize = function(){
+        var fm = document.getElementsByTagName("iframe")[0];
+        fm.height = window.document.documentElement.clientHeight-10;
+    }
+</script>
+</html>

+ 33 - 0
src/main/resources/web/picture.ftl

@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>图片预览图</title>
+    <link rel="stylesheet" href="css/viewer.min.css">
+    <style>
+        * { margin: 0; padding: 0;}
+        #dowebok { width: 800px; margin: 0 auto; font-size: 0;}
+        #dowebok li { display: inline-block; width: 32%; margin-left: 1%; padding-top: 1%;}
+        /*#dowebok li img { width: 200%;}*/
+    </style>
+</head>
+<body>
+<h1>如果图片质量很好,首次加载图片时间可能会有点长,请耐心等待</h1>
+
+<ul id="dowebok">
+    <li><img id="Imgbox" src="#" width="800px" height="550px"></li>
+
+</ul>
+<script src="js/viewer.min.js"></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'});
+</script>
+<input name="url" value="${imgurl}" type="hidden" id="url" >
+</body>
+
+</html>

+ 18 - 0
src/main/resources/web/txt.ftl

@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>普通文件预览</title>
+</head>
+
+
+
+<body>
+<script language="javascript" type="text/javascript">
+    window.location.href="${ordinaryUrl}";
+</script>
+
+
+</body>
+
+</html>

+ 16 - 0
src/test/java/com/yudianbank/FilePreviewApplicationTests.java

@@ -0,0 +1,16 @@
+package com.yudianbank;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class FilePreviewApplicationTests {
+
+	@Test
+	public void contextLoads() {
+	}
+
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов