MinIO 是一款高性能、分布式的对象存储系统,Minio是基于Go语言编写的对象存储服务,适合于存储大容量非结构化的数据,例如图片、音频、视频、备份数据等传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。

一、配置

导入minio依赖包

io.miniominio8.0.3

application.yml配置文件

minio:#注意此处是https,由于后续讨论协议问题因此提前修改,不需要的可自行修改为httpendpoint: https://xxx.xxx.xx:9002 accesskey: minioadmin#你的服务账号secretkey: minioadmin#你的服务密码

配置MinioInfo文件

@Data@Component@ConfigurationProperties(prefix = "minio")public class MinioInfo {private String endpoint;private String accesskey;private String secretkey;}

配置MinioConfig文件

@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(); }}

二、上传、下载、删除文件

MinioUtils类

import io.minio.*;import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.net.URLEncoder;/** * @author: MM * @date: 2023-03-09 10:09 */@Slf4j@Componentpublic class MinioUtils {@Autowiredprivate MinioClient minioClient;@Autowiredprivate MinioInfo minioInfo;/** * 上传文件 * @param file * @param bucketName * @return * @throws Exception */public String uploadFile(MultipartFile file,String bucketName){if (null==file || 0 == file.getSize()){log.error("msg","上传文件不能为空");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("上传失败:{}",e.getMessage());}log.error("msg","上传失败");return null;} /** * 通过字节流上传 * @param imageFullPath * @param bucketName * @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("上传失败:{}",e.getMessage());}log.error("msg","上传失败");return null;}/** * 删除文件 * @param bucketName * @param fileName * @return */public int 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) {System.out.println("删除文件失败");e.printStackTrace();return 1;}System.out.println("删除文件成功");return 0;}/** * 下载文件 * @param fileName * @param bucketName * @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());}}}

接下来创建个Controller使用就行了

上传

/** * 上传文件 * @param file * @return */@PostMapping(value = "/v1/minio/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)@ResponseBodypublic JSONObject uploadByMinio(@RequestParam(name = "file")MultipartFile file) {JSONObject jso = new JSONObject();//返回存储路径String path = minioUtils.uploadFile(file, "musicearphone");jso.put("code", 2000);jso.put("data", path);return jso;}

下载

/** * 下载文件 根据文件名 * @param fileName * @param response */@GetMapping("/v1/get/download")public void download(@RequestParam(name = "fileName") String fileName, HttpServletResponse response){try {minioUtils.fileDownload(fileName,"musicearphone",response);}catch (Exception e){e.printStackTrace();}}

删除

/** * 通过文件名删除文件 * @param fileName * @return */@PostMapping("/v1/minio/delete")@ResponseBodypublic JSONObject deleteByName(String fileName){JSONObject jso = new JSONObject();int res = minioUtils.removeFile("musicearphone", fileName);if (res!=0){jso.put("code",5000);jso.put("msg","删除失败");}jso.put("code",2000);jso.put("msg","删除成功");return jso;}

三、支持https访问

由于公司项目的原因,项目访问的方式是https,开始集成是minio服务器是http,在之前文章把minio开启了https。

文章链接: https://blog.csdn.net/weixin_53799443/article/details/129335521

但在使用minio https服务的过程中发现文件上传报错了

出现了以下的错误

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

问题原因

源应用程序不信任目标应用程序的证书,因为在源应用程序的JVM信任库中找不到该证书或证书链(简单来说minio服务不信任的证书问题导致)

解决办法

通过java代码取消ssl认证,更新MinioConfig文件

import io.minio.MinioClient;import okhttp3.OkHttpClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.net.ssl.*;import java.security.KeyManagementException;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.security.cert.X509Certificate;/** * @author: MM * @date: 2023-03-09 10:05 */@Configuration@EnableConfigurationProperties(MinioInfo.class)public class MinioConfig {@Autowiredprivate MinioInfo minioInfo;/** * 获取 MinioClient * 取消ssl认证 */@Beanpublic MinioClient minioClient() throws NoSuchAlgorithmException, KeyManagementException {//return MinioClient.builder().endpoint(minioInfo.getEndpoint())//.credentials(minioInfo.getAccesskey(),minioInfo.getSecretkey())//.build();//取消ssl认证final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {@Overridepublic void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}@Overridepublic void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};}}};X509TrustManager x509TrustManager = (X509TrustManager) trustAllCerts[0];final SSLContext sslContext = SSLContext.getInstance("SSL");sslContext.init(null, trustAllCerts, new SecureRandom());final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();OkHttpClient.Builder builder = new OkHttpClient.Builder();builder.sslSocketFactory(sslSocketFactory,x509TrustManager);builder.hostnameVerifier((s, sslSession) -> true);OkHttpClient okHttpClient = builder.build();return MinioClient.builder().endpoint(minioInfo.getEndpoint()).httpClient(okHttpClient).region("eu-west-1").credentials(minioInfo.getAccesskey(), minioInfo.getSecretkey()).build();}}