|
@@ -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);
|
|
|
});
|
|
|
}
|
|
|
|