Looly 5 years ago
parent
commit
99eeb30ffe

+ 32 - 1
hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java

@@ -306,6 +306,7 @@ public class FileUtil extends PathUtil {
 
 	/**
 	 * 创建File对象<br>
+	 * 根据的路径构建文件,在Win下直接构建,在Linux下拆分路径单独构建
 	 * 此方法会检查slip漏洞,漏洞说明见http://blog.nsfocus.net/zip-slip-2/
 	 *
 	 * @param parent 父文件对象
@@ -316,7 +317,7 @@ public class FileUtil extends PathUtil {
 		if (StrUtil.isBlank(path)) {
 			throw new NullPointerException("File path is blank!");
 		}
-		return checkSlip(parent, new File(parent, path));
+		return checkSlip(parent, buildFile(parent, path));
 	}
 
 	/**
@@ -3277,4 +3278,34 @@ public class FileUtil extends PathUtil {
 	public static void tail(File file, Charset charset) {
 		tail(file, charset, Tailer.CONSOLE_HANDLER);
 	}
+
+	/**
+	 * 根据压缩包中的路径构建目录结构,在Win下直接构建,在Linux下拆分路径单独构建
+	 *
+	 * @param outFile  最外部路径
+	 * @param fileName 文件名,可以包含路径
+	 * @return 文件或目录
+	 * @since 5.0.5
+	 */
+	private static File buildFile(File outFile, String fileName) {
+		// 替换Windows路径分隔符为Linux路径分隔符,便于统一处理
+		fileName = fileName.replace('\\', '/');
+		if (false == FileUtil.isWindows()
+				// 检查文件名中是否包含"/",不考虑以"/"结尾的情况
+				&& fileName.lastIndexOf(CharUtil.SLASH, fileName.length() - 2) > 0) {
+			// 在Linux下多层目录创建存在问题,/会被当成文件名的一部分,此处做处理
+			// 使用/拆分路径(zip中无\),级联创建父目录
+			final List<String> pathParts = StrUtil.split(fileName, '/', false, true);
+			final int lastPartIndex = pathParts.size() - 1;//目录个数
+			for (int i = 0; i < lastPartIndex; i++) {
+				//由于路径拆分,slip不检查,在最后一步检查
+				outFile = new File(outFile, pathParts.get(i));
+			}
+			//noinspection ResultOfMethodCallIgnored
+			outFile.mkdirs();
+			// 最后一个部分如果非空,作为文件名
+			fileName = pathParts.get(lastPartIndex);
+		}
+		return new File(outFile, fileName);
+	}
 }

+ 1 - 31
hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java

