Raod %!s(int64=3) %!d(string=hai) anos
pai
achega
dd0a419daf

+ 12 - 0
report-core/pom.xml

@@ -61,6 +61,12 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-mock</artifactId>
+            <version>2.0.8</version>
+        </dependency>
+
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-context</artifactId>
@@ -85,6 +91,12 @@
             </exclusions>
         </dependency>
 
+        <dependency>
+            <groupId>com.anji-plus</groupId>
+            <artifactId>spring-boot-starter-gaea-oss</artifactId>
+            <version>2.0.5.RELEASE</version>
+        </dependency>
+
         <dependency>
             <groupId>com.baomidou</groupId>
             <artifactId>mybatis-plus-boot-starter</artifactId>

+ 2 - 1
report-core/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java

@@ -118,7 +118,8 @@ public interface ResponseCode {
     String FILE_SUFFIX_UNSUPPORTED = "2002";
     String FILE_UPLOAD_ERROR = "2003";
     String FILE_ONT_EXSIT = "2004";
-    String LIST_IS_EMPTY = "2005";
+    String FILE_OPERATION_FAILED = "file.operation.failed";
+
     String PUSHCODE_NEED_UNIQUE = "3001";
     String RECEIVER_IS_EMPTY = "3002";
     String DATA_SOURCE_CONNECTION_FAILED = "4001";

+ 6 - 10
report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/ReportDashboardServiceImpl.java

@@ -80,13 +80,13 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
     @Autowired
     private ReportService reportService;
 
-    @Value("${customer.file.downloadPath:''}")
+    @Value("${spring.gaea.subscribes.oss.downloadPath:}")
     private String fileDownloadPath;
 
-    @Value("${customer.file.dist-path:''}")
+    @Value("${customer.file.tmp-path:.}")
     private String dictPath;
 
-    private final static String ZIP_PATH = "/zip/";
+    private final static String ZIP_PATH = "/tmp_zip/";
     private final static String JSON_PATH = "dashboard.json";
 
     private Map<String, ChartStrategy> queryServiceImplMap = new HashMap<>();
@@ -395,13 +395,9 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi
             queryWrapper.eq(GaeaFile::getFileId, fileName);
             GaeaFile gaeaFile = gaeaFileService.selectOne(queryWrapper);
             if (null != gaeaFile) {
-                String fileType = gaeaFile.getFileType();
-                path = path + "/image/" + fileName + "." + fileType;
-                //path = /app/disk/upload/zip/UUID/image
-
-                //原始文件的路径
-                String filePath = gaeaFile.getFilePath();
-                FileUtil.copyFileUsingFileChannels(filePath, path);
+                byte[] file = gaeaFileService.getFile(gaeaFile.getFileId());
+                path = path + "/image/";
+                FileUtil.byte2File(file, path, gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType()));
             }
         }
 

+ 7 - 0
report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java

@@ -54,4 +54,11 @@ public interface GaeaFileService extends GaeaBaseService<GaeaFileParam, GaeaFile
      * @return
      */
     ResponseEntity<byte[]> download(HttpServletRequest request, HttpServletResponse response, String fileId);
+
+    /**
+     * 获取文件
+     * @param fileId
+     * @return
+     */
+    byte[] getFile(String fileId);
 }

+ 120 - 115
report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java

@@ -4,59 +4,51 @@ import com.anji.plus.gaea.constant.BaseOperationEnum;
 import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper;
 import com.anji.plus.gaea.exception.BusinessException;
 import com.anji.plus.gaea.exception.BusinessExceptionBuilder;
+import com.anji.plus.gaea.oss.exceptions.GaeaOSSException;
+import com.anji.plus.gaea.oss.exceptions.GaeaOSSTypeLimitedException;
+import com.anji.plus.gaea.oss.ossbuilder.GaeaOSSTemplate;
+import com.anji.plus.gaea.oss.utils.ResponseUtil;
 import com.anjiplus.template.gaea.business.code.ResponseCode;
 import com.anjiplus.template.gaea.business.modules.file.dao.GaeaFileMapper;
 import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile;
 import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService;
