|
|
@@ -11,11 +11,16 @@ import java.io.OutputStream;
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
import java.net.URLDecoder;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
+import java.nio.file.attribute.FileTime;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collection;
|
|
|
+import java.util.Comparator;
|
|
|
import java.util.Enumeration;
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
import java.util.Objects;
|
|
|
+import java.util.stream.Collectors;
|
|
|
import java.util.zip.ZipEntry;
|
|
|
import java.util.zip.ZipFile;
|
|
|
import java.util.zip.ZipOutputStream;
|
|
|
@@ -31,6 +36,13 @@ public final class JarUtil {
|
|
|
/** 打包时需要忽略的(可能由操作系统产生的)文件 */
|
|
|
private static final String[] IGNORE_FILE_SUFFIX = {".DS_Store", "Thumbs.db"};
|
|
|
|
|
|
+ /**
|
|
|
+ * @see JarUtil#doJarWar(String, String, FileOrderSupport)
|
|
|
+ */
|
|
|
+ public static String doJarWar(String srcDir, String targetJarOrWar) {
|
|
|
+ return doJarWar(srcDir, targetJarOrWar, null);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 把目录压缩成jar(or war)
|
|
|
*
|
|
|
@@ -38,12 +50,19 @@ public final class JarUtil {
|
|
|
* 需要打包的目录(如 /tmp/demo-1.0.0/)
|
|
|
* @param targetJarOrWar
|
|
|
* 打包出的jar/war文件路径(如 /tmp/abc.jar)
|
|
|
+ * @param fileOrderSupport
|
|
|
+ * 文件排序序号提供者<br>
|
|
|
+ * 注:部分jar包会对jar包内的条目有顺序要求(如:spring-boot的jar包的lib目录下,lib包的顺序要和pom.xml中的声明顺序保持一致),
|
|
|
+ * 此时就可以使用此字段来实现排序了。
|
|
|
* @return 打包出的jar/war文件路径
|
|
|
*/
|
|
|
- public static String doJarWar(String srcDir, String targetJarOrWar) {
|
|
|
+ public static String doJarWar(String srcDir, String targetJarOrWar, FileOrderSupport fileOrderSupport) {
|
|
|
File jarDirFile = new File(srcDir);
|
|
|
// 枚举jarDir下的所有文件以及目录
|
|
|
List<File> files = IOUtil.listSubFile(jarDirFile, 0);
|
|
|
+ if (fileOrderSupport != null) {
|
|
|
+ files = files.stream().sorted(Comparator.comparing(fileOrderSupport::obtainFileOrder)).collect(Collectors.toList());
|
|
|
+ }
|
|
|
ZipOutputStream zos = null;
|
|
|
OutputStream out = null;
|
|
|
try {
|
|
|
@@ -65,7 +84,8 @@ public final class JarUtil {
|
|
|
// 目录,添加一个目录entry
|
|
|
if (file.isDirectory()) {
|
|
|
ZipEntry zipEntry = new ZipEntry(fileName + Constant.LINUX_FILE_SEPARATOR);
|
|
|
- zipEntry.setTime(System.currentTimeMillis());
|
|
|
+ zipEntry.setTime(file.lastModified());
|
|
|
+ zipEntry.setLastModifiedTime(FileTime.fromMillis(file.lastModified()));
|
|
|
zos.putNextEntry(zipEntry);
|
|
|
zos.closeEntry();
|
|
|
}
|
|
|
@@ -75,8 +95,9 @@ public final class JarUtil {
|
|
|
ZipEntry ze = new ZipEntry(fileName);
|
|
|
ze.setMethod(ZipEntry.STORED);
|
|
|
ze.setSize(bytes.length);
|
|
|
- ze.setTime(System.currentTimeMillis());
|
|
|
ze.setCrc(IOUtil.computeCrc32(bytes));
|
|
|
+ ze.setTime(file.lastModified());
|
|
|
+ ze.setLastModifiedTime(FileTime.fromMillis(file.lastModified()));
|
|
|
zos.putNextEntry(ze);
|
|
|
zos.write(bytes);
|
|
|
zos.closeEntry();
|
|
|
@@ -84,7 +105,8 @@ public final class JarUtil {
|
|
|
// 其它文件直接写入
|
|
|
else {
|
|
|
ZipEntry zipEntry = new ZipEntry(fileName);
|
|
|
- zipEntry.setTime(System.currentTimeMillis());
|
|
|
+ zipEntry.setTime(file.lastModified());
|
|
|
+ zipEntry.setLastModifiedTime(FileTime.fromMillis(file.lastModified()));
|
|
|
zos.putNextEntry(zipEntry);
|
|
|
byte[] bytes = IOUtil.toBytes(file);
|
|
|
zos.write(bytes);
|
|
|
@@ -123,7 +145,7 @@ public final class JarUtil {
|
|
|
* 注:当entry对应jar或者war中的目录时,那么其值形如 BOOT-INF/classes/
|
|
|
* <br/>
|
|
|
* 注:当entry对应jar或者war中的文件时,那么其值形如 BOOT-INF/classes/com/example/ssm/author/JustryDeng.class
|
|
|
- * @return 解压出来的文件(包含目录)的完整路径
|
|
|
+ * @return (按压缩文件中条目的顺序)解压出来的(有序的)文件(包含目录)的完整路径
|
|
|
*/
|
|
|
public static <T extends Collection<String>> List<String> unJarWar(String jarWarPath, String targetDir,
|
|
|
boolean delOldTargetDirIfAlreadyExist,
|
|
|
@@ -136,6 +158,9 @@ public final class JarUtil {
|
|
|
guarantyDirExist(target);
|
|
|
|
|
|
ZipFile zipFile = null;
|
|
|
+ // 此集合中的file会保留上一次修改时间,不会被当前解压操作覆盖
|
|
|
+ List<String> storeLastModifiedTimeList = new ArrayList<>();
|
|
|
+ Map<String, Long> filePthAndLastModifiedTimeMap = new HashMap<>(64);
|
|
|
try {
|
|
|
zipFile = new ZipFile(new File(jarWarPath));
|
|
|
ZipEntry entry;
|
|
|
@@ -152,6 +177,9 @@ public final class JarUtil {
|
|
|
if (entry.isDirectory()) {
|
|
|
targetFile = new File(target, entryName);
|
|
|
guarantyDirExist(targetFile);
|
|
|
+ String absolutePath = targetFile.getAbsolutePath();
|
|
|
+ storeLastModifiedTimeList.add(absolutePath);
|
|
|
+ filePthAndLastModifiedTimeMap.put(absolutePath, entry.getLastModifiedTime().toMillis());
|
|
|
} else {
|
|
|
// 有时遍历时,文件先于文件夹出来,所以也得保证目录存在
|
|
|
int lastSeparatorIndex = entryName.lastIndexOf(Constant.LINUX_FILE_SEPARATOR);
|
|
|
@@ -162,7 +190,10 @@ public final class JarUtil {
|
|
|
targetFile = new File(target, entryName);
|
|
|
byte[] bytes = IOUtil.toBytes(zipFile.getInputStream(entry));
|
|
|
IOUtil.toFile(bytes, targetFile, true);
|
|
|
- list.add(targetFile.getAbsolutePath());
|
|
|
+ String absolutePath = targetFile.getAbsolutePath();
|
|
|
+ list.add(absolutePath);
|
|
|
+ storeLastModifiedTimeList.add(absolutePath);
|
|
|
+ filePthAndLastModifiedTimeMap.put(absolutePath, entry.getLastModifiedTime().toMillis());
|
|
|
}
|
|
|
}
|
|
|
} catch (IOException e) {
|
|
|
@@ -170,6 +201,11 @@ public final class JarUtil {
|
|
|
} finally {
|
|
|
IOUtil.close(zipFile);
|
|
|
}
|
|
|
+ for (String filePath : storeLastModifiedTimeList) {
|
|
|
+ Long lastModifiedTime = filePthAndLastModifiedTimeMap.get(filePath);
|
|
|
+ //noinspection ResultOfMethodCallIgnored
|
|
|
+ new File(filePath).setLastModified(lastModifiedTime == null ? System.currentTimeMillis() : lastModifiedTime);
|
|
|
+ }
|
|
|
return list;
|
|
|
}
|
|
|
|