MinIO 是一款高性能、分布式的对象存储系统,Minio是基于Go语言编写的对象存储服务,适合于存储大容量非结构化的数据,例如图片、音频、视频、备份数据等,传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。
导入minio依赖包
io.minio minio8.0.3
application.yml配置文件
minio: #注意此处是https,由于后续讨论协议问题因此提前修改,不需要的可自行修改为http endpoint: 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 { @Autowired private MinioInfo minioInfo; /** * 获取 MinioClient */ @Bean public 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 @Component public class MinioUtils { @Autowired private MinioClient minioClient; @Autowired private 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(); } } } @SneakyThrows public 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) @ResponseBody public 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") @ResponseBody public 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,开始集成是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 { @Autowired private MinioInfo minioInfo; /** * 获取 MinioClient * 取消ssl认证 */ @Bean public 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() { @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { } @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { } @Override public 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(); } }