-import com.anjiplus.template.gaea.business.modules.file.util.FileUtils;
-import com.anjiplus.template.gaea.business.modules.file.util.StringPatternUtil;
-import com.anjiplus.template.gaea.business.util.FileUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.http.entity.ContentType;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.CacheControl;
-import org.springframework.http.MediaType;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.http.ResponseEntity;
+import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.File;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Arrays;
+import java.io.FileInputStream;
 import java.util.List;
 import java.util.UUID;
-import java.util.stream.Collectors;
 
 /**
- * (GaeaFile)ServiceImpl
- *
- * @author peiyanni
- * @since 2021-02-18 14:48:26
+ * 文件管理服务实现
+ * @author: Raod
+ * @since: 2022-08-31
  */
 @Service
 @Slf4j
+@RefreshScope
 public class GaeaFileServiceImpl implements GaeaFileService {
 
-    @Value("${customer.file.dist-path:''}")
-    private String dictPath;
-
-    @Value("${customer.file.white-list:''}")
-    private String whiteList;
-
-    @Value("${customer.file.excelSuffix:''}")
-    private String excelSuffix;
-
-    @Value("${customer.file.downloadPath:''}")
+    @Value("${spring.gaea.subscribes.oss.downloadPath:''}")
     private String fileDownloadPath;
 
+    @Autowired
+    private GaeaOSSTemplate gaeaOSSTemplate;
+
     @Autowired
     private GaeaFileMapper gaeaFileMapper;
 
@@ -69,65 +61,60 @@ public class GaeaFileServiceImpl implements GaeaFileService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public GaeaFile upload(MultipartFile multipartFile, File file, String customFileName) {
-        try {
-            String fileName = "";
-            if (null != multipartFile) {
-                fileName = multipartFile.getOriginalFilename();
-            }else {
-                fileName = file.getName();
-            }
+        String originalFilename =  multipartFile.getOriginalFilename();
 
-            if (StringUtils.isBlank(fileName)) {
-                throw BusinessExceptionBuilder.build(ResponseCode.FILE_EMPTY_FILENAME);
-            }
+        if (StringUtils.isBlank(originalFilename)) {
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_EMPTY_FILENAME);
+        }
+        // 文件后缀 .png
+        String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
+        // 生成文件唯一性标识
+        String fileId;
+        if (StringUtils.isBlank(customFileName)) {
+            fileId = UUID.randomUUID().toString();
+        } else {
+            fileId = customFileName;
+        }
+        // 生成在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png
+        String fileObjectName = fileId + suffixName;
+        // 生成链接通过fileId http访问路径 http://10.108.3.121:9089/meta/file/download/402b6193e70e40a9bf5b73a78ea1e8ab
+        String urlPath = fileDownloadPath + "/" + fileId;
+
+        // 上传文件
+        try{
+            gaeaOSSTemplate.uploadFileByInputStream(multipartFile, fileObjectName);
+        }catch (GaeaOSSTypeLimitedException e){
+            log.error("上传失败GaeaOSSTypeLimitedException", e);
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_SUFFIX_UNSUPPORTED, e.getMessage());
+        }catch (GaeaOSSException e){
+            log.error("上传失败GaeaOSSException", e);
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_UPLOAD_ERROR, e.getMessage());
+        }
 
