Browse Source

优化文件上传逻辑

zhouhao 7 năm trước cách đây
mục cha
commit
ef96ed01a6

+ 40 - 11
hsweb-system/hsweb-system-file/hsweb-system-file-controller/src/main/java/org/hswebframework/web/controller/file/FileController.java

@@ -1,13 +1,16 @@
 package org.hswebframework.web.controller.file;
 
 import com.alibaba.fastjson.JSON;
+import org.apache.commons.fileupload.ParameterParser;
 import org.hswebframework.expands.compress.Compress;
 import org.hswebframework.expands.compress.zip.ZIPWriter;
 import org.hswebframework.utils.StringUtils;
 import org.hswebframework.web.BusinessException;
 import org.hswebframework.web.NotFoundException;
+import org.hswebframework.web.WebUtil;
 import org.hswebframework.web.authorization.Authentication;
 import org.hswebframework.web.authorization.annotation.Authorize;
+import org.hswebframework.web.commons.entity.DataStatus;
 import org.hswebframework.web.controller.message.ResponseMessage;
 import org.hswebframework.web.entity.file.FileInfoEntity;
 import org.hswebframework.web.logging.AccessLogger;
@@ -16,7 +19,6 @@ import org.hswebframework.web.service.file.FileService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -26,14 +28,18 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import static java.util.Optional.ofNullable;
+
 /**
  * 文件操作控制器,提供文件上传下载等操作
  *
@@ -126,6 +132,7 @@ public class FileController {
                              @PathVariable("name") String name,
                              HttpServletResponse response,
                              HttpServletRequest request) throws IOException {
+
         downLoad(id, name, response, request);
     }
 
@@ -149,7 +156,7 @@ public class FileController {
                          HttpServletResponse response, HttpServletRequest request)
             throws IOException {
         FileInfoEntity fileInfo = fileInfoService.selectByIdOrMd5(idOrMd5);
-        if (fileInfo == null || fileInfo.getStatus() != 1) {
+        if (fileInfo == null || !DataStatus.STATUS_ENABLED.equals(fileInfo.getStatus())) {
             throw new NotFoundException("文件不存在");
         }
         String fileName = fileInfo.getName();
@@ -174,9 +181,9 @@ public class FileController {
         //尝试判断是否为断点下载
         try {
             //获取要继续下载的位置
-            String Range = request.getHeader("Range").replaceAll("bytes=", "").replaceAll("-", "");
+            String Range = request.getHeader("Range").replace("bytes=", "").replace("-", "");
             skip = StringUtils.toInt(Range);
-        } catch (Exception e) {
+        } catch (Exception ignore) {
         }
         response.setContentLength((int) fSize);//文件大小
         response.setContentType(contentType);
@@ -205,7 +212,12 @@ public class FileController {
                 .map(this::upload)
                 .map(ResponseMessage::getResult)
                 .collect(Collectors.toList()))
-                .include(FileInfoEntity.class, FileInfoEntity.id, FileInfoEntity.name, FileInfoEntity.md5);
+                .include(FileInfoEntity.class,
+                        FileInfoEntity.id,
+                        FileInfoEntity.name,
+                        FileInfoEntity.md5,
+                        FileInfoEntity.size,
+                        FileInfoEntity.type);
     }
 
     /**
@@ -224,9 +236,21 @@ public class FileController {
         if (file.isEmpty()) {
             return ResponseMessage.ok();
         }
-        if (logger.isInfoEnabled())
-            logger.info("start write file:{}", file.getOriginalFilename());
         String fileName = file.getOriginalFilename();
+        String contentType = Optional.ofNullable(WebUtil.getHttpServletRequest())
+                .orElseThrow(UnsupportedOperationException::new)
+                .getContentType();
+        ParameterParser parser = new ParameterParser();
+        Map<String, String> params = parser.parse(contentType, ';');
+        if (params.get("charset") == null) {
+            try {
+                fileName = new String(file.getOriginalFilename().getBytes("ISO-8859-1"), "utf-8");
+            } catch (UnsupportedEncodingException ignore) {
+            }
+        }
+        if (logger.isInfoEnabled())
+            logger.info("start write file:{}", fileName);
+
         FileInfoEntity fileInfo;
         try {
             fileInfo = fileService.saveFile(file.getInputStream(), fileName, file.getContentType(), creator);
@@ -235,13 +259,17 @@ public class FileController {
         }
         fileInfoList.add(fileInfo);
         return ResponseMessage.ok(fileInfo)
-                .include(FileInfoEntity.class, FileInfoEntity.id, FileInfoEntity.name, FileInfoEntity.md5);
+                .include(FileInfoEntity.class, FileInfoEntity.id,
+                        FileInfoEntity.name,
+                        FileInfoEntity.md5,
+                        FileInfoEntity.size,
+                        FileInfoEntity.type);
     }
 
     @PostMapping(value = "/upload-static")
     @AccessLogger("上传静态文件")
     @Authorize(action = "static")
-    public ResponseMessage<String> uploadStatic(MultipartFile file) throws IOException {
+    public ResponseMessage<String> uploadStatic(@RequestParam("file") MultipartFile file) throws IOException {
         if (file.isEmpty()) return ResponseMessage.ok();
         return ResponseMessage.ok(fileService.saveStaticFile(file.getInputStream(), file.getOriginalFilename()));
     }
@@ -249,7 +277,8 @@ public class FileController {
     @GetMapping(value = "/md5/{md5}")
     @AccessLogger("根据MD5获取文件信息")
     public ResponseMessage<FileInfoEntity> uploadStatic(@PathVariable String md5) throws IOException {
-        return ResponseMessage
-                .ok(fileInfoService.selectByMd5(md5));
+        return ofNullable(fileInfoService.selectByMd5(md5))
+                .map(ResponseMessage::ok)
+                .orElseThrow(() -> new NotFoundException("file not found"));
     }
 }

+ 15 - 24
hsweb-system/hsweb-system-file/hsweb-system-file-service/hsweb-system-file-service-simple/src/main/java/org/hswebframework/web/service/file/simple/LocalFileService.java

@@ -33,7 +33,7 @@ public class LocalFileService implements FileService {
     /**
      * 静态文件访问地址,上传静态文件后,将返回此地址+文件相对地址,以/结尾
      */
