一、Docker 安装 MinIO 部署
1.官方链接
2. 拉取镜像
| docker pull minio/minio:latest |
3. 创建挂载目录
| mkdir -p /mydata/minio/{data,config} |
4. 创建和启动容器
| docker run -d \ |
| --restart always \ |
| -p 9800:9800 \ |
| -p 9801:9801 \ |
| --name minio \ |
| -v /mydata/minio/data:/data \ |
| -v /mydata/minio/config:/root/.minio \ |
| -e "MINIO_ROOT_USER=<设置账户名称>" \ |
| -e "MINIO_ROOT_PASSWORD=<设置账号密码>" \ |
| minio/minio server /data --console-address ":9001" |
- -e "MINIO_ROOT_USER=<设置账户名称>" : MinIO控制台用户名
- -e "MINIO_ROOT_PASSWORD=<设置账号密码>" :MinIO控制台密码
5. 访问MinIO控制台
控制台地址: http://192.168.10.100:9001(opens new window)
用户名/密码: minioadmin/minioadmin

6.设置开机启动
| docker restart minio |
| |
| docker update minio --restart=always |
二、创建 spring-minio 服务
1. pom.xml相关依赖
- spring-boot版本 2.7.14
- spring-cloud版本 2021.0.8
- spring-cloud-alibaba版本 2021.1
- knife4j版本 4.1.0
| |
| <dependency> |
| <groupId>io.minio</groupId> |
| <artifactId>minio</artifactId> |
| <version>8.5.5</version> |
| </dependency> |
| |
| |
| <dependency> |
| <groupId>me.tongfei</groupId> |
| <artifactId>progressbar</artifactId> |
| <version>0.9.5</version> |
| </dependency> |
| |
| |
| <dependency> |
| <groupId>com.squareup.okhttp3</groupId> |
| <artifactId>okhttp</artifactId> |
| <version>4.10.0</version> |
| </dependency> |
| |
| |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-configuration-processor</artifactId> |
| </dependency> |
2.在 config 包下面创建 minio 的 client
- 创建引用yml的配置, MinioProperties 的 class 文件
| @Data |
| @Component |
| @ConfigurationProperties(prefix = "minio") |
| public class MinioProperties { |
| |
| @ApiModelProperty("端点") |
| private String endpoint; |
| |
| @ApiModelProperty("访问秘钥key") |
| private String accessKey; |
| |
| @ApiModelProperty("秘密密钥key") |
| private String secretKey; |
| } |
- 创建 MinioConfiguration 的 class文件,引用在yml文件中配置的依赖
| @Configuration |
| public class MinioConfiguration { |
| |
| private @Resource MinioProperties properties; |
| |
| @Bean |
| public MinioClient minioClient() { |
| |
| return MinioClient.builder().endpoint(properties.getEndpoint()) |
| .credentials(properties.getAccessKey(), properties.getSecretKey()) |
| .build(); |
| } |
| } |
3.在 common 包下面创建响应体等公共依赖
| @Data |
| @ApiModel("查询时,返回上传的文件路径与是否为目录") |
| public class Fileinfo { |
| |
| |
| |
| |
| private String filename; |
| |
| |
| |
| |
| private Boolean directory; |
| |
| } |
| @Data |
| public class Res<T> implements Serializable { |
| |
| private String code; |
| |
| private T data; |
| |
| private String msg; |
| |
| } |
4.编写相关的 Impl 创建实现方法
| private @Resource MinioProperties properties; |
| |
| private @Resource MinioClient minioClient; |
| |
| @Value("${minio.bucketName}") |
| private String bucketName; |
| |
| @Value("${minio.groupName}") |
| private String groupName; |
| |
| |
| |
| |
| |
| @Override |
| public List<Object> listItem() { |
| |
| Iterable<Result<Item>> myObjects = minioClient.listObjects(ListObjectsArgs.builder() |
| .bucket(bucketName).recursive(true) |
| .build()); |
| |
| List<Object> infos = new ArrayList<>(); |
| for (Result<Item> r : myObjects) { |
| Fileinfo info = new Fileinfo(); |
| try { |
| Item item = r.get(); |
| info.setFilename(item.objectName()); |
| info.setDirectory(item.isDir()); |
| |
| infos.add(info); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| return infos; |
| } |
| |
| |
| |
| |
| |
| @Override |
| public Res upload(MultipartFile[] file) { |
| |
| if (file == null || 0 == file.length ) { |
| return Res.failed("上传文件不能为空"); |
| } |
| |
| List<String> list = new ArrayList<>(file.length); |
| |
| for (MultipartFile multipartFile : file) { |
| |
| String originalFilename = multipartFile.getOriginalFilename(); |
| |
| try { |
| |
| |
| InputStream in = multipartFile.getInputStream(); |
| |
| String dateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); |
| |
| String newName = groupName + "/" + dateTime + "/" +UUID.randomUUID().toString().replaceAll("-", "") |
| + originalFilename.substring(originalFilename.lastIndexOf(".")); |
| |
| minioClient.putObject( |
| PutObjectArgs.builder().bucket(bucketName).object(newName) |
| |
| .stream( |
| in, multipartFile.getSize(), -1) |
| .contentType(multipartFile.getContentType()) |
| .build()); |
| in.close(); |
| // 生成uri路径 |
| String uri = properties.getEndpoint() + "/" + bucketName + "/" + newName; |
| list.add(uri); |
| |
| } catch (Exception e) { |
| log.error(e.getMessage()); |
| return Res.failed("上传失败"); |
| } |
| } |
| |
| Map<String, Object> map = new HashMap<>(); |
| map.put("bucketName", bucketName ); |
| map.put("fileName", list); |
| |
| return Res.success(map); |
| |
| } |
| |
| |
| |
| |
| |
| @Override |
| public void downloadFileName(HttpServletResponse response, String fileName) { |
| |
| InputStream in = null; |
| |
| try { |
| StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build()); |
| |
| response.setContentType(stat.contentType()); |
| response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); |
| |
| |
| in = minioClient.getObject( |
| GetObjectArgs.builder() |
| .bucket(bucketName) |
| .object(fileName) |
| .build()); |
| IOUtils.copy(in, response.getOutputStream()); |
| |
| } catch (Exception e) { |
| |
| log.error(e.getMessage()); |
| |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| log.error(e.getMessage()); |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| @Override |
| public Res delFileName(String fileName) { |
| try { |
| minioClient.removeObject( |
| RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build()); |
| } catch (Exception e) { |
| log.error(e.getMessage()); |
| return Res.failed("删除失败"); |
| } |
| return Res.success("删除成功"); |
| |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了