一、先保证:你已经装好并启动了 MinIO
-
地址:
http://127.0.0.1:9000 -
控制台:
http://127.0.0.1:9000(新版也可能是 9090) -
默认账号 / 密码:
minioadmin / minioadmin -
提前创建好一个桶,比如 ruoyi-files(后面配置要一致)
-

二、后端添加 MinIO 依赖(ruoyi-common/pom.xml)
<!-- MinIO 文件存储 --> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.5.17</version> </dependency>然后执行
mvn clean install让依赖生效。
三、application.yml 配置(ruoyi-admin/src/main/resources/application.yml)
1)先关闭本地上传(或保留,用开关控制)
# 上传配置(本地可保留,方便切换)
ruoyi:
uploadType: minio # 关键:local / minio 二选一
profile: /home/ruoyi/upload
2)添加 MinIO 配置
# MinIO 配置
minio:
endpoint: http://127.0.0.1:9000
accessKey: minioadmin
secretKey: minioadmin
bucketName: ruoyi-files
endpoint:MinIO 地址accessKey/secretKey:登录账号密码bucketName:你在 MinIO 里建好的桶名
四、若依开启 MinIO 的核心:配置类 & 开关
若依原生已经支持上传类型切换 :ruoyi.uploadType=minio 即可自动走 MinIO 上传逻辑。
- 若依的
CommonController.upload()
java
package com.lims.web.controller.common;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.lims.common.config.RuoYiConfig;
import com.lims.common.core.domain.AjaxResult;
import com.lims.common.utils.StringUtils;
import com.lims.common.utils.file.FileUploadUtils;
import com.lims.common.utils.file.FileUtils;
import com.lims.framework.config.ServerConfig;
// 1. 引入MinIO工具类(需自行实现,示例类名)
import com.lims.common.utils.minio.MinioUploadUtils;
/**
* 通用请求处理
*
* @author ruoyi
*/
@RestController
@RequestMapping("/common")
public class CommonController
{
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@Autowired
private ServerConfig serverConfig;
private static final String FILE_DELIMITER = ",";
// 2. 定义上传类型常量(也可配置在yml中)
private static final String UPLOAD_TYPE_MINIO = "minio";
private static final String UPLOAD_TYPE_LOCAL = "local";
/**
* 通用下载请求
*
* @param fileName 文件名称
* @param delete 是否删除
*/
@GetMapping("/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{
try
{
if (!FileUtils.checkAllowDownload(fileName))
{
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = RuoYiConfig.getDownloadPath() + fileName;
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, realFileName);
FileUtils.writeBytes(filePath, response.getOutputStream());
if (delete)
{
FileUtils.deleteFile(filePath);
}
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
/**
* 通用上传请求(单个)
*/
@PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
// 3. 获取上传类型(建议配置在RuoYiConfig中,从yml读取)
String uploadType = RuoYiConfig.getUploadType(); // 需在RuoYiConfig中新增该方法
String fileName = null;
String url = null;
// 4. 分支:MinIO上传 / 本地上传
if (UPLOAD_TYPE_MINIO.equals(uploadType)) {
// MinIO上传逻辑(调用MinIO工具类)
fileName = MinioUploadUtils.upload(file); // 需实现MinIO上传方法,返回存储名称/路径
url = MinioUploadUtils.getFileUrl(fileName); // 获取MinIO文件访问地址
} else {
// 原有本地上传逻辑
String filePath = RuoYiConfig.getUploadPath();
fileName = FileUploadUtils.upload(filePath, file);
url = serverConfig.getUrl() + fileName;
}
AjaxResult ajax = AjaxResult.success();
ajax.put("url", url);
ajax.put("fileName", fileName);
ajax.put("newFileName", FileUtils.getName(fileName));
ajax.put("originalFilename", file.getOriginalFilename());
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 通用上传请求(多个)
*/
@PostMapping("/uploads")
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
{
try
{
// 3. 获取上传类型
String uploadType = RuoYiConfig.getUploadType();
// 上传文件路径(仅本地使用)
String filePath = RuoYiConfig.getUploadPath();
List<String> urls = new ArrayList<String>();
List<String> fileNames = new ArrayList<String>();
List<String> newFileNames = new ArrayList<String>();
List<String> originalFilenames = new ArrayList<String>();
for (MultipartFile file : files)
{
String fileName = null;
String url = null;
// 4. 分支:MinIO上传 / 本地上传
if (UPLOAD_TYPE_MINIO.equals(uploadType)) {
// MinIO多文件上传逻辑
fileName = MinioUploadUtils.upload(file);
url = MinioUploadUtils.getFileUrl(fileName);
} else {
// 原有本地多文件上传逻辑
fileName = FileUploadUtils.upload(filePath, file);
url = serverConfig.getUrl() + fileName;
}
urls.add(url);
fileNames.add(fileName);
newFileNames.add(FileUtils.getName(fileName));
originalFilenames.add(file.getOriginalFilename());
}
AjaxResult ajax = AjaxResult.success();
ajax.put("urls", StringUtils.join(urls, FILE_DELIMITER));
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMITER));
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMITER));
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMITER));
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 本地资源通用下载
*/
@GetMapping("/download/resource")
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
try
{
if (!FileUtils.checkAllowDownload(resource))
{
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
}
// 本地资源路径
String localPath = RuoYiConfig.getProfile();
// 数据库资源地址
String downloadPath = localPath + FileUtils.stripPrefix(resource);
// 下载名称
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, downloadName);
FileUtils.writeBytes(downloadPath, response.getOutputStream());
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
}
配套修改说明(必须完成):
-
RuoYiConfig 补充配置 在
RuoYiConfig类中新增上传类型读取方法(从配置文件application.yml读取):// RuoYiConfig.java @Value("${upload.type:local}") // 默认本地存储 private String uploadType; public String getUploadType() { return uploadType; }并在
application.yml中增加配置:# 上传配置 upload: type: local # 可选值:local/minio # 其他配置(如minio地址、密钥等) minio: endpoint: http://127.0.0.1:9000 accessKey: minioadmin secretKey: minioadmin bucketName: lims-bucket -
实现 MinIO 工具类 需编写
MinioUploadUtils工具类,核心方法示例:java// MinioUploadUtils.java public class MinioUploadUtils { // MinIO客户端配置(从yml读取) private static String endpoint; private static String accessKey; private static String secretKey; private static String bucketName; // 初始化MinIO客户端 private static MinioClient getMinioClient() { return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } // 上传文件到MinIO public static String upload(MultipartFile file) throws Exception { // 1. 生成唯一文件名(避免重复) String originalFilename = file.getOriginalFilename(); String fileName = UUID.randomUUID().toString() + "." + FileUtils.getExtension(originalFilename); // 2. 上传到MinIO getMinioClient().putObject( PutObjectArgs.builder() .bucket(bucketName) .object(fileName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build() ); return fileName; } // 获取MinIO文件访问URL public static String getFileUrl(String fileName) throws Exception { // 生成带签名的URL(或直接返回公网地址,根据MinIO配置) return endpoint + "/" + bucketName + "/" + fileName; } }
五、MinIO 桶权限必须设置(否则访问 403)
进入 MinIO 控制台 → 选中你的桶(ruoyi-files)→ Edit Policy → 写入:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": ["s3:GetObject","s3:PutObject"],
"Resource": ["arn:aws:s3:::ruoyi-files/*"]
}
]
}