当前位置: 首页 > news >正文

项目实战--Spring Boot + Minio文件切片上传下载

1.搭建环境

引入项目依赖

<!-- 操作minio的java客户端-->
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.2</version>
</dependency>
<!--        jwt鉴权相应依赖-->
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.2</version>
</dependency>

创建容器桶
在这里插入图片描述
在这里插入图片描述
获取API访问凭证
在这里插入图片描述
在这里插入图片描述
编写配置文件

server:port: 8080
spring:servlet:multipart:max-file-size: 10MBmax-request-size: 10MB#minio配置minio:access-key: dAMaxkWaXUD1CV1JHbqwsecret-key: AXt3SD0JFkDENFbMeJKOOQb5wj8KvabZWu33Rs84url: http://192.168.128.114:9090  #访问地址bucket-name: wx_manager
首先是服务器的配置:端口号为8080,用于监听请求。使用了一个Servlet来处理multipart/form-data类型的请求。在接收到multipart/form-data类型的请求时,会将上传的文件大小限制在10MB以内,并将请求大小限制在10MB以内。接下来是minio的配置:access-key和secret-key是访问minio服务的凭证,需要根据实际情况进行填写。url是minio服务的地址,需要根据实际情况进行填写。bucket-name是存储文件的桶名,需要根据实际情况进行填写。

http请求状态

public class HttpStatus
{/*** 操作成功*/public static final int SUCCESS = 200;/*** 对象创建成功*/public static final int CREATED = 201;/*** 请求已经被接受*/public static final int ACCEPTED = 202;/*** 操作已经执行成功,但是没有返回数据*/public static final int NO_CONTENT = 204;/*** 资源已被移除*/public static final int MOVED_PERM = 301;/*** 重定向*/public static final int SEE_OTHER = 303;/*** 资源没有被修改*/public static final int NOT_MODIFIED = 304;/*** 参数列表错误(缺少,格式不匹配)*/public static final int BAD_REQUEST = 400;/*** 未授权*/public static final int UNAUTHORIZED = 401;/*** 访问受限,授权过期*/public static final int FORBIDDEN = 403;/*** 资源,服务未找到*/public static final int NOT_FOUND = 404;/*** 不允许的http方法*/public static final int BAD_METHOD = 405;/*** 资源冲突,或者资源被锁*/public static final int CONFLICT = 409;/*** 不支持的数据,媒体类型*/public static final int UNSUPPORTED_TYPE = 415;/*** 系统内部错误*/public static final int ERROR = 500;/*** 接口未实现*/public static final int NOT_IMPLEMENTED = 501;/*** 系统警告消息*/public static final int WARN = 601;
}

通用常量信息

import io.jsonwebtoken.Claims;public class Constants
{/*** UTF-8 字符集*/public static final String UTF8 = "UTF-8";/*** GBK 字符集*/public static final String GBK = "GBK";/*** www主域*/public static final String WWW = "www.";/*** http请求*/public static final String HTTP = "http://";/*** https请求*/public static final String HTTPS = "https://";/*** 通用成功标识*/public static final String SUCCESS = "0";/*** 通用失败标识*/public static final String FAIL = "1";/*** 登录成功*/public static final String LOGIN_SUCCESS = "Success";/*** 注销*/public static final String LOGOUT = "Logout";/*** 注册*/public static final String REGISTER = "Register";/*** 登录失败*/public static final String LOGIN_FAIL = "Error";/*** 验证码有效期(分钟)*/public static final Integer CAPTCHA_EXPIRATION = 2;/*** 令牌*/public static final String TOKEN = "token";/*** 令牌前缀*/public static final String TOKEN_PREFIX = "Bearer ";/*** 令牌前缀*/public static final String LOGIN_USER_KEY = "login_user_key";/*** 用户ID*/public static final String JWT_USERID = "userid";/*** 用户名称*/public static final String JWT_USERNAME = Claims.SUBJECT;/*** 用户头像*/public static final String JWT_AVATAR = "avatar";/*** 创建时间*/public static final String JWT_CREATED = "created";/*** 用户权限*/public static final String JWT_AUTHORITIES = "authorities";/*** 资源映射路径 前缀*/public static final String RESOURCE_PREFIX = "/profile";/*** RMI 远程方法调用*/public static final String LOOKUP_RMI = "rmi:";/*** LDAP 远程方法调用*/public static final String LOOKUP_LDAP = "ldap:";/*** LDAPS 远程方法调用*/public static final String LOOKUP_LDAPS = "ldaps:";/*** 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)*/public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" };/*** 定时任务违规的字符*/public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml","org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config" };
}

Minio的配置类

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "spring.minio")
public class MinioConfig {// 访问密钥和密钥值private String accessKey;private String secretKey;private String url;private String bucketName;@Beanpublic MinioClient minioClient(){return MinioClient.builder().endpoint(url).credentials(accessKey,secretKey).build();}
}

Minio的工具类