-            String suffixName = fileName.substring(fileName.lastIndexOf("."));
-            String fileInstruction = fileName.substring(0, fileName.lastIndexOf("."));
-            //白名单校验(不区分大小写)
-            List<String> list = new ArrayList<>(Arrays.asList(whiteList.split("\\|")));
-            list.addAll(list.stream().map(String::toUpperCase).collect(Collectors.toList()));
-            if (!list.contains(suffixName)) {
-                throw BusinessExceptionBuilder.build(ResponseCode.FILE_SUFFIX_UNSUPPORTED);
-            }
-            // 生成文件唯一性标识
-            String fileId;
-            if (StringUtils.isBlank(customFileName)) {
-                fileId = UUID.randomUUID().toString();
-            } else {
-                fileId = customFileName;
-            }
-            String newFileName = fileId + suffixName;
-            // 本地文件保存路径
-            String filePath = dictPath + newFileName;
-            String urlPath = fileDownloadPath + "/" + fileId;
-
-            GaeaFile gaeaFile = new GaeaFile();
-            gaeaFile.setFilePath(filePath);
-            gaeaFile.setFileId(fileId);
-            gaeaFile.setUrlPath(urlPath);
-            gaeaFile.setFileType(suffixName.replace(".", ""));
-            gaeaFile.setFileInstruction(fileInstruction);
-            gaeaFileMapper.insert(gaeaFile);
-
-            //写文件 将文件保存/app/dictPath/upload/下
-            java.io.File dest = new java.io.File(dictPath + newFileName);
-            java.io.File parentFile = dest.getParentFile();
-            if (!parentFile.exists()) {
-                parentFile.mkdirs();
-            }
-            if (null != multipartFile) {
-                multipartFile.transferTo(dest);
-            }else {
-                FileUtil.copyFileUsingFileChannels(file, dest);
-            }
-            // 将完整的http访问路径返回
-            return gaeaFile;
-        } catch (BusinessException e){
-            throw BusinessExceptionBuilder.build(e.getCode());
-        }catch (Exception e) {
-            log.error("file upload error", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FILE_UPLOAD_ERROR);
+        // 保存到文件管理中
+        GaeaFile gaeaFile = new GaeaFile();
+        gaeaFile.setFileId(fileId);
+        gaeaFile.setFilePath(fileObjectName);
+        gaeaFile.setUrlPath(urlPath);
+        gaeaFile.setFileType(suffixName.replace(".", ""));
+        gaeaFile.setFileInstruction(originalFilename);
+        insert(gaeaFile);
+
+        return gaeaFile;
+    }
+
+    private MultipartFile getMultipartFile(File file){
+        FileInputStream fileInputStream;
+        MultipartFile multipartFile;
+        try {
+            fileInputStream = new FileInputStream(file);
+            multipartFile = new MockMultipartFile(file.getName(),file.getName(),
+                    ContentType.APPLICATION_OCTET_STREAM.toString(),fileInputStream);
+        } catch (Exception e) {
+            log.error("file转MultipartFile失败", e);
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         }
+        return multipartFile;
     }
 
     /**
@@ -150,52 +137,73 @@ public class GaeaFileServiceImpl implements GaeaFileService {
      */
     @Override
     public GaeaFile upload(File file, String customFileName) {
-        return upload(null, file, customFileName);
+        return upload(getMultipartFile(file));
     }
 
     @Override
     public ResponseEntity<byte[]> download(HttpServletRequest request, HttpServletResponse response, String fileId) {
         try {
-            String userAgent = request.getHeader("User-Agent");
-            boolean isIeBrowser = userAgent.indexOf("MSIE") > 0;
-            //根据fileId,从gaea_file中读出filePath
+            // fileId必填
+            if(StringUtils.isBlank(fileId)){
+                throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT);
+            }
+            // 根据fileId,从gaea_file中读出filePath
             LambdaQueryWrapper<GaeaFile> queryWrapper = Wrappers.lambdaQuery();
             queryWrapper.eq(GaeaFile::getFileId, fileId);
             GaeaFile gaeaFile = gaeaFileMapper.selectOne(queryWrapper);
             if (null == gaeaFile) {
                 throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT);
             }
-            //解析文件路径、文件名和后缀
-            String filePath = gaeaFile.getFilePath();
-            if (StringUtils.isBlank(filePath)) {
+
+            String userAgent = request.getHeader("User-Agent");
+            boolean isIEBrowser = userAgent.indexOf("MSIE") > 0;
+            // 在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png
+            String fileObjectName = gaeaFile.getFilePath();
+            String originalFilename = gaeaFile.getFileInstruction();
+            if (StringUtils.isBlank(fileObjectName) || StringUtils.isBlank(originalFilename)) {
                 throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT);
             }
