Эх сурвалжийг харах

修改上传组件 md5问题

NorthLan 6 жил өмнө
parent
commit
ac0554e93f

+ 3 - 3
build.gradle

@@ -29,7 +29,7 @@ buildscript {
     }
     repositories {
         mavenCentral()
-        maven { url 'http://repo.spring.io/plugins-release' }
+        maven { url = 'http://repo.spring.io/plugins-release' }
     }
     dependencies {
         classpath 'io.spring.gradle:propdeps-plugin:0.0.9.RELEASE'
@@ -40,8 +40,8 @@ buildscript {
 }
 
 allprojects {
-    group "com.gxzc.zen"
-    version "1.0-SNAPSHOT"
+    group = "com.gxzc.zen"
+    version = "1.0-SNAPSHOT"
 }
 
 subprojects {

+ 54 - 59
zen-core/src/main/kotlin/com/gxzc/zen/common/util/UploadUtil.kt

@@ -59,15 +59,16 @@ object UploadUtil {
             // 文件分片 如果分片小于chunkSize && totalChunk = 1,直接转存
             if (fileMetadata.totalChunks == 1 && fileMetadata.chunkSize!! <= chunkSize) {
                 val filename = fileMetadata.filename!!
-                val relativePath = fileMetadata.relativePath!!
-
-                val destPath = FilenameUtils.normalize("$dataPath$FILE_SEPARATOR${getDestFilePath(filename, relativePath, fileMetadata.repath)}")
-                val destDir = Paths.get(destPath)
-                if (Files.notExists(destDir)) {
-                    Files.createDirectories(destDir)
+                val md5 = fileMetadata.md5!!
+
+                // 目标文件流 通过文件名来拼接
+                val outputFullFilename = getFullDestFilename(dataPath, filename, md5)
+                val outputPath = Paths.get(FilenameUtils.getFullPath(outputFullFilename))
+                // 不存在则创建文件夹
+                if (Files.notExists(outputPath)) {
+                    Files.createDirectories(outputPath)
                 }
-                val outputPath = FilenameUtils.normalize("$destPath$FILE_SEPARATOR${getDestFileName(filename, fileMetadata.rename)}")
-                retFile = File(outputPath)
+                retFile = File(outputFullFilename)
                 file.transferTo(retFile)
                 retFile.setLastModified(fileMetadata.lastModified!!)
             } else {
@@ -102,11 +103,15 @@ object UploadUtil {
         }
     }
 
+    /**
+     * 设置批次文件数量信息 ++
+     */
     private fun setBatch(fileMetadata: ZenFileMetadata): String {
         val batchId = fileMetadata.batchId!!
         val totalNumber = fileMetadata.totalNumber!!
         synchronized(batchCountMap) {
             var count = batchCountMap[batchId]?.get() as? Int ?: 0
+            logger.debug("batchId: $batchId, count: ${count + 1}, totalNumber: $totalNumber")
             return if (++count >= totalNumber) {
                 batchCountMap.evict(batchId)
                 STATUS.BATCH_UPLOADED
@@ -119,18 +124,20 @@ object UploadUtil {
 
     /**
      * 检测文件是否存在 实现文件秒传
+     * 真实文件已存在,秒传
+     * 真实文件不存在,检查分片上传情况
      */
     fun checkUpload(fileMetadata: ZenFileMetadata): ZenFileResponse {
+        val tmpPath = uploadProperties!!.tmpPath!!
         val dataPath = uploadProperties!!.dataPath!!
-        val ret = ZenFileResponse()
+        val ret = ZenFileResponse().apply { status = STATUS.CHECKING }
         if (validateRequest(fileMetadata, null)) {
             if (fileExists(fileMetadata)) {
                 ret.uploadedChunks = mutableListOf()
                 for (i in 1..fileMetadata.totalChunks!!) {
-                    ret.uploadedChunks?.add(i)
+                    ret.uploadedChunks!!.add(i)
                 }
-                ret.status = setBatch(fileMetadata)
-                ret.file = File(getFullDestFilename(dataPath, fileMetadata.filename!!, fileMetadata.relativePath!!, fileMetadata.repath, fileMetadata.rename))
+                ret.file = File(getFullDestFilename(dataPath, fileMetadata.filename!!, fileMetadata.md5!!))
             } else {
                 // 检查分片存在情况
                 for (i in 1..fileMetadata.totalChunks!!) {
@@ -138,15 +145,28 @@ object UploadUtil {
                         if (ret.uploadedChunks == null) {
                             ret.uploadedChunks = mutableListOf()
                         }
-                        ret.uploadedChunks?.add(i)
+                        ret.uploadedChunks!!.add(i)
                     }
                 }
                 if (ret.uploadedChunks != null && ret.uploadedChunks!!.size == fileMetadata.totalChunks) {
-                    ret.status = STATUS.CHECKING // 秒传
-                    // 所有分块传完 移除其中一个分块,再传一次而后 merge
-                    ret.uploadedChunks!!.removeAt(0)
+                    // 合并
+                    ret.file = try {
+                        mergeChunks(tmpPath, dataPath, fileMetadata)
+                    } catch (e: Throwable) {
+                        logger.error("merge file chunks exception, cause ", e)
+                        uploadedStatusMap.remove(fileMetadata.md5!!)
+                        null
+                    }
+
+//                    // 所有分块传完 移除其中一个分块,再传一次而后 merge
+//                    ret.uploadedChunks!!.removeAt(0)
                 }
             }
+        } else {
+            throw ZenException(ZenExceptionEnum.FILE_METADATA_VALIDATE_ERROR)
+        }
+        if (ret.file != null) {
+            ret.status = setBatch(fileMetadata)
         }
         return ret
     }
@@ -158,10 +178,9 @@ object UploadUtil {
         val dataPath = uploadProperties!!.dataPath!!
         // 获取filename 真实文件
         val filename = fileMetadata.filename!!
-        val relativePath = fileMetadata.relativePath!!
         val md5 = fileMetadata.md5!!
-        val path = getFullDestFilename(dataPath, filename, relativePath, fileMetadata.repath, fileMetadata.rename)
-        return Files.exists(Paths.get(path)) && FileUtil.md5HeadTail(path, uploadProperties!!.chunkSize!!.toInt()) == md5 // # 防篡改
+        val realFilename = getFullDestFilename(dataPath, filename, md5)
+        return Files.exists(Paths.get(realFilename)) && FileUtil.md5HeadTail(realFilename, uploadProperties!!.chunkSize!!.toInt()) == md5 // # 防篡改
     }
 
     /**
@@ -193,7 +212,6 @@ object UploadUtil {
     private fun mergeChunks(sourceRootPath: String, destRootPath: String, fileMetadata: ZenFileMetadata): File? {
         // 源文件的文件夹信息 然后组合拼接
         val filename = fileMetadata.filename!!
-        val relativePath = fileMetadata.relativePath!!
         val totalChunks = fileMetadata.totalChunks!!
         val md5 = fileMetadata.md5!!
 
@@ -206,14 +224,14 @@ object UploadUtil {
         val t = System.currentTimeMillis()
         logger.debug("start merging chunks for [$filename], now: $t")
 
-        val destPath = getFullDestFilepath(destRootPath, filename, relativePath, fileMetadata.repath, fileMetadata.rename)
-        val destDir = Paths.get(destPath)
-        if (Files.notExists(destDir)) {
-            Files.createDirectories(destDir)
-        }
         // 目标文件流 通过文件名来拼接
-        val outputPath = getFullDestFilename(destRootPath, filename, relativePath, fileMetadata.repath, fileMetadata.rename)
-        val outputFile = File(outputPath)
+        val outputFullFilename = getFullDestFilename(destRootPath, filename, md5)
+        val outputPath = Paths.get(FilenameUtils.getFullPath(outputFullFilename))
+        // 不存在则创建文件夹
+        if (Files.notExists(outputPath)) {
+            Files.createDirectories(outputPath)
+        }
+        val outputFile = File(outputFullFilename)
         val destOutputStream = BufferedOutputStream(FileOutputStream(outputFile))
 
         val buffer = ByteArray(4096)
@@ -246,52 +264,29 @@ object UploadUtil {
     }
 
     /**
-     * 获取 分片文件名
+     * 生成 分片文件名
      */
     private fun getChunkFilename(path: String, chunkNumber: Int?, identifier: String?): String {
         return "$path/upload-$identifier.$chunkNumber"
     }
 
     /**
-     * 生成 输出的文件名
-     */
-    private fun getDestFileName(filename: String, rename: String?): String {
-        return if (rename == null || rename.isEmpty()) {
-            filename
-        } else {
-            // 后缀
-            val ext = FilenameUtils.getExtension(rename)
-            if (ext.isNullOrEmpty()) {
-                "$rename.${FilenameUtils.getExtension(filename)}"
-            } else {
-                rename
-            }
-        }
-    }
-
-    /**
-     * 生成 输出的文件夹结构
+     * 生成 输出文件名
      */
-    private fun getDestFilePath(filename: String, relativePath: String, repath: String?): String {
-        return if (repath.isNullOrEmpty()) {
-            relativePath.replace(filename, "")
+    private fun getDestFileName(filename: String, md5: String): String {
+        val ext = FilenameUtils.getExtension(filename)
+        return if (!ext.isNullOrEmpty()) {
+            "$md5.$ext"
         } else {
-            repath!!
+            md5
         }
     }
 
-    /**
-     * 获取输出完整文件路径
-     */
-    private fun getFullDestFilepath(dataPath: String, filename: String, relativePath: String, repath: String?, rename: String?): String {
-        return FilenameUtils.getFullPath(getFullDestFilename(dataPath, filename, relativePath, repath, rename))
-    }
-
     /**
      * 获取输出完整文件名
      */
-    private fun getFullDestFilename(dataPath: String, filename: String, relativePath: String, repath: String?, rename: String?): String {
-        return FilenameUtils.normalize("$dataPath$FILE_SEPARATOR${getDestFilePath(filename, relativePath, repath)}$FILE_SEPARATOR${getDestFileName(filename, rename)}")
+    private fun getFullDestFilename(dataPath: String, filename: String, md5: String): String {
+        return FilenameUtils.normalize("$dataPath$FILE_SEPARATOR${getDestFileName(filename, md5)}")
     }
 
     /**