import com.xiaohui.config.MinioConfig;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.SneakyThrows;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;/*** @Description Minio工具类*/@Component
public class MinioUtils {@Autowiredprivate MinioClient minioClient;@Autowiredprivate MinioConfig configuration;/*** @param name 名字* @return boolean* @Description description: 判断bucket是否存在,不存在则创建*/public boolean existBucket(String name) {boolean exists;try {exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());if (!exists) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());exists = true;}} catch (Exception e) {e.printStackTrace();exists = false;}return exists;}/*** @param bucketName 存储bucket名称* @return {@link Boolean }* @Description 创建存储bucket*/public Boolean makeBucket(String bucketName) {try {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** @param bucketName 存储bucket名称* @return {@link Boolean }* @Description 删除存储bucket* @Author IT小辉同学* @Date 2023/06/02*/public Boolean removeBucket(String bucketName) {try {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** @param fileName 文件名称* @param time     时间* @return {@link Map }* @Description 获取上传临时签名*/@SneakyThrowspublic Map getPolicy(String fileName, ZonedDateTime time) {PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);postPolicy.addEqualsCondition("key", fileName);try {Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);HashMap<String, String> map1 = new HashMap<>();map.forEach((k, v) -> {map1.put(k.replaceAll("-", ""), v);});map1.put("host", configuration.getUrl() + "/" + configuration.getBucketName());return map1;} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();}return null;}/*** @param objectName 对象名称* @param method     方法* @param time       时间* @param timeUnit   时间单位* @return {@link String }* @Description 获取上传文件的url*/public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit) {try {return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(method).bucket(configuration.getBucketName()).object(objectName).expiry(time, timeUnit).build());} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();}return null;}/*** @param file     文件* @param fileName 文件名称* @Description 上传文件*/public void upload(MultipartFile file, String fileName) {// 使用putObject上传一个文件到存储桶中。try {InputStream inputStream = file.getInputStream();minioClient.putObject(PutObjectArgs.builder().bucket(configuration.getBucketName()).object(fileName).stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build());} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();}}/*** @param objectName 对象名称* @param time       时间* @param timeUnit   时间单位* @return {@link String }* @Description 根据filename获取文件访问地址*/public String getUrl(String objectName, int time, TimeUnit timeUnit) {String url = null;try {url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(configuration.getBucketName()).object(objectName).expiry(time, timeUnit).build());} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();}return url;}/*** @param fileName* @return {@link ResponseEntity }<{@link byte[] }>* @Description description: 下载文件*/public ResponseEntity<byte[]> download(String fileName) {ResponseEntity<byte[]> responseEntity = null;InputStream in = null;ByteArrayOutputStream out = null;try {in = minioClient.getObject(GetObjectArgs.builder().bucket(configuration.getBucketName()).object(fileName).build());out = new ByteArrayOutputStream();IOUtils.copy(in, out);//封装返回值byte[] bytes = out.toByteArray();HttpHeaders headers = new HttpHeaders();try {headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));} catch (UnsupportedEncodingException e) {e.printStackTrace();}headers.setContentLength(bytes.length);headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);headers.setAccessControlExposeHeaders(Arrays.asList("*"));responseEntity = new ResponseEntity<byte[]>(bytes, headers, HttpStatus.SUCCESS);} catch (Exception e) {e.printStackTrace();} finally {try {if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}}if (out != null) {out.close();}} catch (IOException e) {e.printStackTrace();}}return responseEntity;}/*** @param objectFile 对象文件* @return {@link String }* @Description 根据文件名和桶获取文件路径*/public String getFileUrl(String objectFile) {try {return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(configuration.getBucketName()).object(objectFile).build());} catch (Exception e) {e.printStackTrace();}return null;}
}
使用阿里云的对象存储服务(OSS)进行文件上传和下载:getPolicy(String fileName, ZonedDateTime time):根据文件名和时间戳获取上传临时签名。getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit):获取上传文件的url。upload(MultipartFile file, String fileName):将文件上传到OSS中。getUrl(String objectName, int time, TimeUnit timeUnit):获取文件的下载url。使用枚举类型来定义不同的上传和下载方法。使用了注解@Autowired来自动注入MinioClient对象。该工具类没有提供异常处理机制,需要根据实际情况进行补充。

Ajax请求工具类