-            String filename = filePath.substring(filePath.lastIndexOf(File.separator));
-            String fileSuffix = filename.substring(filename.lastIndexOf("."));
-
-            //根据文件后缀来判断,是显示图片\视频\音频,还是下载文件
-            File file = new File(filePath);
-            ResponseEntity.BodyBuilder builder = ResponseEntity.ok();
-            builder.contentLength(file.length());
-            if (StringPatternUtil.stringMatchIgnoreCase(fileSuffix, "(.png|.jpg|.jpeg|.bmp|.gif|.icon)")) {
-                builder.cacheControl(CacheControl.noCache()).contentType(MediaType.IMAGE_PNG);
-            } else if (StringPatternUtil.stringMatchIgnoreCase(fileSuffix, "(.flv|.swf|.mkv|.avi|.rm|.rmvb|.mpeg|.mpg|.ogg|.ogv|.mov|.wmv|.mp4|.webm|.wav|.mid|.mp3|.aac)")) {
-                builder.header("Content-Type", "video/mp4; charset=UTF-8");
-            } else {
-                //application/octet-stream 二进制数据流(最常见的文件下载)
-                builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
-                filename = URLEncoder.encode(filename, "UTF-8");
-                if (isIeBrowser) {
-                    builder.header("Content-Disposition", "attachment; filename=" + filename);
-                } else {
-                    builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + filename);
-                }
-            }
-            return builder.body(FileUtils.readFileToByteArray(file));
+
+            // 调用文件存储工厂,读取文件,返回字节数组
+            byte[] fileBytes = gaeaOSSTemplate.downloadFile(fileObjectName);
+
+            // 根据文件后缀来判断,是显示图片\视频\音频,还是下载文件
+            return ResponseUtil.writeBody(originalFilename, fileBytes, isIEBrowser);
         } catch (Exception e) {
-            log.error("file download error: {}", e);
-            return null;
+            log.error("file download error", e);
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
+        }
+    }
+
+    /**
+     * 获取文件
+     *
+     * @param fileId
+     * @return
+     */
+    @Override
+    public byte[] getFile(String fileId) {
+        // fileId必填
+        if(StringUtils.isBlank(fileId)){
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT);
+        }
+        // 根据fileId,从gaea_file中读出filePath
+        LambdaQueryWrapper<GaeaFile> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(GaeaFile::getFileId, fileId);
+        GaeaFile gaeaFile = gaeaFileMapper.selectOne(queryWrapper);
+        if (null == gaeaFile) {
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT);
         }
