Browse Source

backup when uploading files

sunyj 7 years ago
parent
commit
fb0a157692

+ 6 - 0
report-common/src/main/java/com/uas/report/util/Assert.java

@@ -25,4 +25,10 @@ public class Assert {
             throw new IllegalArgumentException(message);
         }
     }
+
+    public static void isTrue(boolean expression, String message) {
+        if (!expression) {
+            throw new IllegalArgumentException(message);
+        }
+    }
 }

+ 89 - 0
report-common/src/main/java/com/uas/report/util/FileUtils.java

@@ -8,6 +8,8 @@ import java.nio.ByteBuffer;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.WritableByteChannel;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 /**
  * 文件操作工具类
@@ -352,4 +354,91 @@ public class FileUtils {
 		stream.close();
 		return bytesOut.toByteArray();
 	}
+
+    /**
+     * 备份文件
+     *
+     * @param file 文件
+     */
+    public static void backup(File file) throws IOException {
+        backup(file, null);
+    }
+
+    /**
+     * 备份文件
+     *
+     * @param file    文件
+     * @param maxCopy 备份最大数量,超过限制后删除最旧的备份
+     */
+    public static void backup(File file, Integer maxCopy) throws IOException {
+        Assert.notNull(file, "file is null");
+        if (maxCopy != null) {
+            Assert.isTrue(maxCopy > 0, "maxCopy must be greater than 0");
+        } else {
+            maxCopy = 64;
+        }
+        if (!file.exists()) {
+            return;
+        } else if (file.isDirectory()) {
+            throw new IOException("不支持备份文件夹");
+        }
+        File dir = file.getParentFile();
+        final String fileName = file.getName();
+        File[] files = dir.listFiles(new FilenameFilter() {
+            @Override
+            public boolean accept(File dir, String name) {
+                // 文件名称可能含有特殊字符,因此先去除文件名,再利用正则进行匹配
+                if (!name.startsWith(fileName)) {
+                    return false;
+                }
+                name = name.substring(fileName.length());
+                return name.matches("^_\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}-\\d{3}\\.bak$");
+            }
+        });
+        if (files != null && files.length >= maxCopy) {
+            sort(files);
+            // 只保留指定数量的备份,删除最旧的
+            for (int i = 0; i <= files.length - maxCopy; i++) {
+                if (!files[i].delete()) {
+                    throw new IOException("备份删除失败:" + files[i].getPath());
+                }
+            }
+        }
+        File copy = new File(dir, fileName + "_" + new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss-SSS").format(new Date()) + ".bak");
+        copy(file, copy);
+    }
+
+    /**
+     * 根据文件的最近修改时间进行排序(增序)
+     *
+     * @param files
+     */
+    private static void sort(File[] files) {
+        int N = files.length;
+        int h = 1;
+        while (h < N / 3) {
+            h = h * 3 + 1;
+        }
+        while (h >= 1) {
+            for (int i = h; i < N; i++) {
+                for (int j = i; j >= h && less(files[j], files[j - h]); j -= h) {
+                    exchange(files, j, j - h);
+                }
+            }
+            h /= 3;
+        }
+    }
+
+    private static boolean less(File f1, File f2) {
+        return f1.lastModified() < f2.lastModified();
+    }
+
+    /**
+     * 交换位置
+     */
+    private static void exchange(File[] files, int i, int j) {
+        File temp = files[i];
+        files[i] = files[j];
+        files[j] = temp;
+    }
 }

+ 16 - 23
report-common/src/main/java/com/uas/report/util/ZipUtils.java

@@ -1,15 +1,9 @@
 package com.uas.report.util;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
 import java.nio.charset.Charset;
 import java.util.Enumeration;
 import java.util.zip.ZipEntry;
@@ -17,9 +11,6 @@ import java.util.zip.ZipFile;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 /**
  * 压缩工具类
  * 
@@ -131,16 +122,15 @@ public class ZipUtils {
 		}
 	}
 
-	/**
-	 * 解压缩
-	 * 
-	 * @param zipData
-	 *            压缩包数据
-	 * @param folderPath
-	 *            解压缩后的文件路径
-	 * @throws IOException
-	 */
-	public static void unzip(byte[] zipData, String folderPath) throws IOException {
+    /**
+     * 解压缩
+     *
+     * @param zipData    压缩包数据
+     * @param folderPath 解压缩后的文件路径
+     * @param ifBackup   是否备份文件
+     * @throws IOException
+     */
+    public static void unzip(byte[] zipData, String folderPath, boolean ifBackup) throws IOException {
 		if (StringUtils.isEmpty(folderPath)) {
 			return;
 		}
@@ -160,6 +150,9 @@ public class ZipUtils {
 				outFile.getParentFile().mkdirs();
 			}
 
+            if(ifBackup){
+                FileUtils.backup(outFile);
+            }
 			OutputStream outputStream = new FileOutputStream(outFile);
 			int b;
 			while ((b = zipInputStream.read()) != -1) {

+ 6 - 4
report/src/main/java/com/uas/report/service/impl/FileServiceImpl.java

@@ -59,7 +59,7 @@ public class FileServiceImpl implements FileService {
 			// 不支持查看、压缩:jasper文件、tmp路径
 			String filePath = file.getPath().toLowerCase();
 			if (filePath.endsWith(".jasper") || filePath.endsWith("tmp") || filePath.contains("\\tmp\\")
-					|| filePath.contains("/tmp/")) {
+					|| filePath.contains("/tmp/") || filePath.endsWith(".bak")) {
 				return false;
 			}
 			return true;
@@ -90,7 +90,7 @@ public class FileServiceImpl implements FileService {
 		String[] userNameArray = destinationUserNames.split(",");
 		// 创建账套路径并解压模板zip包
 		for (String userName : userNameArray) {
-			ZipUtils.unzip(data, getMasterPath(userName));
+			ZipUtils.unzip(data, getMasterPath(userName), true);
 		}
 		return "已自动部署:" + destinationUserNames;
 	}
@@ -113,7 +113,7 @@ public class FileServiceImpl implements FileService {
 				@Override
 				public void run() {
 					try {
-						ZipUtils.unzip(file.getBytes(), getMasterPath(userName));
+						ZipUtils.unzip(file.getBytes(), getMasterPath(userName), true);
 					} catch (IOException e) {
 						throw new IllegalStateException("文件解压失败", e);
 					}
@@ -142,6 +142,7 @@ public class FileServiceImpl implements FileService {
 			targetFile.getParentFile().mkdirs();
 		}
 		try {
+		    FileUtils.backup(targetFile);
 			FileUtils.write(targetFile.getAbsolutePath(), file.getBytes(), true);
 			return "成功上传文件至:" + targetFile.getPath();
 		} catch (IllegalStateException | IOException e) {
@@ -170,7 +171,8 @@ public class FileServiceImpl implements FileService {
 			// 因为在spring boot下上传文件时会对临时路径进行处理,
 			// 导致最终文件路径不正确,如果手动设置临时路径为根路径,
 			// 又会因为权限问题导致文件写入失败,
-			// 所以自己在指定路径创建文件,而不使用transferTo方法
+			// 所以改为在指定路径创建文件,而不使用transferTo方法
+            FileUtils.backup(targetFile);
 			FileUtils.write(targetFile.getAbsolutePath(), file.getBytes(), true);
 			stringBuilder.append("上传成功:").append(fileName).append("\n");
 		}