文件存储时记录数据库

This commit is contained in:
AlanScipio
2024-02-19 16:01:14 +08:00
parent a327ff26ba
commit eae6443f11
23 changed files with 754 additions and 99 deletions

View File

@@ -16,8 +16,8 @@
</description>
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
@@ -46,7 +46,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- FastDFS -->
<dependency>
<groupId>com.github.tobato</groupId>
@@ -65,12 +65,30 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-api-system</artifactId>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- RuoYi Common Swagger -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-swagger</artifactId>
</dependency>
<!-- RuoYi Common Services -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-services</artifactId>
</dependency>
<!-- RuoYi Common Datasource-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-datasource</artifactId>
</dependency>
</dependencies>

View File

@@ -8,16 +8,14 @@ import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
/**
* 文件服务
*
*
* @author ruoyi
*/
@ConditionalOnProperty(name = "spring.cloud.nacos.config.group", havingValue = "DEFAULT_GROUP", matchIfMissing = true)
@EnableCustomSwagger2
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class RuoYiFileApplication
{
public static void main(String[] args)
{
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class RuoYiFileApplication {
public static void main(String[] args) {
SpringApplication.run(RuoYiFileApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 文件服务模块启动成功 ლ(´ڡ`ლ)゙");
}

View File

@@ -18,6 +18,7 @@ import com.ruoyi.system.api.domain.SysFile;
*/
@RestController
public class SysFileController {
private static final Logger log = LoggerFactory.getLogger(SysFileController.class);
@Autowired

View File

@@ -0,0 +1,23 @@
package com.ruoyi.file.domain;
import com.ruoyi.file.utils.FileUploadResult;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author Alan Scipio
* created on 2024/2/19
*/
@Data
public class FileSaveRecord implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String requestUrl;
private FileUploadResult uploadResult;
}

View File

@@ -4,17 +4,16 @@ import org.springframework.web.multipart.MultipartFile;
/**
* 文件上传接口
*
*
* @author ruoyi
*/
public interface ISysFileService
{
public interface ISysFileService {
/**
* 文件上传接口
*
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
public String uploadFile(MultipartFile file) throws Exception;
String uploadFile(MultipartFile file) throws Exception;
}

View File

@@ -1,20 +1,25 @@
package com.ruoyi.file.service;
import com.ruoyi.common.services.constants.FileStorageType;
import com.ruoyi.common.services.domain.SysFile;
import com.ruoyi.common.services.mapper.SysFileMapper;
import com.ruoyi.file.utils.FileUploadResult;
import com.ruoyi.file.utils.FileUploadUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.file.utils.FileUploadUtils;
/**
* 本地文件存储
*
*
* @author ruoyi
*/
@Primary
@Service
public class LocalSysFileServiceImpl implements ISysFileService
{
public class LocalSysFileServiceImpl implements ISysFileService {
/**
* 资源映射路径 前缀
*/
@@ -26,25 +31,45 @@ public class LocalSysFileServiceImpl implements ISysFileService
*/
@Value("${file.domain}")
public String domain;
/**
* 上传文件存储在本地的根路径
*/
@Value("${file.path}")
private String localFilePath;
@Autowired
private SysFileMapper sysFileMapper;
/**
* 本地文件上传接口
*
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
@Transactional
@Override
public String uploadFile(MultipartFile file) throws Exception
{
String name = FileUploadUtils.upload(localFilePath, file);
String url = domain + localFilePrefix + name;
public String uploadFile(MultipartFile file) throws Exception {
// 保存文件到本地
FileUploadResult uploadResult = FileUploadUtils.upload(localFilePath, file);
String savedPathFileName = uploadResult.getSavedPathFileName();
String url = domain + localFilePrefix + savedPathFileName;
// 保存文件记录
saveFileRecord(url, uploadResult);
// 返回访问地址
return url;
}
private void saveFileRecord(String requestUrl, FileUploadResult uploadResult) {
SysFile record = new SysFile();
record.setFileId(uploadResult.getFileId()); // 文件ID
record.setSavedName(uploadResult.getSavedFileName()); // 保存的文件名
record.setOriginalName(uploadResult.getOriginalFilename()); // 原文件名
record.setFilePath(uploadResult.getSavedPath()); // 本地保存的文件路径
record.setExtension(uploadResult.getExtension()); // 文件扩展名
record.setStorageType(FileStorageType.LOCAL.name()); // 存储类型:本地文件存储
record.setRequestUrl(requestUrl); // 获取文件的URL
record.setFileSize(uploadResult.getFileSize()); // 文件大小(Byte)
sysFileMapper.insertSelective(record);
}
}

View File

@@ -1,23 +1,24 @@
package com.ruoyi.file.service;
import java.io.InputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.nacos.common.utils.IoUtils;
import com.ruoyi.file.config.MinioConfig;
import com.ruoyi.file.utils.FileUploadUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
/**
* TODO 未完成,还需要保存文件记录
* Minio 文件存储
*
* @author ruoyi
*/
@Service
public class MinioSysFileServiceImpl implements ISysFileService
{
public class MinioSysFileServiceImpl implements ISysFileService {
@Autowired
private MinioConfig minioConfig;
@@ -29,12 +30,10 @@ public class MinioSysFileServiceImpl implements ISysFileService
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
@Override
public String uploadFile(MultipartFile file) throws Exception
{
String fileName = FileUploadUtils.extractFilename(file);
public String uploadFile(MultipartFile file) throws Exception {
String fileName = FileUploadUtils.extractFilename(file, null);
InputStream inputStream = file.getInputStream();
PutObjectArgs args = PutObjectArgs.builder()
.bucket(minioConfig.getBucketName())

View File

@@ -0,0 +1,32 @@
package com.ruoyi.file.utils;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author Alan Scipio
* created on 2024/2/19
*/
@Data
public class FileUploadResult implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String fileId;
private String savedFileName;
private String savedPathFileName;
private String originalFilename;
private String extension;
private Long fileSize;
private String savedPath;
}

View File

@@ -1,12 +1,5 @@
package com.ruoyi.file.utils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.exception.file.FileException;
import com.ruoyi.common.core.exception.file.FileNameLengthLimitExceededException;
import com.ruoyi.common.core.exception.file.FileSizeLimitExceededException;
@@ -16,6 +9,12 @@ import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.file.MimeTypeUtils;
import com.ruoyi.common.core.utils.uuid.Seq;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;
/**
* 文件上传工具类
@@ -24,9 +23,9 @@ import com.ruoyi.common.core.utils.uuid.Seq;
*/
public class FileUploadUtils {
/**
* 默认大小 50M
* 默认大小 100M
*/
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
public static final long DEFAULT_MAX_SIZE = 100 * 1024 * 1024;
/**
* 默认的文件名最大长度 100
@@ -38,9 +37,9 @@ public class FileUploadUtils {
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @return 文件名称
* @return 文件上传结果
*/
public static String upload(String baseDir, MultipartFile file) throws IOException {
public static FileUploadResult upload(String baseDir, MultipartFile file) throws IOException {
try {
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
} catch (FileException fe) {
@@ -62,29 +61,39 @@ public class FileUploadUtils {
* @throws IOException 比如读写文件出错时
* @throws InvalidExtensionException 文件校验异常
*/
public static String upload(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException {
int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
public static FileUploadResult upload(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException {
int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();
if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
assertAllowed(file, allowedExtension);
FileUploadResult result = new FileUploadResult();
String fileName = extractFilename(file);
assertAllowed(file, allowedExtension, result);
String fileName = extractFilename(file, result);
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
file.transferTo(Paths.get(absPath));
return getPathFileName(fileName);
String savedPathFileName = getPathFileName(fileName);
result.setSavedPathFileName(savedPathFileName);
result.setSavedPath(absPath);
return result;
}
/**
* 编码文件名
* 编码文件名,最终结果举例: .../2024/02/19/20240219154651A001.jpg
*/
public static String extractFilename(MultipartFile file) {
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), FileTypeUtils.getExtension(file));
public static String extractFilename(MultipartFile file, FileUploadResult result) {
String fileId = Seq.getId(Seq.uploadSeqType);
String savedFileName = StringUtils.format("{}.{}", fileId, FileTypeUtils.getExtension(file));
if (result != null) {
result.setFileId(fileId);
result.setSavedFileName(savedFileName);
}
return StringUtils.format("{}/{}", DateUtils.datePath(), savedFileName);
}
@SuppressWarnings("ResultOfMethodCallIgnored")
@@ -100,26 +109,29 @@ public class FileUploadUtils {
}
private static String getPathFileName(String fileName) {
String pathFileName = "/" + fileName;
return pathFileName;
return "/" + fileName;
}
/**
* 文件大小校验
*
* @param file 上传的文件
* @param file 上传的文件
* @param result 文件上传结果
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws InvalidExtensionException 文件校验异常
*/
public static void assertAllowed(MultipartFile file, String[] allowedExtension)
public static void assertAllowed(MultipartFile file, String[] allowedExtension, FileUploadResult result)
throws FileSizeLimitExceededException, InvalidExtensionException {
long size = file.getSize();
if (size > DEFAULT_MAX_SIZE) {
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
}
result.setFileSize(size);
String fileName = file.getOriginalFilename();
String extension = FileTypeUtils.getExtension(file);
result.setExtension(extension);
result.setOriginalFilename(fileName);
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,