+
+        // 在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png
+        String fileObjectName = gaeaFile.getFilePath();
+        String originalFilename = gaeaFile.getFileInstruction();
+        if (StringUtils.isBlank(fileObjectName) || StringUtils.isBlank(originalFilename)) {
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT);
+        }
+
+        // 调用文件存储工厂,读取文件,返回字节数组
+        return gaeaOSSTemplate.downloadFile(fileObjectName);
     }
 
     /**
@@ -212,10 +220,7 @@ public class GaeaFileServiceImpl implements GaeaFileService {
             // 删除本地文件
             entities.forEach(gaeaFile -> {
                 String filePath = gaeaFile.getFilePath();
-                File file = new File(filePath);
-                if (file.exists()) {
-                    file.delete();
-                }
+                gaeaOSSTemplate.deleteFile(filePath);
             });
         }
 

+ 2 - 2
report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/impl/ReportExcelServiceImpl.java

@@ -58,10 +58,10 @@ public class ReportExcelServiceImpl implements ReportExcelService {
     @Autowired
     private ReportMapper reportMapper;
 
-    @Value("${customer.file.dist-path:''}")
+    @Value("${customer.file.tmp-path:.}")
     private String dictPath;
 
-    @Value("${customer.file.downloadPath:''}")
+    @Value("${spring.gaea.subscribes.oss.downloadPath:''}")
     private String fileDownloadPath;
 
     @Autowired

+ 68 - 24
report-core/src/main/java/com/anjiplus/template/gaea/business/util/FileUtil.java

@@ -1,7 +1,7 @@
 package com.anjiplus.template.gaea.business.util;
 
-import com.anji.plus.gaea.code.ResponseCode;
 import com.anji.plus.gaea.exception.BusinessExceptionBuilder;
+import com.anjiplus.template.gaea.business.code.ResponseCode;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -42,7 +42,7 @@ public class FileUtil {
             log.info("链接下载图片:{},临时路径:{}", urlPath, path);
         } catch (IOException e) {
             log.error("根据链接下载失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         }
     }
 
@@ -66,14 +66,14 @@ public class FileUtil {
             outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
         } catch (IOException e) {
             log.error("复制文件失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         } finally {
             try {
                 inputChannel.close();
                 outputChannel.close();
             } catch (IOException e) {
                 log.error("", e);
-                throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+                throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
             }
         }
     }
@@ -106,7 +106,7 @@ public class FileUtil {
             outputStream.close();
         } catch (Exception e) {
             log.error("写入文件失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         }
     }
 
@@ -132,20 +132,20 @@ public class FileUtil {
             return sbf.toString();
         } catch (IOException e) {
             log.error("读文件失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         } finally {
             if (null != isr) {
                 try {
                     isr.close();
                 } catch (IOException e) {
-                    throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                 }
             }
             if (reader != null) {
                 try {
                     reader.close();
                 } catch (IOException e1) {
-                    throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e1.getMessage());
+                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e1.getMessage());
                 }
             }
         }
@@ -185,14 +185,14 @@ public class FileUtil {
             compress(srcFile, zipOut, baseDir);
         } catch (IOException e) {
             log.error("压缩文件夹失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         } finally {
             if (null != zipOut) {
                 try {
                     zipOut.close();
                 } catch (IOException e) {
                     log.error("", e);
-                    throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                 }
                 out = null;
             }
@@ -201,7 +201,7 @@ public class FileUtil {
                     out.close();
                 } catch (IOException e) {
                     log.error("", e);
-                    throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                 }
             }
         }
@@ -246,14 +246,14 @@ public class FileUtil {
 
         } catch (IOException e) {
             log.error("压缩文件夹失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         } finally {
             if (null != bis) {
                 try {
                     bis.close();
                 } catch (IOException e) {
                     log.error("", e);
-                    throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                 }
             }
         }
@@ -264,23 +264,26 @@ public class FileUtil {
             decompress(new ZipFile(zipFile), dstPath);
         } catch (IOException e) {
             log.error("", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         }
     }
 
     public static void decompress(MultipartFile zipFile, String dstPath) {
         try {
-            File file = new File(dstPath + File.separator + zipFile.getOriginalFilename());
-            if (!file.getParentFile().exists()) {
-                file.getParentFile().mkdirs();
+            File dir = new File(dstPath);
+            if (!dir.exists()){
+                dir.mkdirs();
             }
+            String path = dir.getPath();
+            String absolutePath = dir.getAbsolutePath();
+            File file = new File(dir.getAbsolutePath() + File.separator + zipFile.getOriginalFilename());
             zipFile.transferTo(file);
             decompress(new ZipFile(file), dstPath);
             //解压完删除
             file.delete();
         } catch (IOException e) {
             log.error("", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         }
     }
 
@@ -326,14 +329,14 @@ public class FileUtil {
                     }
                 } catch (IOException e) {
                     log.error("解压失败", e);
-                    throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                 } finally {
                     if (null != in) {
                         try {
                             in.close();
                         } catch (IOException e) {
                             log.error("", e);
-                            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+                            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                         }
                     }
 
@@ -342,7 +345,7 @@ public class FileUtil {
                             out.close();
                         } catch (IOException e) {
                             log.error("", e);
-                            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+                            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                         }
                     }
                 }
@@ -350,7 +353,7 @@ public class FileUtil {
             zip.close();
         } catch (IOException e) {
             log.error("解压失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         }
     }
 
@@ -371,7 +374,7 @@ public class FileUtil {
             ins.close();
         } catch (Exception e) {
             log.error("获取流文件失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
         }
     }
 
@@ -399,8 +402,49 @@ public class FileUtil {
             });
         } catch (IOException e) {
             log.error("删除文件失败", e);
-            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
+        }
+    }
+
+    /**
+     * byte 转file
+     */
+    public static File byte2File(byte[] buf, String filePath, String fileName){
+        BufferedOutputStream bos = null;
+        FileOutputStream fos = null;
+        File file = null;
+        try{
+            File dir = new File(filePath);
+            if (!dir.exists()){
+                dir.mkdirs();
+            }
+            file = new File(filePath + File.separator + fileName);
+            fos = new FileOutputStream(file);
+            bos = new BufferedOutputStream(fos);
+            bos.write(buf);
+        }catch (Exception e){
+            log.error("", e);
+            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
+        }
+        finally{
+            if (bos != null){
+                try{
+                    bos.close();
+                }catch (IOException e){
+                    log.error("", e);
+                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
+                }
+            }
+            if (fos != null){
+                try{
+                    fos.close();
+                }catch (IOException e){
+                    log.error("", e);
+                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
+                }
+            }
         }
+        return file;
     }
 
 

+ 11 - 4
report-core/src/main/resources/bootstrap-dev.yml