-    private String staticLocation = "/upload";
+    private String staticLocation = "/upload/";
 
     /**
      * 文件上传目录
@@ -45,7 +45,7 @@ public class LocalFileService implements FileService {
         this.staticFilePath = staticFilePath;
     }
 
-    @Value("${hsweb.web.upload.static-location:/upload}")
+    @Value("${hsweb.web.upload.static-location:/upload/}")
     public void setStaticLocation(String staticLocation) {
         this.staticLocation = staticLocation;
     }
@@ -127,17 +127,10 @@ public class LocalFileService implements FileService {
         if (!path.exists()) path.mkdirs(); //创建目录
         String newName = String.valueOf(System.nanoTime()); //临时文件名 ,纳秒的md5值
         String fileAbsName = absPath.concat("/").concat(newName);
-        //try with resource
-        long fileLength = 0;
+        long fileLength;
         try (BufferedInputStream in = new BufferedInputStream(fileStream);
-             BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(fileAbsName))) {
-            byte[] buffer = new byte[2048 * 10];
-            int len;
-            while ((len = in.read(buffer)) != -1) {
-                fileLength += len;
-                os.write(buffer, 0, len);
-            }
-            os.flush();
+             FileOutputStream os = new FileOutputStream(fileAbsName)) {
+            fileLength = StreamUtils.copy(in, os);
         }
         File newFile = new File(fileAbsName);
         //获取文件的md5值
@@ -146,13 +139,16 @@ public class LocalFileService implements FileService {
             md5 = DigestUtils.md5Hex(inputStream);
         }
         //  判断文件是否已经存在
-        FileInfoEntity resources = fileInfoService.selectByMd5(md5);
-        if (resources != null) {
-            newFile.delete();//文件已存在则删除临时文件不做处理
-            return resources;
+        FileInfoEntity fileInfo = fileInfoService.selectByMd5(md5);
+        if (fileInfo != null) {
+            if (new File(getFilePath() + "/" + fileInfo.getLocation()).exists()) {
+                newFile.delete();//文件已存在则删除临时文件不做处理
+            } else {
+                newFile.renameTo(new File(absPath.concat("/").concat(md5)));
+            }
+            return fileInfo;
         } else {
-            newName = md5;
-            newFile.renameTo(new File(absPath.concat("/").concat(newName)));
+            newFile.renameTo(new File(absPath.concat("/").concat(md5)));
         }
         FileInfoEntity infoEntity = fileInfoService.createEntity();
         infoEntity.setCreateTimeNow();
@@ -170,13 +166,8 @@ public class LocalFileService implements FileService {
     @Override
     public void writeFile(String fileId, OutputStream out, long skip) throws IOException {
         try (InputStream inputStream = readFile(fileId)) {
-            BufferedOutputStream outputStream = out instanceof BufferedOutputStream ? ((BufferedOutputStream) out) : new BufferedOutputStream(out);
             if (skip > 0) inputStream.skip(skip);
-            byte b[] = new byte[2048 * 10];
-            while ((inputStream.read(b)) != -1) {
-                outputStream.write(b);
-            }
-            outputStream.flush();
+            StreamUtils.copy(inputStream, out);
         }
     }
 

+ 18 - 3
hsweb-system/hsweb-system-file/hsweb-system-file-service/hsweb-system-file-service-simple/src/main/java/org/hswebframework/web/service/file/simple/SimpleFileInfoService.java

@@ -43,7 +43,20 @@ public class SimpleFileInfoService extends GenericEntityService<FileInfoEntity,
     @Override
     @Caching(evict = {
             @CacheEvict(key = "'md5:'+#entity.md5"),
-            @CacheEvict(key = "'id:'+#entity.id")
+            @CacheEvict(key = "'id:'+#result"),
+            @CacheEvict(key = "'id-or-md5:'+#result"),
+            @CacheEvict(key = "'id-or-md5:'+#result")
+    })
+    public String insert(FileInfoEntity entity) {
+        return super.insert(entity);
+    }
+
+    @Override
+    @Caching(evict = {
+            @CacheEvict(key = "'md5:'+#entity.md5"),
+            @CacheEvict(key = "'id:'+#entity.id"),
+            @CacheEvict(key = "'id-or-md5:'+#entity.id"),
+            @CacheEvict(key = "'id-or-md5:'+#entity.id")
     })
     protected int updateByPk(FileInfoEntity entity) {
         return super.updateByPk(entity);
@@ -52,7 +65,9 @@ public class SimpleFileInfoService extends GenericEntityService<FileInfoEntity,
     @Override
     @Caching(evict = {
             @CacheEvict(key = "'md5:'+#target.selectByPk(#id).md5"),
-            @CacheEvict(key = "'id:'+#id")
+            @CacheEvict(key = "'id:'+#id"),
+            @CacheEvict(key = "'id-or-md5:'+#id"),
+            @CacheEvict(key = "'id-or-md5:'+#id")
     })
     public int deleteByPk(String id) {
         return super.deleteByPk(id);
@@ -81,6 +96,6 @@ public class SimpleFileInfoService extends GenericEntityService<FileInfoEntity,
     @Cacheable(key = "'id-or-md5:'+#idOrMd5", condition = "#idOrMd5!=null")
     public FileInfoEntity selectByIdOrMd5(String idOrMd5) {
         if (null == idOrMd5) return null;
-        return createQuery().where(FileInfoEntity.md5,idOrMd5).or(FileInfoEntity.id,idOrMd5).single();
+        return createQuery().where(FileInfoEntity.md5, idOrMd5).or(FileInfoEntity.id, idOrMd5).single();
     }
 }