文件模块开发
This commit is contained in:
34
src/main/java/com/dc/dc_project/config/MinioConfig.java
Normal file
34
src/main/java/com/dc/dc_project/config/MinioConfig.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package com.dc.dc_project.config;
|
||||
|
||||
|
||||
import io.minio.MinioClient;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@Data
|
||||
public class MinioConfig {
|
||||
|
||||
@Value("${minio.endpoint}")
|
||||
public static String MINIO_ENDPOINT;
|
||||
|
||||
@Value("${minio.accessKey}")
|
||||
public static String MINIO_ACCESS_KEY;
|
||||
|
||||
@Value("${minio.secretKey}")
|
||||
public static String MINIO_SECRET_KEY;
|
||||
|
||||
@Value("${minio.bucketName}")
|
||||
public static String MINIO_BUCKET_NAME;
|
||||
|
||||
|
||||
@Bean
|
||||
public MinioClient defaultClient(){
|
||||
return MinioClient.builder()
|
||||
.endpoint(MINIO_ENDPOINT)
|
||||
.credentials(MINIO_ACCESS_KEY, MINIO_SECRET_KEY)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,8 @@ package com.dc.dc_project.controller;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.dc.dc_project.common.ResponseResult;
|
||||
import com.dc.dc_project.model.dto.*;
|
||||
import com.dc.dc_project.model.pojo.PersonnelPosition;
|
||||
import com.dc.dc_project.model.pojo.Position;
|
||||
import com.dc.dc_project.service.PositionService;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.dc.dc_project.controller.sys;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.dc.dc_project.common.ResponseResult;
|
||||
import com.dc.dc_project.model.dto.FileUploadDto;
|
||||
import com.dc.dc_project.service.FileService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class FileController {
|
||||
|
||||
private final FileService fileService;
|
||||
|
||||
@PostMapping("/Upload")
|
||||
public ResponseResult Upload(@ModelAttribute FileUploadDto fileUploadDto) {
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
return fileService.upload(fileUploadDto, userId);
|
||||
}
|
||||
}
|
||||
61
src/main/java/com/dc/dc_project/enums/FileType.java
Normal file
61
src/main/java/com/dc/dc_project/enums/FileType.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package com.dc.dc_project.enums;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum FileType {
|
||||
|
||||
Unknown(0, "未知", "/unknown"),
|
||||
UserAvatar(1, "用户头像", "/avatar"),
|
||||
Certificate(2, "证书", "/certificate"),
|
||||
Report(3, "报告", "/report"),
|
||||
File(4, "文件", "/file"),
|
||||
Image(5, "图片", "/image"),
|
||||
UserFile(6, "用户文件", "/userFile"),
|
||||
ReportFile(7, "报告文件", "/reportFile"),
|
||||
Other(8, "其他", "/other");
|
||||
|
||||
private final Integer code;
|
||||
private final String message;
|
||||
private final String path;
|
||||
FileType(int code, String message, String path) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.path = path;
|
||||
}
|
||||
public static String getMessage(int code) {
|
||||
for (FileType item : FileType.values()) {
|
||||
if (item.getCode() == code) {
|
||||
return item.getMessage();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static int getCode(String message) {
|
||||
for (FileType item : FileType.values()) {
|
||||
if (item.getMessage().equals(message)) {
|
||||
return item.getCode();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static String getPath(int code) {
|
||||
for (FileType item : FileType.values()) {
|
||||
if (item.getCode() == code) {
|
||||
return item.getPath();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FileType getFileType(Integer code){
|
||||
for (FileType item : FileType.values()) {
|
||||
if (item.getCode() == code) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
17
src/main/java/com/dc/dc_project/model/dto/FileUploadDto.java
Normal file
17
src/main/java/com/dc/dc_project/model/dto/FileUploadDto.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.dc.dc_project.model.dto;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class FileUploadDto {
|
||||
|
||||
private Integer type;
|
||||
|
||||
private List<MultipartFile> files;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.dc.dc_project.service;
|
||||
|
||||
import com.dc.dc_project.common.ResponseResult;
|
||||
import com.dc.dc_project.model.dto.FileUploadDto;
|
||||
import com.dc.dc_project.model.pojo.File;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author ADMIN
|
||||
* @description 针对表【sys_file(通用文件信息表(文件存储记录))】的数据库操作Service
|
||||
@@ -10,4 +14,11 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
*/
|
||||
public interface FileService extends IService<File> {
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* @param fileUploadDto
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
ResponseResult upload(FileUploadDto fileUploadDto, Long userId);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
package com.dc.dc_project.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.dc.dc_project.common.ResponseResult;
|
||||
import com.dc.dc_project.config.MinioConfig;
|
||||
import com.dc.dc_project.config.exception.BusinessException;
|
||||
import com.dc.dc_project.enums.FileType;
|
||||
import com.dc.dc_project.model.dto.FileUploadDto;
|
||||
import com.dc.dc_project.model.pojo.File;
|
||||
import com.dc.dc_project.service.FileService;
|
||||
import com.dc.dc_project.mapper.FileMapper;
|
||||
import com.dc.dc_project.utils.FileUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ADMIN
|
||||
@@ -14,9 +31,73 @@ import lombok.extern.slf4j.Slf4j;
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class FileServiceImpl extends ServiceImpl<FileMapper, File>
|
||||
implements FileService{
|
||||
|
||||
private final MinioService minioService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResponseResult upload(FileUploadDto fileUploadDto, Long userId) {
|
||||
log.info("上传文件");
|
||||
FileType fileType = FileType.getFileType(fileUploadDto.getType());
|
||||
if (fileType == null) {
|
||||
return ResponseResult.error("文件类型错误");
|
||||
}
|
||||
|
||||
List<String> uploadedUrls = new ArrayList<>();
|
||||
List<File> files = new ArrayList<>();
|
||||
try {
|
||||
// 1. 先上传文件
|
||||
for (MultipartFile file : fileUploadDto.getFiles()) {
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
File sysFile = new File();
|
||||
sysFile.setFileName(file.getOriginalFilename());
|
||||
sysFile.setFileExt(FileUtil.getFileType(inputStream));
|
||||
sysFile.setRemark(fileUploadDto.getRemark());
|
||||
sysFile.setUploaderId(userId);
|
||||
sysFile.setFileSize(file.getSize());
|
||||
sysFile.setFileType(fileType.getCode());
|
||||
|
||||
// 上传到 MinIO
|
||||
String url = minioService.uploadFile(
|
||||
inputStream,
|
||||
FileUtil.getRandomFileName(),
|
||||
MinioConfig.MINIO_BUCKET_NAME,
|
||||
file.getContentType(),
|
||||
fileType.getPath()
|
||||
);
|
||||
|
||||
sysFile.setFileUrl(url);
|
||||
files.add(sysFile);
|
||||
uploadedUrls.add(url); // 记录已上传的 URL
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 保存到数据库
|
||||
if (!this.saveBatch(files)) {
|
||||
throw new BusinessException("数据库保存失败");
|
||||
}
|
||||
|
||||
return ResponseResult.success(files);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("文件上传失败,开始清理已上传的文件", e);
|
||||
|
||||
// 3. 回滚:删除已上传的文件
|
||||
for (String url : uploadedUrls) {
|
||||
try {
|
||||
minioService.deleteFile(url, MinioConfig.MINIO_BUCKET_NAME);
|
||||
log.info("已删除文件: {}", url);
|
||||
} catch (Exception deleteException) {
|
||||
log.error("删除文件失败: {}", url, deleteException);
|
||||
}
|
||||
}
|
||||
|
||||
throw new BusinessException("文件上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.dc.dc_project.service.impl;
|
||||
|
||||
|
||||
import com.dc.dc_project.config.MinioConfig;
|
||||
import io.minio.GetPresignedObjectUrlArgs;
|
||||
import io.minio.MinioClient;
|
||||
import io.minio.PutObjectArgs;
|
||||
import io.minio.RemoveObjectArgs;
|
||||
import io.minio.errors.*;
|
||||
import io.minio.http.Method;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class MinioService {
|
||||
|
||||
private final MinioClient minioClient;
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
public String uploadFile(InputStream inputStream, String fileName, String bucketName, String contentType, String path) {
|
||||
fileName = path + "/" + fileName;
|
||||
try {
|
||||
minioClient.putObject(
|
||||
PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
|
||||
inputStream, -1, 10485760)
|
||||
.contentType(contentType)
|
||||
.build());
|
||||
} catch (ErrorResponseException | XmlParserException | ServerException | InvalidResponseException |
|
||||
IOException | NoSuchAlgorithmException | InvalidKeyException | InternalException |
|
||||
InsufficientDataException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return MinioConfig.MINIO_ENDPOINT + "/" + bucketName + "/" + fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取临时访问连接
|
||||
*/
|
||||
public String getPreSignedUrl(String bucketName, String objectName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
|
||||
Map<String, String> reqParams = new HashMap<String, String>();
|
||||
reqParams.put("response-content-type", "application/json");
|
||||
|
||||
String url =
|
||||
minioClient.getPresignedObjectUrl(
|
||||
GetPresignedObjectUrlArgs.builder()
|
||||
.method(Method.GET)
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.expiry(2, TimeUnit.HOURS)
|
||||
.extraQueryParams(reqParams)
|
||||
.build());
|
||||
return url;
|
||||
}
|
||||
|
||||
public void deleteFile(String url, String minioBucketName) {
|
||||
String objectName = url.replace(MinioConfig.MINIO_ENDPOINT + "/" + minioBucketName + "/", "");
|
||||
try {
|
||||
minioClient.removeObject(
|
||||
RemoveObjectArgs.builder()
|
||||
.bucket(minioBucketName)
|
||||
.object(objectName)
|
||||
.build());
|
||||
} catch (ErrorResponseException | XmlParserException | ServerException | InvalidResponseException |
|
||||
IOException | NoSuchAlgorithmException | InvalidKeyException | InternalException |
|
||||
InsufficientDataException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dc.dc_project.service;
|
||||
package com.dc.dc_project.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@@ -13,6 +13,7 @@ import com.dc.dc_project.model.pojo.PersonnelPosition;
|
||||
import com.dc.dc_project.model.pojo.Position;
|
||||
import com.dc.dc_project.mapper.PositionMapper;
|
||||
import com.dc.dc_project.model.vo.PositionVo;
|
||||
import com.dc.dc_project.service.PositionService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -30,7 +31,7 @@ import static com.dc.dc_project.model.vo.PositionVo.potoVo;
|
||||
@Service
|
||||
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
|
||||
public class PositionServiceImpl extends ServiceImpl<PositionMapper, Position>
|
||||
implements PositionService{
|
||||
implements PositionService {
|
||||
|
||||
private final OrgMapper orgMapper;
|
||||
private final PersonnelPositionMapper personnelPositionMapper;
|
||||
38
src/main/java/com/dc/dc_project/utils/FileUtil.java
Normal file
38
src/main/java/com/dc/dc_project/utils/FileUtil.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package com.dc.dc_project.utils;
|
||||
|
||||
|
||||
import cn.hutool.core.io.FileTypeUtil;
|
||||
import com.dc.dc_project.enums.FileType;
|
||||
import com.dc.dc_project.model.pojo.File;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
public class FileUtil {
|
||||
|
||||
/**
|
||||
* 获取随机文件名
|
||||
*/
|
||||
public static String getRandomFileName() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件后缀
|
||||
* @param fileName
|
||||
* @date :2023/05/05
|
||||
*
|
||||
**/
|
||||
public static String getFileSuffix(String fileName) {
|
||||
return fileName.substring(fileName.lastIndexOf("."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型
|
||||
*
|
||||
**/
|
||||
public static String getFileType(InputStream file) {
|
||||
return FileTypeUtil.getType(file);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,9 @@ spring:
|
||||
shutdown-timeout: 100ms
|
||||
servlet:
|
||||
multipart:
|
||||
max-request-size: 100MB
|
||||
max-file-size: 100MB
|
||||
max-request-size: 200MB
|
||||
resolve-lazily: true
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
@@ -68,3 +70,11 @@ springdoc:
|
||||
swagger-ui:
|
||||
enabled: true # 开启swagger界面,依赖OpenApi,需要OpenApi同时开启
|
||||
path: /swagger-ui/index.html # 自定义路径,默认为"/swagger-ui/index.html"
|
||||
|
||||
minio:
|
||||
endpoint: http://192.168.1.100:9000
|
||||
accessKey: minioadmin
|
||||
secretKey: minioadmin
|
||||
bucketName: dc-lab-system
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user