@@ -471,7 +471,7 @@ public class ZipUtil {
 			while (em.hasMoreElements()) {
 				zipEntry = em.nextElement();
 				// FileUtil.file会检查slip漏洞,漏洞说明见http://blog.nsfocus.net/zip-slip-2/
-				outItemFile = buildFile(outFile, zipEntry.getName());
+				outItemFile = FileUtil.file(outFile, zipEntry.getName());
 				if (zipEntry.isDirectory()) {
 					// 创建对应目录
 					//noinspection ResultOfMethodCallIgnored
@@ -1106,36 +1106,6 @@ public class ZipUtil {
 			throw new IORuntimeException(e);
 		}
 	}
-
-	/**
-	 * 根据压缩包中的路径构建目录结构,在Win下直接构建,在Linux下拆分路径单独构建
-	 *
-	 * @param outFile  最外部路径
-	 * @param fileName 文件名,可以包含路径
-	 * @return 文件或目录
-	 * @since 5.0.5
-	 */
-	private static File buildFile(File outFile, String fileName) {
-		// 替换Windows路径分隔符为Linux路径分隔符,便于统一处理
-		fileName = fileName.replace('\\', '/');
-		if (false == FileUtil.isWindows()
-				// 检查文件名中是否包含"/",不考虑以"/"结尾的情况
-				&& fileName.lastIndexOf(CharUtil.SLASH, fileName.length() - 2) > 0) {
-			// 在Linux下多层目录创建存在问题,/会被当成文件名的一部分,此处做处理
-			// 使用/拆分路径(zip中无\),级联创建父目录
-			final List<String> pathParts = StrUtil.split(fileName, '/', false, true);
-			final int lastPartIndex = pathParts.size() - 1;//目录个数
-			for (int i = 0; i < lastPartIndex; i++) {
-				//由于路径拆分,slip不检查,在最后一步检查
-				outFile = new File(outFile, pathParts.get(i));
-			}
-			//noinspection ResultOfMethodCallIgnored
-			outFile.mkdirs();
-			// 最后一个部分如果非空,作为文件名
-			fileName = pathParts.get(lastPartIndex);
-		}
-		return FileUtil.file(outFile, fileName);
-	}
 	// ---------------------------------------------------------------------------------------------- Private method end
 
 }

+ 0 - 4
hutool-extra/src/main/java/cn/hutool/extra/compress/Extractor.java

@@ -1,4 +0,0 @@
-package cn.hutool.extra.compress;
-
-public class Extractor {
-}

+ 1 - 1
hutool-extra/src/main/java/cn/hutool/extra/compress/archiver/Archiver.java

@@ -7,7 +7,7 @@ import java.io.File;
 import java.io.FileFilter;
 
 /**
- * 数据归档封装,归档即将几个文件或目录打成一个压缩包<br>
+ * 数据归档封装,归档即将几个文件或目录打成一个压缩包
  *
  * @author looly
  */

+ 1 - 1
hutool-extra/src/main/java/cn/hutool/extra/compress/archiver/StreamArchiver.java

@@ -56,7 +56,7 @@ public class StreamArchiver implements Archiver {
 		return new StreamArchiver(charset, archiverName, out);
 	}
 
-	private ArchiveOutputStream out;
+	private final ArchiveOutputStream out;
 
 	/**
 	 * 构造

+ 11 - 0
hutool-extra/src/main/java/cn/hutool/extra/compress/archiver/package-info.java

@@ -0,0 +1,11 @@
+/**
+ * 基于commons-compress的打包(压缩)封装
+ *
+ *  <p>
+ *     见:https://commons.apache.org/proper/commons-compress/
+ * </p>
+ * 
+ * @author looly
+ *
+ */
+package cn.hutool.extra.compress.archiver;

+ 11 - 0
hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/Extractor.java

@@ -0,0 +1,11 @@
+package cn.hutool.extra.compress.extractor;
+
+/**
+ * 数据解包封装,用于将zip、tar等包解包为文件
+ *
+ * @author looly
+ * @since 5.5.0
+ */
+public interface Extractor {
+
+}

+ 69 - 0
hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/StreamExtractor.java

@@ -0,0 +1,69 @@
+package cn.hutool.extra.compress.extractor;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IORuntimeException;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.extra.compress.CompressException;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.ArchiveStreamFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+public class StreamExtractor {
+
+	private final ArchiveInputStream in;
+
+	public StreamExtractor(Charset charset, InputStream in) {
+		final ArchiveStreamFactory factory = new ArchiveStreamFactory(charset.name());
+		try {
+			this.in = factory.createArchiveInputStream(in);
+		} catch (ArchiveException e) {
+			throw new CompressException(e);
+		}
+	}
+
+	/**
+	 * 释放(解压)到指定目录
+	 *
+	 * @param targetDir 目标目录
+	 */
+	public void extract(File targetDir) {
+		try {
+			extractInternal(targetDir);
+		} catch (IOException e) {
+			throw new IORuntimeException(e);
+		}
+	}
+
+	/**
+	 * 释放(解压)到指定目录
+	 *
+	 * @param targetDir 目标目录
+	 * @throws IOException IO异常
+	 */
+	private void extractInternal(File targetDir) throws IOException {
+		Assert.isTrue(null != targetDir && targetDir.isDirectory(), "target must be dir.");
+		final ArchiveInputStream in = this.in;
+		ArchiveEntry entry;
+		File outItemFile;
+		while(null != (entry = this.in.getNextEntry())){
+			if(false == in.canReadEntryData(entry)){
+				// 无法读取的文件直接跳过
+				continue;
+			}
+			outItemFile = FileUtil.file(targetDir, entry.getName());
+			if(entry.isDirectory()){
+				// 创建对应目录
+				//noinspection ResultOfMethodCallIgnored
+				outItemFile.mkdirs();
+			} else {
+				FileUtil.writeFromStream(in, outItemFile);
+			}
+		}
+	}
+}

+ 11 - 0
hutool-extra/src/main/java/cn/hutool/extra/compress/extractor/package-info.java

@@ -0,0 +1,11 @@
+/**
+ * 基于commons-compress的解包(解压缩)封装
+ *
+ *  <p>
+ *     见:https://commons.apache.org/proper/commons-compress/
+ * </p>
+ * 
+ * @author looly
+ *
+ */
+package cn.hutool.extra.compress.extractor;

+ 40 - 36
hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerEngine.java

@@ -1,7 +1,5 @@
 package cn.hutool.extra.template.engine.freemarker;
 
-import java.io.IOException;
-
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.util.ClassUtil;
@@ -13,9 +11,12 @@ import freemarker.cache.ClassTemplateLoader;
 import freemarker.cache.FileTemplateLoader;
 import freemarker.template.Configuration;
 
+import java.io.IOException;
+
 /**
- * Beetl模板引擎封装
- * 
+ * FreeMarker模板引擎封装<br>
+ * 见:https://freemarker.apache.org/
+ *
  * @author looly
  */
 public class FreemarkerEngine implements TemplateEngine {
@@ -23,14 +24,16 @@ public class FreemarkerEngine implements TemplateEngine {
 	private Configuration cfg;
 
 	// --------------------------------------------------------------------------------- Constructor start
+
 	/**
 	 * 默认构造
 	 */
-	public FreemarkerEngine() {}
+	public FreemarkerEngine() {
+	}
 
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param config 模板配置
 	 */
 	public FreemarkerEngine(TemplateConfig config) {
@@ -39,7 +42,7 @@ public class FreemarkerEngine implements TemplateEngine {
 
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param freemarkerCfg {@link Configuration}
 	 */
 	public FreemarkerEngine(Configuration freemarkerCfg) {
@@ -49,7 +52,7 @@ public class FreemarkerEngine implements TemplateEngine {
 
 	@Override
 	public TemplateEngine init(TemplateConfig config) {
-		if(null == config){
+		if (null == config) {
 			config = TemplateConfig.DEFAULT;
 		}
 		init(createCfg(config));
@@ -58,29 +61,30 @@ public class FreemarkerEngine implements TemplateEngine {
 
 	/**
 	 * 初始化引擎
+	 *
 	 * @param freemarkerCfg Configuration
 	 */
-	private void init(Configuration freemarkerCfg){
+	private void init(Configuration freemarkerCfg) {
 		this.cfg = freemarkerCfg;
 	}
 
 	@Override
 	public Template getTemplate(String resource) {
-		if(null == this.cfg){
+		if (null == this.cfg) {
 			init(TemplateConfig.DEFAULT);
 		}
 		try {
 			return FreemarkerTemplate.wrap(this.cfg.getTemplate(resource));
-		} catch(IOException e) {
+		} catch (IOException e) {
 			throw new IORuntimeException(e);
-		}catch (Exception e) {
+		} catch (Exception e) {
 			throw new TemplateException(e);
 		}
 	}
 
 	/**
 	 * 创建配置项
-	 * 
+	 *
 	 * @param config 模板配置
 	 * @return {@link Configuration }
 	 */
@@ -94,30 +98,30 @@ public class FreemarkerEngine implements TemplateEngine {
 		cfg.setDefaultEncoding(config.getCharset().toString());
 
 		switch (config.getResourceMode()) {
-		case CLASSPATH:
-			cfg.setTemplateLoader(new ClassTemplateLoader(ClassUtil.getClassLoader(), config.getPath()));
-			break;
-		case FILE:
-			try {
-				cfg.setTemplateLoader(new FileTemplateLoader(FileUtil.file(config.getPath())));
-			} catch (IOException e) {
-				throw new IORuntimeException(e);
-			}
-			break;
-		case WEB_ROOT:
-			 try {
-				 cfg.setTemplateLoader(new FileTemplateLoader(FileUtil.file(FileUtil.getWebRoot(), config.getPath())));
-			 } catch (IOException e) {
-				 throw new IORuntimeException(e);
-			 }
-			break;
-		case STRING:
-			cfg.setTemplateLoader(new SimpleStringTemplateLoader());
-			break;
-		default:
-			break;
+			case CLASSPATH:
+				cfg.setTemplateLoader(new ClassTemplateLoader(ClassUtil.getClassLoader(), config.getPath()));
+				break;
+			case FILE:
+				try {
+					cfg.setTemplateLoader(new FileTemplateLoader(FileUtil.file(config.getPath())));
+				} catch (IOException e) {
+					throw new IORuntimeException(e);
+				}
+				break;
+			case WEB_ROOT:
+				try {
+					cfg.setTemplateLoader(new FileTemplateLoader(FileUtil.file(FileUtil.getWebRoot(), config.getPath())));
+				} catch (IOException e) {
+					throw new IORuntimeException(e);
+				}
+				break;
+			case STRING:
+				cfg.setTemplateLoader(new SimpleStringTemplateLoader());
+				break;
+			default:
+				break;
 		}
-		
+
 		return cfg;
 	}
 }

+ 3 - 3
hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/package-info.java

@@ -1,7 +1,7 @@
 /**
- * Freemarker实现
- * 
- * @author looly
+ * Freemarker实现<br>
+ * 见:https://freemarker.apache.org/
  *
+ * @author looly
  */
 package cn.hutool.extra.template.engine.freemarker;

+ 39 - 36
hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityEngine.java

@@ -7,10 +7,10 @@ import cn.hutool.extra.template.TemplateEngine;
 import org.apache.velocity.app.Velocity;
 
 /**
- * Velocity模板引擎
- * 
- * @author looly
+ * Velocity模板引擎<br>
+ * 见:http://velocity.apache.org/
  *
+ * @author looly
  */
 public class VelocityEngine implements TemplateEngine {
 
@@ -18,14 +18,16 @@ public class VelocityEngine implements TemplateEngine {
 	private TemplateConfig config;
 
 	// --------------------------------------------------------------------------------- Constructor start
+
 	/**
 	 * 默认构造
 	 */
-	public VelocityEngine() {}
+	public VelocityEngine() {
+	}
 
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param config 模板配置
 	 */
 	public VelocityEngine(TemplateConfig config) {
@@ -34,7 +36,7 @@ public class VelocityEngine implements TemplateEngine {
 
 	/**
 	 * 构造
-	 * 
+	 *
 	 * @param engine {@link org.apache.velocity.app.VelocityEngine}
 	 */
 	public VelocityEngine(org.apache.velocity.app.VelocityEngine engine) {
@@ -44,7 +46,7 @@ public class VelocityEngine implements TemplateEngine {
 
 	@Override
 	public TemplateEngine init(TemplateConfig config) {
-		if(null == config){
+		if (null == config) {
 			config = TemplateConfig.DEFAULT;
 		}
 		this.config = config;
@@ -54,15 +56,16 @@ public class VelocityEngine implements TemplateEngine {
 
 	/**
 	 * 初始化引擎
+	 *
 	 * @param engine 引擎
 	 */
-	private void init(org.apache.velocity.app.VelocityEngine engine){
+	private void init(org.apache.velocity.app.VelocityEngine engine) {
 		this.engine = engine;
 	}
 
 	/**
 	 * 获取原始的引擎对象
-	 * 
+	 *
 	 * @return 原始引擎对象
 	 * @since 4.3.0
 	 */
@@ -72,7 +75,7 @@ public class VelocityEngine implements TemplateEngine {
 
 	@Override
 	public Template getTemplate(String resource) {
-		if(null == this.engine){
+		if (null == this.engine) {
 			init(TemplateConfig.DEFAULT);
 		}
 
@@ -80,15 +83,15 @@ public class VelocityEngine implements TemplateEngine {
 		String root;
 		// 自定义编码
 		String charsetStr = null;
-		if(null != this.config){
+		if (null != this.config) {
 			root = this.config.getPath();
 			charsetStr = this.config.getCharsetStr();
 
 			// 修正template目录,在classpath或者web_root模式下,按照配置添加默认前缀
 			// 如果用户已经自行添加了前缀,则忽略之
 			final TemplateConfig.ResourceMode resourceMode = this.config.getResourceMode();
-			if(TemplateConfig.ResourceMode.CLASSPATH == resourceMode
-					|| TemplateConfig.ResourceMode.WEB_ROOT == resourceMode){
+			if (TemplateConfig.ResourceMode.CLASSPATH == resourceMode
+					|| TemplateConfig.ResourceMode.WEB_ROOT == resourceMode) {
 				resource = StrUtil.addPrefixIfNot(resource, StrUtil.addSuffixIfNot(root, "/"));
 			}
 		}
@@ -98,7 +101,7 @@ public class VelocityEngine implements TemplateEngine {
 
 	/**
 	 * 创建引擎
-	 * 
+	 *
 	 * @param config 模板配置
 	 * @return {@link org.apache.velocity.app.VelocityEngine}
 	 */
@@ -116,29 +119,29 @@ public class VelocityEngine implements TemplateEngine {
 
 		// loader
 		switch (config.getResourceMode()) {
-		case CLASSPATH:
-			// 新版Velocity弃用
+			case CLASSPATH:
+				// 新版Velocity弃用
 //			ve.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
-			ve.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
-			break;
-		case FILE:
-			// path
-			final String path = config.getPath();
-			if (null != path) {
-				ve.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, path);
-			}
-			break;
-		case WEB_ROOT:
-			ve.setProperty(Velocity.RESOURCE_LOADER, "webapp");
-			ve.setProperty("webapp.resource.loader.class", "org.apache.velocity.tools.view.servlet.WebappLoader");
-			ve.setProperty("webapp.resource.loader.path", StrUtil.nullToDefault(config.getPath(), StrUtil.SLASH));
-			break;
-		case STRING:
-			ve.setProperty(Velocity.RESOURCE_LOADER, "str");
-			ve.setProperty("str.resource.loader.class", SimpleStringResourceLoader.class.getName());
-			break;
-		default:
-			break;
+				ve.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+				break;
+			case FILE:
+				// path
+				final String path = config.getPath();
+				if (null != path) {
+					ve.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, path);
+				}
+				break;
+			case WEB_ROOT:
+				ve.setProperty(Velocity.RESOURCE_LOADER, "webapp");
+				ve.setProperty("webapp.resource.loader.class", "org.apache.velocity.tools.view.servlet.WebappLoader");
+				ve.setProperty("webapp.resource.loader.path", StrUtil.nullToDefault(config.getPath(), StrUtil.SLASH));
+				break;
+			case STRING:
+				ve.setProperty(Velocity.RESOURCE_LOADER, "str");
+				ve.setProperty("str.resource.loader.class", SimpleStringResourceLoader.class.getName());
+				break;
+			default:
+				break;
 		}
 
 		ve.init();

+ 3 - 3
hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/package-info.java

@@ -1,7 +1,7 @@
 /**
- * Velocity实现
- * 
- * @author looly
+ * Velocity实现<br>
+ * 见:http://velocity.apache.org/
  *
+ * @author looly
  */
 package cn.hutool.extra.template.engine.velocity;