前言
MinIO 是一个开源的对象存储服务器,它可以存储大容量非结构化的数据,例如图片、音频、视频、日志文件、备份数据和容器/虚拟机镜像等。
Spring Boot 与 MinIO 的整合可以方便地实现文件的上传和下载等功能
在实际应用中,Spring Boot 对接 MinIO 可以用于以下场景:
- 文件存储:将文件存储在 MinIO 中,以便在需要时进行访问和下载。
- 数据备份:将数据备份到 MinIO 中,以便在需要时进行恢复。
- 容器镜像存储:将 Docker 容器镜像存储在 MinIO 中,以便在需要时进行访问和下载。
- 静态资源存储:将静态资源(如 CSS、JavaScript 和图像)存储在 MinIO 中,以便在需要时进行访问和下载。
通过 Spring Boot 对接 MinIO,你可以方便地管理和操作文件存储,并且可以根据自己的需求进行扩展和定制化
MinIO 安装
MinIO 安装参考:Linux 部署 MinIO 分布式对象存储 & 配置为 typora 图床
引入依赖
maven 依赖
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.2</version>
</dependency>
配置
配置文件
在 application.yml 中添加
minio:endpoint: http://192.168.101.3:9001access-key: DHgpKILqY5iNa88LByHx # minio 的 accessKeysecret-key: Ppa9Nxes7jOkbBD2BTuFhjFcfGjw3lXmXUItKcBV # minio 的 secretKey
创建配置类
对应配置文件
@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioInfo {private String endpoint;private String accessKey;private String secretKey;
}
配置客户端
配置 minio 操作客户端
@Configuration
@EnableConfigurationProperties(MinioInfo.class)
public class MinioConfig {@Autowiredprivate MinioInfo minioInfo;/*** 获取 minioClient*/@Beanpublic MinioClient minioClient() throws NoSuchAlgorithmException, KeyManagementException {return MinioClient.builder().endpoint(minioInfo.getEndpoint()).credentials(minioInfo.getAccessKey(),minioInfo.getSecretKey()).build();}
}
工具类封装
@Slf4j
@Component
public class MinioUtils {@Autowiredprivate MinioClient minioClient;@Autowiredprivate MinioInfo minioInfo;/*** 上传文件** @param file 文件信息* @param bucketName minio bucket 名称* @return 上传文件路径*/public String uploadFile(MultipartFile file, String bucketName) {if (file == null || file.getSize() == 0) {log.error("minio 上传文件:{}", "上传文件不能为空");return null;}try {// 判断是否存在createBucket(bucketName);// 原文件名String originalFilename = file.getOriginalFilename();minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(originalFilename).stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build());return minioInfo.getEndpoint() + "/" + bucketName + "/" + originalFilename;} catch (Exception e) {log.error("minio 上传失败:{}", e.getMessage());}log.error("minio 上传文件:{}", "上传失败");return null;}/*** 通过字节流上传** @param imageFullPath 图片路径* @param bucketName minio bucket 名称* @param imageData 图片数据* @return 上传文件路径*/public String uploadImage(String imageFullPath,String bucketName,byte[] imageData) {ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(imageData);try {//判断是否存在createBucket(bucketName);minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(imageFullPath).stream(byteArrayInputStream, byteArrayInputStream.available(), -1).contentType(".jpg").build());return minioInfo.getEndpoint() + "/" + bucketName + "/" + imageFullPath;} catch (Exception e) {log.error("minio 上传失败:{}", e.getMessage());}log.error("minio 上传失败:{}", "上传失败");return null;}/*** 删除文件** @param bucketName minio bucket 名称* @param fileName 文件名* @return*/public Boolean removeFile(String bucketName, String fileName) {try {//判断桶是否存在boolean res = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());if (res) {//删除文件minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());}} catch (Exception e) {log.error("minio 删除文件失败");e.printStackTrace();return false;}return true;}/*** 下载文件** @param fileName 文件名* @param bucketName minio bucket 名称* @param response 请求响应*/public void fileDownload(String fileName,String bucketName,HttpServletResponse response) {InputStream inputStream = null;OutputStream outputStream = null;try {if (StringUtils.isBlank(fileName)) {response.setHeader("Content-type", "text/html;charset=UTF-8");String data = "文件下载失败";OutputStream ps = response.getOutputStream();ps.write(data.getBytes("UTF-8"));return;}outputStream = response.getOutputStream();// 获取文件对象inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());byte buf[] = new byte[1024];int length = 0;response.reset();response.setHeader("Content-Disposition", "attachment;filename=" +URLEncoder.encode(fileName.substring(fileName.lastIndexOf("/") + 1), "UTF-8"));response.setContentType("application/octet-stream");response.setCharacterEncoding("UTF-8");// 输出文件while ((length = inputStream.read(buf)) > 0) {outputStream.write(buf, 0, length);}System.out.println("下载成功");inputStream.close();} catch (Throwable ex) {response.setHeader("Content-type", "text/html;charset=UTF-8");String data = "文件下载失败";try {OutputStream ps = response.getOutputStream();ps.write(data.getBytes("UTF-8"));} catch (IOException e) {e.printStackTrace();}} finally {try {outputStream.close();if (inputStream != null) {inputStream.close();}} catch (IOException e) {e.printStackTrace();}}}@SneakyThrowspublic void createBucket(String bucketName) {// 不存在就创建if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}}
}
使用
上传文件
@RestController
@RequestMapping("/minio")
public class TestMinioController {@Resourceprivate MinioUtils minioUtils;/*** 上传文件* @param file 文件* @return 路径*/@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)@ResponseBodypublic BaseResponse<String> uploadByMinio(@RequestParam(name = "file") MultipartFile file) {//返回存储路径String path = minioUtils.uploadFile(file, "minio-img");return ResultUtils.success(path);}
}
请求参数为 file,类型为 file,响应回来的 data 为文件路径
请求成功后,可以在 minio 中查看
下载文件
根据文件名下载文件
/*** 根据文件名下载文件** @param fileName 文件名* @param response 请求响应体*/
@GetMapping("/download")
public void downloadByMinio(@RequestParam(name = "fileName") String fileName,HttpServletResponse response) {try {minioUtils.fileDownload(fileName, "minio-img", response);} catch (Exception e) {e.printStackTrace();}
}
请求参数为 fileName
删除文件
/*** 根据文件名删除文件** @param fileName 文件名* @return 是否成功*/
@PostMapping("/delete")
@ResponseBody
public BaseResponse<String> deleteByMonio(String fileName) {Boolean result = minioUtils.removeFile("minio-img", fileName);if (!result) {return ResultUtils.error(ErrorCode.SYSTEM_ERROR,"删除失败");}return ResultUtils.success("删除成功");
}