mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-18 09:35:29 +08:00
rustfs 文件上传系统支持
This commit is contained in:
parent
c9f291a898
commit
545488d5e0
@ -84,6 +84,17 @@
|
|||||||
<artifactId>dubbo-nacos-spring-boot-starter</artifactId>
|
<artifactId>dubbo-nacos-spring-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.liuxp</groupId>
|
||||||
|
<artifactId>minio-plus-all-springboot-starter</artifactId>
|
||||||
|
<version>1.0.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.liuxp</groupId>
|
||||||
|
<artifactId>s3-api-minio</artifactId>
|
||||||
|
<version>1.0.5</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
package com.luban.api.config;
|
package com.luban.api.config;
|
||||||
|
|
||||||
|
import com.luban.api.s3.config.S3LoginUserInterceptor;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
@ -19,4 +21,14 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
|||||||
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
|
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
|
||||||
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0);
|
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前置拦截器
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
// 登录用户获取用户id
|
||||||
|
registry.addInterceptor(new S3LoginUserInterceptor()).addPathPatterns("/storage/**");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.luban.api.s3.config;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.liuxp.minioplus.extension.context.UserHolder;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录用户拦截器
|
||||||
|
*
|
||||||
|
* @author contact@liuxp.me
|
||||||
|
* @since 2024/06/11
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class S3LoginUserInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理登录用户信息
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @param response 返回
|
||||||
|
* @param handler 要执行的处理程序
|
||||||
|
* @return 是否继续执行下一个拦截器
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler) {
|
||||||
|
String userId = request.getHeader("Authorization");
|
||||||
|
if (CharSequenceUtil.isBlank(userId)) {
|
||||||
|
UserHolder.set("");
|
||||||
|
} else {
|
||||||
|
//TODO 用户id还未生成
|
||||||
|
UserHolder.set(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理资源
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @param response 返回
|
||||||
|
* @param handler 要执行的处理程序
|
||||||
|
* @param exception 异常信息
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception exception) {
|
||||||
|
log.debug("Project ThreadLocal 清理之前:{}", UserHolder.get());
|
||||||
|
UserHolder.clean();
|
||||||
|
log.debug("Project ThreadLocal 清理之之后:{}", UserHolder.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.luban.api.s3.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import com.luban.api.s3.entity.FileMetadataInfoEntity;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface FileMetadataInfoMapper extends BaseMapper<FileMetadataInfoEntity> {
|
||||||
|
}
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
package com.luban.api.s3.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件元数据信息表Entity
|
||||||
|
*
|
||||||
|
* @author contact@liuxp.me
|
||||||
|
* @since 2024-05-22
|
||||||
|
**/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@TableName(value = "file_metadata_info")
|
||||||
|
public class FileMetadataInfoEntity {
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
@Schema(description = "主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "文件KEY")
|
||||||
|
@TableField(value = "file_key")
|
||||||
|
private String fileKey;
|
||||||
|
|
||||||
|
@Schema(description = "文件md5")
|
||||||
|
@TableField(value = "file_md5")
|
||||||
|
private String fileMd5;
|
||||||
|
|
||||||
|
@Schema(description = "文件名")
|
||||||
|
@TableField(value = "file_name")
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
@Schema(description = "MIME类型")
|
||||||
|
@TableField(value = "file_mime_type")
|
||||||
|
private String fileMimeType;
|
||||||
|
|
||||||
|
@Schema(description = "文件后缀")
|
||||||
|
@TableField(value = "file_suffix")
|
||||||
|
private String fileSuffix;
|
||||||
|
|
||||||
|
@Schema(description = "文件长度")
|
||||||
|
@TableField(value = "file_size")
|
||||||
|
private Long fileSize;
|
||||||
|
|
||||||
|
@Schema(description = "预览图 0:无 1:有")
|
||||||
|
@TableField(value = "is_preview")
|
||||||
|
private Boolean isPreview;
|
||||||
|
|
||||||
|
@Schema(description = "是否私有 0:否 1:是")
|
||||||
|
@TableField(value = "is_private")
|
||||||
|
private Boolean isPrivate;
|
||||||
|
|
||||||
|
@Schema(description = "存储桶")
|
||||||
|
@TableField(value = "bucket")
|
||||||
|
private String storageBucket;
|
||||||
|
|
||||||
|
@Schema(description = "存储桶路径")
|
||||||
|
@TableField(value = "bucket_path")
|
||||||
|
private String storagePath;
|
||||||
|
|
||||||
|
@Schema(description = "上传任务id,用于合并切片")
|
||||||
|
@TableField(value = "upload_id")
|
||||||
|
private String uploadTaskId;
|
||||||
|
|
||||||
|
@Schema(description = "状态 0:未完成 1:已完成")
|
||||||
|
@TableField(value = "is_finished")
|
||||||
|
private Boolean isFinished;
|
||||||
|
|
||||||
|
@Schema(description = "是否分块 0:否 1:是")
|
||||||
|
@TableField(value = "is_part")
|
||||||
|
private Boolean isPart;
|
||||||
|
|
||||||
|
@Schema(description = "分块数量")
|
||||||
|
@TableField(value = "part_number")
|
||||||
|
private Integer partNumber;
|
||||||
|
|
||||||
|
@Schema(description = "创建人")
|
||||||
|
@TableField("create_user")
|
||||||
|
private String createUser;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
@TableField("create_time")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
@Schema(description = "修改人")
|
||||||
|
@TableField("update_user")
|
||||||
|
private String updateUser;
|
||||||
|
|
||||||
|
@Schema(description = "修改时间")
|
||||||
|
@TableField("update_time")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
package com.luban.api.s3.service;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.liuxp.minioplus.api.model.dto.FileMetadataInfoDTO;
|
||||||
|
import org.liuxp.minioplus.api.model.dto.FileMetadataInfoSaveDTO;
|
||||||
|
import org.liuxp.minioplus.api.model.dto.FileMetadataInfoUpdateDTO;
|
||||||
|
import org.liuxp.minioplus.api.model.vo.FileMetadataInfoVo;
|
||||||
|
import org.liuxp.minioplus.core.repository.MetadataRepository;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.luban.api.s3.dao.FileMetadataInfoMapper;
|
||||||
|
import com.luban.api.s3.entity.FileMetadataInfoEntity;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件元数据接口实现类
|
||||||
|
*
|
||||||
|
* @author contact@liuxp.me
|
||||||
|
* @since 2024/05/22
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class MetadataRepositoryImpl extends ServiceImpl<FileMetadataInfoMapper, FileMetadataInfoEntity> implements MetadataRepository {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FileMetadataInfoVo> list(FileMetadataInfoDTO searchDTO) {
|
||||||
|
|
||||||
|
// 组装查询参数
|
||||||
|
QueryWrapper<FileMetadataInfoEntity> queryWrapper = buildParams(searchDTO);
|
||||||
|
|
||||||
|
List<FileMetadataInfoEntity> fileMetadataInfoEntityList = super.list(queryWrapper);
|
||||||
|
|
||||||
|
List<FileMetadataInfoVo> fileMetadataInfoVoList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (FileMetadataInfoEntity fileMetadataInfoEntity : fileMetadataInfoEntityList) {
|
||||||
|
FileMetadataInfoVo fileMetadataInfoVo = new FileMetadataInfoVo();
|
||||||
|
BeanUtils.copyProperties(fileMetadataInfoEntity, fileMetadataInfoVo);
|
||||||
|
fileMetadataInfoVoList.add(fileMetadataInfoVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileMetadataInfoVoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileMetadataInfoVo one(FileMetadataInfoDTO searchDTO) {
|
||||||
|
|
||||||
|
// 组装查询参数
|
||||||
|
QueryWrapper<FileMetadataInfoEntity> queryWrapper = buildParams(searchDTO);
|
||||||
|
queryWrapper.last("limit 1");
|
||||||
|
|
||||||
|
FileMetadataInfoEntity fileMetadataInfoEntity = super.getOne(queryWrapper);
|
||||||
|
|
||||||
|
FileMetadataInfoVo fileMetadataInfoVo = null;
|
||||||
|
|
||||||
|
if (null != fileMetadataInfoEntity) {
|
||||||
|
fileMetadataInfoVo = new FileMetadataInfoVo();
|
||||||
|
BeanUtils.copyProperties(fileMetadataInfoEntity, fileMetadataInfoVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileMetadataInfoVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileMetadataInfoVo save(FileMetadataInfoSaveDTO saveDTO) {
|
||||||
|
|
||||||
|
FileMetadataInfoEntity fileMetadataInfoEntity = new FileMetadataInfoEntity();
|
||||||
|
BeanUtils.copyProperties(saveDTO, fileMetadataInfoEntity);
|
||||||
|
fileMetadataInfoEntity.setCreateTime(new Date());
|
||||||
|
fileMetadataInfoEntity.setUpdateTime(new Date());
|
||||||
|
|
||||||
|
boolean result = super.save(fileMetadataInfoEntity);
|
||||||
|
|
||||||
|
FileMetadataInfoVo fileMetadataInfoVo = new FileMetadataInfoVo();
|
||||||
|
if (result) {
|
||||||
|
BeanUtils.copyProperties(fileMetadataInfoEntity, fileMetadataInfoVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileMetadataInfoVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileMetadataInfoVo update(FileMetadataInfoUpdateDTO updateDTO) {
|
||||||
|
|
||||||
|
FileMetadataInfoEntity fileMetadataInfoEntity = new FileMetadataInfoEntity();
|
||||||
|
BeanUtils.copyProperties(updateDTO, fileMetadataInfoEntity);
|
||||||
|
fileMetadataInfoEntity.setUpdateTime(new Date());
|
||||||
|
boolean result = super.updateById(fileMetadataInfoEntity);
|
||||||
|
|
||||||
|
FileMetadataInfoVo fileMetadataInfoVo = new FileMetadataInfoVo();
|
||||||
|
if (result) {
|
||||||
|
BeanUtils.copyProperties(fileMetadataInfoEntity, fileMetadataInfoVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileMetadataInfoVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean remove(Long id) {
|
||||||
|
return super.removeById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryWrapper<FileMetadataInfoEntity> buildParams(FileMetadataInfoDTO searchDTO) {
|
||||||
|
// 组装查询参数
|
||||||
|
QueryWrapper<FileMetadataInfoEntity> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq(CharSequenceUtil.isNotBlank(searchDTO.getFileKey()), "file_key", searchDTO.getFileKey());
|
||||||
|
queryWrapper.eq(CharSequenceUtil.isNotBlank(searchDTO.getFileMd5()), "file_md5", searchDTO.getFileMd5());
|
||||||
|
queryWrapper.eq(CharSequenceUtil.isNotBlank(searchDTO.getBucket()), "bucket", searchDTO.getBucket());
|
||||||
|
queryWrapper.eq(null != searchDTO.getIsPrivate(), "is_private", searchDTO.getIsPrivate());
|
||||||
|
queryWrapper.eq(CharSequenceUtil.isNotBlank(searchDTO.getCreateUser()), "create_user", searchDTO.getCreateUser());
|
||||||
|
|
||||||
|
return queryWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -73,3 +73,10 @@ mybatis-plus:
|
|||||||
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
|
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
|
||||||
# 如需改为自增 需要将数据库表全部设置为自增
|
# 如需改为自增 需要将数据库表全部设置为自增
|
||||||
idType: ASSIGN_ID
|
idType: ASSIGN_ID
|
||||||
|
minioplus:
|
||||||
|
# rustfs 部署地址
|
||||||
|
backend: http://localhost:9000
|
||||||
|
# 授权key
|
||||||
|
key: rustfsadmin
|
||||||
|
# 密钥
|
||||||
|
secret: rustfsadmin
|
||||||
|
|||||||
@ -7,3 +7,18 @@ services:
|
|||||||
- /d/Program Files/docker/path/mall-swarm/mongo/db:/data/db #数据文件挂载
|
- /d/Program Files/docker/path/mall-swarm/mongo/db:/data/db #数据文件挂载
|
||||||
ports:
|
ports:
|
||||||
- 27017:27017
|
- 27017:27017
|
||||||
|
rustfs:
|
||||||
|
image: registry.cn-shanghai.aliyuncs.com/study-03/rustfs:latest
|
||||||
|
container_name: rustfs
|
||||||
|
ports:
|
||||||
|
- "19000:9000" # 管理控制台
|
||||||
|
- "9090:9090" # API服务端口
|
||||||
|
volumes:
|
||||||
|
- rustfs_data_volume:/data
|
||||||
|
environment:
|
||||||
|
- RUSTFS_ROOT_USER=admin
|
||||||
|
- RUSTFS_ROOT_PASSWORD=admin123
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
rustfs_data_volume:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user