/*** @Description ajax结果*/
public class AjaxResult extends HashMap<String, Object>
{private static final long serialVersionUID = 1L;/** 状态码 */public static final String CODE_TAG = "code";/** 返回内容 */public static final String MSG_TAG = "msg";/** 数据对象 */public static final String DATA_TAG = "data";/*** 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。*/public AjaxResult(){}/*** 初始化一个新创建的 AjaxResult 对象** @param code 状态码* @param msg 返回内容*/public AjaxResult(int code, String msg){super.put(CODE_TAG, code);super.put(MSG_TAG, msg);}/*** 初始化一个新创建的 AjaxResult 对象** @param code 状态码* @param msg 返回内容* @param data 数据对象*/public AjaxResult(int code, String msg, Object data){super.put(CODE_TAG, code);super.put(MSG_TAG, msg);if (data!=null){super.put(DATA_TAG, data);}}/*** 返回成功消息** @return 成功消息*/public static AjaxResult success(){return AjaxResult.success("操作成功");}/*** 返回成功数据** @return 成功消息*/public static AjaxResult success(Object data){return AjaxResult.success("操作成功", data);}/*** 返回成功消息** @param msg 返回内容* @return 成功消息*/public static AjaxResult success(String msg){return AjaxResult.success(msg, null);}/*** 返回成功消息** @param msg 返回内容* @param data 数据对象* @return 成功消息*/public static AjaxResult success(String msg, Object data){return new AjaxResult(HttpStatus.SUCCESS, msg, data);}/*** 返回警告消息** @param msg 返回内容* @return 警告消息*/public static AjaxResult warn(String msg){return AjaxResult.warn(msg, null);}/*** 返回警告消息** @param msg 返回内容* @param data 数据对象* @return 警告消息*/public static AjaxResult warn(String msg, Object data){return new AjaxResult(HttpStatus.WARN, msg, data);}/*** 返回错误消息** @return 错误消息*/public static AjaxResult error(){return AjaxResult.error("操作失败");}/*** 返回错误消息** @param msg 返回内容* @return 错误消息*/public static AjaxResult error(String msg){return AjaxResult.error(msg, null);}/*** 返回错误消息** @param msg 返回内容* @param data 数据对象* @return 错误消息*/public static AjaxResult error(String msg, Object data){return new AjaxResult(HttpStatus.ERROR, msg, data);}/*** 返回错误消息** @param code 状态码* @param msg 返回内容* @return 错误消息*/public static AjaxResult error(int code, String msg){return new AjaxResult(code, msg, null);}/*** 方便链式调用** @param key 键* @param value 值* @return 数据对象*/@Overridepublic AjaxResult put(String key, Object value){super.put(key, value);return this;}
}

Minio文件操作接口层

import com.xiaohui.utils.AjaxResult;
import com.xiaohui.utils.MinioUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.util.HashMap;/*** @Description minio文件上传控制器*/
@CrossOrigin
@RestController
@RequestMapping("/api")
public class MinioFileUploadController {@Autowiredprivate MinioUtils minioUtils;/*** @param file     文件* @param fileName 文件名称* @return {@link AjaxResult }* @Description 上传文件*/@GetMapping("/upload")public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, String fileName) {minioUtils.upload(file, fileName);return AjaxResult.success("上传成功");}/*** @param fileName 文件名称* @return {@link ResponseEntity }* @Description dowload文件*/@GetMapping("/dowload")public ResponseEntity dowloadFile(@RequestParam("fileName") String fileName) {return minioUtils.download(fileName);}/*** @param fileName 文件名称* @return {@link AjaxResult }* @Description 得到文件url*/@GetMapping("/getUrl")public AjaxResult getFileUrl(@RequestParam("fileName") String fileName){HashMap map=new HashMap();map.put("FileUrl",minioUtils.getFileUrl(fileName));return AjaxResult.success(map);}
}
2.测试

Minio大文件上传
在这里插入图片描述
在这里插入图片描述
Minio大文件地址
在这里插入图片描述

访问这个地址即可。

参考文档
Centos7安装Minio笔记

相关文章:

  • PyTorch(六)优化模型参数
  • 2.2.5 C#中显示控件BDPictureBox 的实现----ROI交互续2
  • Golang中defer和return顺序
  • LabVIEW幅频特性测试系统
  • 前端工程化08-新的包管理工具pnpm
  • python系列30:各种爬虫技术总结
  • MySQL增删改查
  • Java Nio核心概念理解
  • 关于 Mybatis 的开启二级缓存返回对象不一致问题
  • 嵌入式PCB制图面试题及参考答案(2万字长文)
  • 【融合ChatGPT等AI模型】Python-GEE遥感云大数据分析、管理与可视化及多领域案例应用
  • 【2024德国签证】去德国读博士需要申请什么签证?
  • Spire.PDF for .NET【文档操作】演示:以特定的缩放比例/百分比打开 PDF 文件
  • 力扣习题--哈沙德数
  • Redis Stream Redisson Stream
  • 深入了解以太坊
  • 77. Combinations
  • CSS盒模型深入
  • ES6--对象的扩展
  • HashMap ConcurrentHashMap
  • iOS小技巧之UIImagePickerController实现头像选择
  • java正则表式的使用
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • Protobuf3语言指南
  • React-生命周期杂记
  • Xmanager 远程桌面 CentOS 7
  • 复杂数据处理
  • 高性能JavaScript阅读简记(三)
  • 关于 Cirru Editor 存储格式
  • 利用DataURL技术在网页上显示图片
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 原生js练习题---第五课
  • 自动记录MySQL慢查询快照脚本
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • 正则表达式-基础知识Review
  • #pragma预处理命令
  • #QT项目实战(天气预报)
  • #Spring-boot高级
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • (003)SlickEdit Unity的补全
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (Oracle)SQL优化技巧(一):分页查询
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (九十四)函数和二维数组
  • (力扣)1314.矩阵区域和
  • (七)Knockout 创建自定义绑定
  • (三)elasticsearch 源码之启动流程分析
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .Net FrameWork总结
  • .NET 材料检测系统崩溃分析