@@ -4,8 +4,15 @@ spring:
     url: jdbc:mysql://10.108.26.197:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false
     username: root
     password: appuser@anji
+  gaea:
+    subscribes:
+      oss: #文件存储
+        enabled: true
+        ##允许上传的文件后缀
+        file-type-while-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi|.jpeg
+        # 用于文件上传成功后,生成文件的下载公网完整URL
+        downloadPath: http://127.0.0.1:9095/file/download
+        nfs:
+          path: D:\\aaa\\
+
 
-customer:
-  file:
-    dist-path: D:\Workspace\AJ-Report\report-core\upload
-    downloadPath: http://127.0.0.1:9095/file/download

+ 0 - 4
report-core/src/main/resources/bootstrap-prod.yml

@@ -4,7 +4,3 @@ spring:
     url: jdbc:mysql://10.108.26.197:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false
     username: root
     password: appuser@anji
-
-customer:
-  file:
-    dist-path: /app/disk/upload/

+ 24 - 10
report-core/src/main/resources/bootstrap.yml

@@ -46,6 +46,30 @@ spring:
     placeholder-replacement: false
     init-sqls:
       - CREATE DATABASE IF NOT EXISTS `aj_report` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
+  gaea:
+    subscribes:
+      oss: #文件存储
+        enabled: true
+        ##允许上传的文件后缀
+        file-type-while-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi|.jpeg|.aaa
+        # 用于文件上传成功后,生成文件的下载公网完整URL
+        downloadPath: http://10.108.26.197:9095/file/download
+        nfs:
+          path: /app/disk/upload/
+        #若要使用minio文件存储,请启用以下配置
+        #minio:
+        #  url: http://127.0.0.1
+        #  port: 9000
+        #  access-key: minioreport
+        #  secret-key: minioreport
+        #  bucket-name: aj-report
+        #若要使用amazonS3文件存储,请启用以下配置
+        #amazonS3:
+        #  url: http://127.0.0.1
+        #  access-key: access-key
+        #  secret-key: secret-key
+        #  bucket-name: AJ-Report
+        #若minio和amazonS3都没有,使用服务器高可用的nfs共享盘
 
 mybatis-plus:
   configuration:
@@ -64,16 +88,6 @@ logging:
 
 # 本应用自定义参数
 customer:
-  # 开发测试用本地文件,如果是生产,请考虑使用对象存储
-  file:
-    #上传对应本地全路径,目录必须是真实存在的,注意 Win是 \ 且有盘符,linux是 / 无盘符
-    dist-path: /app/disk/upload/
-    #dist-path: D:\Download
-    white-list: .png|.jpg|.jpeg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi
-    excelSuffix: .xlsx|.xls|.csv
-    #上传对应下载的下载链接路径 http://serverip:9095/file/download
-    downloadPath: http://10.108.26.197:9095/file/download
-
   # 跳过token验证和权限验证的url清单
   skip-authenticate-urls: /gaeaDict/all, /login, /static, /file/download/, /index.html, /favicon.ico, /reportShare/detailByCode
   user:

+ 2 - 1
report-core/src/main/resources/i18n/messages_en_US.properties

@@ -9,8 +9,9 @@ user.old.password.error=user old password error
 1013=The code does not allow duplication
 2001=File names are not allowed to be empty
 2002=Unsupported suffix type
-2003=File upload failed
+2003=File upload failed:{0}
 2004=File does not exist
+file.operation.failed=File operation failed\uFF1A{0}
 
 field.not.null={} can not be null
 field.not.empty={} can not be empty

+ 2 - 1
report-core/src/main/resources/i18n/messages_zh_CN.properties

@@ -8,8 +8,9 @@ user.old.password.error=\u65E7\u5BC6\u7801\u4E0D\u6B63\u786E
 1013=\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D
 2001=\u6587\u4EF6\u540D\u4E0D\u5141\u8BB8\u4E3A\u7A7A
 2002=\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301
-2003=\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25
+2003=\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF1A{0}
 2004=\u6587\u4EF6\u4E0D\u5B58\u5728
+file.operation.failed=\u6587\u4EF6\u64CD\u4F5C\u5931\u8D25\uFF1A{0}
 
 field.not.null={}\u4E0D\u80FD\u4E3Anull
 field.not.empty={}\u4E0D\u80FD\u4E3A\u7A7A\u5B57\u7B26\u4E32