oss文件存储服务
This commit is contained in:
parent
fa932cf25e
commit
7f7cee2453
|
|
@ -0,0 +1,103 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.bonus</groupId>
|
||||
<artifactId>bonus-modules</artifactId>
|
||||
<version>3.6.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>bonus-modules-oss</artifactId>
|
||||
<description>
|
||||
bonus-modules-oss存储服务
|
||||
</description>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Actuator -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- FastDFS -->
|
||||
<dependency>
|
||||
<groupId>com.github.tobato</groupId>
|
||||
<artifactId>fastdfs-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Minio -->
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<version>${minio.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- bonus Api System -->
|
||||
<dependency>
|
||||
<groupId>com.bonus</groupId>
|
||||
<artifactId>bonus-api-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- bonus Common Swagger -->
|
||||
<dependency>
|
||||
<groupId>com.bonus</groupId>
|
||||
<artifactId>bonus-common-swagger</artifactId>
|
||||
</dependency>
|
||||
<!--阿里云oss 存储-->
|
||||
<dependency>
|
||||
<groupId>com.aliyun.oss</groupId>
|
||||
<artifactId>aliyun-sdk-oss</artifactId>
|
||||
<version>3.10.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mchange</groupId>
|
||||
<artifactId>mchange-commons-java</artifactId>
|
||||
<version>0.2.15</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.bonus.oss;
|
||||
|
||||
import com.bonus.common.swagger.annotation.EnableCustomSwagger2;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
@EnableCustomSwagger2
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
|
||||
public class BonusOssApplication {
|
||||
public static void main(String[] args)
|
||||
{
|
||||
SpringApplication.run(BonusOssApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ oss存储服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
" .-------. ____ __ \n" +
|
||||
" | _ _ \\ \\ \\ / / \n" +
|
||||
" | ( ' ) | \\ _. / ' \n" +
|
||||
" |(_ o _) / _( )_ .' \n" +
|
||||
" | (_,_).' __ ___(_ o _)' \n" +
|
||||
" | |\\ \\ | || |(_,_)' \n" +
|
||||
" | | \\ `' /| `-' / \n" +
|
||||
" | | \\ / \\ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.bonus.oss.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "oss")
|
||||
public class OSSConfig {
|
||||
private String accessKeyId;
|
||||
private String accessKeySecret;
|
||||
private String bucket;
|
||||
private String endpoint;
|
||||
// Getters and Setters
|
||||
|
||||
public String getAccessKeyId() {
|
||||
return accessKeyId;
|
||||
}
|
||||
|
||||
public void setAccessKeyId(String accessKeyId) {
|
||||
this.accessKeyId = accessKeyId;
|
||||
}
|
||||
|
||||
public String getAccessKeySecret() {
|
||||
return accessKeySecret;
|
||||
}
|
||||
|
||||
public void setAccessKeySecret(String accessKeySecret) {
|
||||
this.accessKeySecret = accessKeySecret;
|
||||
}
|
||||
|
||||
public String getBucket() {
|
||||
return bucket;
|
||||
}
|
||||
|
||||
public void setBucket(String bucket) {
|
||||
this.bucket = bucket;
|
||||
}
|
||||
|
||||
public String getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public void setEndpoint(String endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
package com.bonus.oss.controller;
|
||||
|
||||
import com.aliyun.oss.model.OSSObject;
|
||||
import com.bonus.common.core.domain.R;
|
||||
import com.bonus.oss.domain.OssInfo;
|
||||
import com.bonus.oss.service.OssService;
|
||||
import com.bonus.oss.utils.FileUtils;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/oss")
|
||||
public class OssController {
|
||||
@Resource
|
||||
private OssService ossService;
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param file 文件流
|
||||
* @return 文件信息
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public R<OssInfo> upload(@RequestParam("file") MultipartFile file) {
|
||||
return ossService.upload(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多文件上传
|
||||
*
|
||||
* @param files 文件流数组
|
||||
* @return 上传结果
|
||||
*/
|
||||
@PostMapping("/uploadMultiple")
|
||||
public R<List<OssInfo>> uploadMultiple(@RequestParam("files") MultipartFile[] files) {
|
||||
return ossService.uploadMultiple(files);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param ossFilePath oss文件存储地址
|
||||
*/
|
||||
@GetMapping("/download")
|
||||
public void download(HttpServletRequest request, HttpServletResponse response, @RequestParam String ossFilePath) {
|
||||
try (OSSObject ossObject = ossService.download(ossFilePath)) {
|
||||
if (ossObject == null) {
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return;
|
||||
}
|
||||
InputStream inputStream = ossObject.getObjectContent();
|
||||
String safeFileName = FileUtils.getFileNameFromPath(ossFilePath);
|
||||
String encodedFileName = URLEncoder.encode(safeFileName, StandardCharsets.UTF_8.toString());
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"");
|
||||
try (OutputStream outputStream = response.getOutputStream()) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
outputStream.flush();
|
||||
} catch (IOException e) {
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
response.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
} catch (Exception e) {
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*
|
||||
* @param ossFilePath 文件路径
|
||||
* @return 删除结果
|
||||
*/
|
||||
@PostMapping("/delete")
|
||||
public R<T> delete(@RequestParam String ossFilePath) {
|
||||
return ossService.delete(ossFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多文件删除
|
||||
*
|
||||
* @param ossFilePaths 文件路径列表
|
||||
* @return 删除结果
|
||||
*/
|
||||
@PostMapping("/deleteMultiple")
|
||||
public R<T> deleteMultiple(@RequestParam List<String> ossFilePaths) {
|
||||
return ossService.deleteMultiple(ossFilePaths);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件复制
|
||||
*
|
||||
* @param source 原oss文件存储地址
|
||||
* @param path 目标oss文件存储地址
|
||||
* @return 复制结果
|
||||
*/
|
||||
@PostMapping("/copy")
|
||||
public R<T> copy(@RequestParam String source, @RequestParam String path) {
|
||||
return ossService.copy(source, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多文件复制
|
||||
*
|
||||
* @param sources 原oss文件存储地址列表
|
||||
* @param paths 目标oss文件存储地址列表
|
||||
* @return 复制结果
|
||||
*/
|
||||
@PostMapping("/copyMultiple")
|
||||
public R<T> copyMultiple(@RequestParam List<String> sources, @RequestParam List<String> paths) {
|
||||
return ossService.copyMultiple(sources, paths);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.bonus.oss.domain;
|
||||
|
||||
|
||||
/**
|
||||
* @author 陈敏
|
||||
* @version Info.java, v 1.1 2021/11/15 10:16 chenmin Exp $
|
||||
* Created on 2021/11/15
|
||||
*/
|
||||
|
||||
public class OssInfo {
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* oss里的路径存储路径
|
||||
*/
|
||||
private String path;
|
||||
/**
|
||||
* 对象大小
|
||||
*/
|
||||
private String length;
|
||||
/**
|
||||
* 文件类型
|
||||
*/
|
||||
private String fileType;
|
||||
/**
|
||||
* Bucket名称
|
||||
**/
|
||||
private String bucketName;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(String length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
|
||||
public String getFileType() {
|
||||
return fileType;
|
||||
}
|
||||
|
||||
public void setFileType(String fileType) {
|
||||
this.fileType = fileType;
|
||||
}
|
||||
|
||||
public String getBucketName() {
|
||||
return bucketName;
|
||||
}
|
||||
|
||||
public void setBucketName(String bucketName) {
|
||||
this.bucketName = bucketName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.bonus.oss.service;
|
||||
|
||||
import com.aliyun.oss.model.OSSObject;
|
||||
import com.bonus.common.core.domain.R;
|
||||
import com.bonus.oss.domain.OssInfo;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface OssService {
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param param 文件流
|
||||
* @return 文件信息
|
||||
*/
|
||||
R<OssInfo> upload(MultipartFile param);
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param ossFilePath oss文件存储地址
|
||||
* @return OSSObject对象
|
||||
*/
|
||||
OSSObject download(String ossFilePath);
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*
|
||||
* @param ossFilePath oss文件存储地址
|
||||
* @return 操作结果
|
||||
*/
|
||||
R<T> delete(String ossFilePath);
|
||||
|
||||
/**
|
||||
* 文件复制
|
||||
*
|
||||
* @param source 原oss文件存储地址
|
||||
* @param path 目标oss文件存储地址
|
||||
* @return 操作结果
|
||||
*/
|
||||
R<T> copy(String source, String path);
|
||||
|
||||
/**
|
||||
* 多文件上传
|
||||
*
|
||||
* @param files 文件流数组
|
||||
* @return 上传结果
|
||||
*/
|
||||
R<List<OssInfo>> uploadMultiple(MultipartFile[] files);
|
||||
|
||||
|
||||
/**
|
||||
* 多文件删除
|
||||
*
|
||||
* @param ossFilePaths oss文件存储地址列表
|
||||
* @return 删除结果
|
||||
*/
|
||||
R<T> deleteMultiple(List<String> ossFilePaths);
|
||||
|
||||
/**
|
||||
* 多文件复制
|
||||
*
|
||||
* @param sources 源oss文件存储地址列表
|
||||
* @param paths 目标oss文件存储地址列表
|
||||
* @return 复制结果
|
||||
*/
|
||||
R<T> copyMultiple(List<String> sources, List<String> paths);
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package com.bonus.oss.service.impl;
|
||||
|
||||
import com.aliyun.oss.model.OSSObject;
|
||||
import com.bonus.common.core.domain.R;
|
||||
import com.bonus.oss.domain.OssInfo;
|
||||
import com.bonus.oss.service.OssService;
|
||||
import com.bonus.oss.utils.FileUtils;
|
||||
import com.bonus.oss.utils.OssUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class OssServiceImpl implements OssService {
|
||||
|
||||
@Resource
|
||||
private OssUtils ossUtils;
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param file 文件流
|
||||
* @return 文件信息
|
||||
*/
|
||||
@Override
|
||||
public R<OssInfo> upload(MultipartFile file) {
|
||||
try {
|
||||
if (!FileUtils.isValidFile(file)) {
|
||||
return R.fail("File is empty or File size exceeds 5GB!");
|
||||
}
|
||||
return ossUtils.upload(file);
|
||||
} catch (Exception e) {
|
||||
return R.fail("File upload failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*
|
||||
* @param ossFilePath oss文件存储地址
|
||||
*/
|
||||
@Override
|
||||
public OSSObject download(String ossFilePath) {
|
||||
return ossUtils.download(ossFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*
|
||||
* @param ossFilePath oss文件存储地址
|
||||
*/
|
||||
@Override
|
||||
public R<T> delete(String ossFilePath) {
|
||||
try {
|
||||
if (ObjectUtils.isNotEmpty(ossFilePath)) {
|
||||
return ossUtils.delete(ossFilePath);
|
||||
} else {
|
||||
return R.fail("ossFilePath is null.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return R.fail("File delete failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件复制
|
||||
*
|
||||
* @param source 原oss文件存储地址target
|
||||
* @param path 目标oss文件存储地址
|
||||
*/
|
||||
@Override
|
||||
public R<T> copy(String source, String path) {
|
||||
return ossUtils.copy(source, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多文件上传
|
||||
*
|
||||
* @param files 文件流数组
|
||||
* @return 上传结果
|
||||
*/
|
||||
@Override
|
||||
public R<List<OssInfo>> uploadMultiple(MultipartFile[] files) {
|
||||
List<OssInfo> uploadedFilesInfo = new ArrayList<>();
|
||||
for (MultipartFile file : files) {
|
||||
R<OssInfo> result = upload(file);
|
||||
if (R.isError(result)) {
|
||||
return R.fail("部分文件上传失败");
|
||||
}
|
||||
uploadedFilesInfo.add(result.getData());
|
||||
}
|
||||
return R.ok(uploadedFilesInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多文件删除
|
||||
*
|
||||
* @param ossFilePaths oss文件存储地址列表
|
||||
* @return 删除结果
|
||||
*/
|
||||
@Override
|
||||
public R<T> deleteMultiple(List<String> ossFilePaths) {
|
||||
for (String path : ossFilePaths) {
|
||||
R<T> result = delete(path);
|
||||
if (R.isError(result)) {
|
||||
return R.fail("部分文件删除失败");
|
||||
}
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 多文件复制
|
||||
*
|
||||
* @param sources 源oss文件存储地址列表
|
||||
* @param paths 目标oss文件存储地址列表
|
||||
* @return 复制结果
|
||||
*/
|
||||
@Override
|
||||
public R<T> copyMultiple(List<String> sources, List<String> paths) {
|
||||
if (sources.size() != paths.size()) {
|
||||
return R.fail("源文件和目标文件数量不匹配");
|
||||
}
|
||||
for (int i = 0; i < sources.size(); i++) {
|
||||
R<T> result = copy(sources.get(i), paths.get(i));
|
||||
if (R.isError(result)) {
|
||||
return R.fail("部分文件复制失败");
|
||||
}
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.bonus.oss.utils;
|
||||
|
||||
import com.bonus.common.core.utils.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class FileUtils {
|
||||
/**
|
||||
* 检查MultipartFile是否有效(不为空且大小不超过5GB)
|
||||
*
|
||||
* @param file MultipartFile对象
|
||||
* @return 文件有效返回true,否则返回false
|
||||
*/
|
||||
public static boolean isValidFile(MultipartFile file) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 文件大小限制为5GB
|
||||
long maxSizeInBytes = 5L * 1024 * 1024 * 1024;
|
||||
return file.getSize() <= maxSizeInBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成统一路径的objectName
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 生成的objectName
|
||||
*/
|
||||
public static String generateObjectName(String fileName) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
|
||||
String datePath = sdf.format(new Date());
|
||||
return "uploads/" + datePath + "/" + fileName;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isValidOssFilePath(String ossFilePath) {
|
||||
// 根据实际情况添加对ossFilePath的校验逻辑,确保其只包含安全的字符
|
||||
return StringUtils.hasText(ossFilePath) && ossFilePath.matches("^[\\w\\d\\-\\_\\.]+$");
|
||||
}
|
||||
|
||||
public static String sanitizeFileName(String fileName) {
|
||||
// 避免文件名注入,移除或替换不安全的字符
|
||||
return fileName.replaceAll("[^a-zA-Z0-9\\.\\-_]", "_");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从文件路径中提取文件名
|
||||
* @param ossFilePath 文件路径
|
||||
* @return 文件名
|
||||
*/
|
||||
public static String getFileNameFromPath(String ossFilePath) {
|
||||
Path path = Paths.get(ossFilePath);
|
||||
return path.getFileName().toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MultipartFile 转 File
|
||||
*
|
||||
* @param multiFile MultipartFile对象
|
||||
* @return 转换后的File对象
|
||||
*/
|
||||
public static File multipartFileToFile(MultipartFile multiFile) {
|
||||
try {
|
||||
String fileName = multiFile.getOriginalFilename();
|
||||
if (fileName == null) {
|
||||
return null;
|
||||
}
|
||||
String prefix = fileName.substring(0, fileName.lastIndexOf("."));
|
||||
String suffix = fileName.substring(fileName.lastIndexOf("."));
|
||||
File file = File.createTempFile(prefix, suffix);
|
||||
multiFile.transferTo(file);
|
||||
return file;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
package com.bonus.oss.utils;
|
||||
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
import com.aliyun.oss.model.OSSObject;
|
||||
import com.aliyun.oss.model.ObjectMetadata;
|
||||
import com.bonus.common.core.domain.R;
|
||||
import com.bonus.common.core.text.Convert;
|
||||
import com.bonus.oss.config.OSSConfig;
|
||||
import com.bonus.oss.domain.OssInfo;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* OSS存储工具类
|
||||
*/
|
||||
@Service
|
||||
public class OssUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OssUtils.class);
|
||||
|
||||
@Resource
|
||||
private OSSConfig ossConfig;
|
||||
|
||||
/**
|
||||
* oss 客户端
|
||||
*/
|
||||
private OSS ossClient;
|
||||
|
||||
/**
|
||||
* 初始化信息
|
||||
* 构建OSS客户端实例
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
ossClient = new OSSClientBuilder().build(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param param MultipartFile对象
|
||||
* @return 包含上传文件信息的R对象
|
||||
*/
|
||||
public R<OssInfo> upload(MultipartFile param) {
|
||||
// 获取上传文件的原始文件名
|
||||
String originalFilename = param.getOriginalFilename();
|
||||
// 将MultipartFile转换为File
|
||||
File file = FileUtils.multipartFileToFile(param);
|
||||
try {
|
||||
// 生成唯一的对象名
|
||||
String objectName = FileUtils.generateObjectName(originalFilename);
|
||||
// 上传文件到OSS
|
||||
ossClient.putObject(ossConfig.getBucket(), objectName, file);
|
||||
// 获取上传文件的信息并返回
|
||||
return R.ok(getInfo(originalFilename, objectName));
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("文件上传失败", e);
|
||||
return R.fail("文件上传失败");
|
||||
} finally {
|
||||
// 删除临时文件
|
||||
if (!file.delete()) {
|
||||
LOGGER.warn("临时文件删除失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
*
|
||||
* @param filename 文件名
|
||||
* @param ossFilePath 文件路径
|
||||
* @return 包含文件信息的OssInfo对象
|
||||
*/
|
||||
public OssInfo getInfo(String filename, String ossFilePath) {
|
||||
try {
|
||||
// 获取文件的元数据
|
||||
ObjectMetadata objectMetadata = ossClient.getObjectMetadata(ossConfig.getBucket(), ossFilePath);
|
||||
OssInfo ossInfo = new OssInfo();
|
||||
// 设置文件信息
|
||||
ossInfo.setLength(Convert.toStr(objectMetadata.getContentLength()));
|
||||
ossInfo.setFileType(objectMetadata.getContentType());
|
||||
ossInfo.setName(filename);
|
||||
ossInfo.setBucketName(ossConfig.getBucket());
|
||||
ossInfo.setPath(ossFilePath);
|
||||
return ossInfo;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("获取文件信息失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
* @param ossFilePath 文件路径
|
||||
* @return OSSObject对象
|
||||
*/
|
||||
public OSSObject download(String ossFilePath) {
|
||||
if (ObjectUtils.isEmpty(ossFilePath)) {
|
||||
return null;
|
||||
}
|
||||
if (!doesObjectExist(ossConfig.getBucket(), ossFilePath)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// 从OSS下载文件
|
||||
return ossClient.getObject(ossConfig.getBucket(), ossFilePath);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("文件下载失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param ossFilePath 文件路径
|
||||
*/
|
||||
public R<T> delete(String ossFilePath) {
|
||||
try {
|
||||
if (!doesObjectExist(ossConfig.getBucket(), ossFilePath)) {
|
||||
return R.fail("文件不存在");
|
||||
}
|
||||
// 从OSS删除文件
|
||||
ossClient.deleteObject(ossConfig.getBucket(), ossFilePath);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("文件删除失败", e);
|
||||
return R.fail("文件删除失败");
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 复制文件
|
||||
*
|
||||
* @param source 源文件路径
|
||||
* @param path 目标文件路径
|
||||
*/
|
||||
public R<T> copy(String source, String path) {
|
||||
if (!doesObjectExist(ossConfig.getBucket(), source)) {
|
||||
return R.fail("文件不存在");
|
||||
}
|
||||
try {
|
||||
// 复制文件
|
||||
ossClient.copyObject(ossConfig.getBucket(), source, ossConfig.getBucket(), path);
|
||||
return R.ok();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("文件复制失败", e);
|
||||
return R.fail("文件复制失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断文件是否存在
|
||||
*
|
||||
* @param bucketName Bucket名称
|
||||
* @param objectName 不包含Bucket名称在内的Object完整路径
|
||||
* @return 如果文件存在则返回true,否则返回false
|
||||
*/
|
||||
private boolean doesObjectExist(String bucketName, String objectName) {
|
||||
try {
|
||||
// 判断文件是否存在
|
||||
return ossClient.doesObjectExist(bucketName, objectName);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("判断文件是否存在失败", e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Spring Boot Version: ${spring-boot.version}
|
||||
Spring Application Name: ${spring.application.name}
|
||||
_
|
||||
| |
|
||||
| |__ ___ _ __ _ _ ___ ______ ___ ___ ___
|
||||
| '_ \ / _ \ | '_ \ | | | | / __| |______| / _ \ / __| / __|
|
||||
| |_) | | (_) | | | | | | |_| | \__ \ | (_) | \__ \ \__ \
|
||||
|_.__/ \___/ |_| |_| \__,_| |___/ \___/ |___/ |___/
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9204
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
application:
|
||||
# 应用名称
|
||||
name: bonus-oss
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
cloud:
|
||||
nacos:
|
||||
username: nacos
|
||||
password: nacos
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 192.168.0.14:8848
|
||||
namespace: f1fcd3ea-9460-4597-8acd-0f334527017c
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 192.168.0.14:8848
|
||||
namespace: f1fcd3ea-9460-4597-8acd-0f334527017c
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<!-- 日志存放路径 -->
|
||||
<property name="log.path" value="logs/bonus-file" />
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.bonus" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
</root>
|
||||
</configuration>
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
<module>bonus-gen</module>
|
||||
<module>bonus-job</module>
|
||||
<module>bonus-file</module>
|
||||
<module>bonus-oss</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>bonus-modules</artifactId>
|
||||
|
|
|
|||
Loading…
Reference in New Issue