MinIO es un sistema de almacenamiento de objetos distribuido de alto rendimiento. Minio es un servicio de almacenamiento de objetos escrito en lenguaje Go. Es adecuado para almacenar datos no estructurados de gran capacidad, como imágenes, audio, video, datos de respaldo, etc. Almacenamiento de objetos tradicional Excelente rendimiento en casos de uso como almacenamiento secundario, recuperación ante desastres y archivado.
1. Configuración
Importar paquete de dependencia minio
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.0.3</version>
</dependency>
archivo de configuración application.yml
minio:
#注意此处是https,由于后续讨论协议问题因此提前修改,不需要的可自行修改为http
endpoint: https://xxx.xxx.xx:9002
accesskey: minioadmin #你的服务账号
secretkey: minioadmin #你的服务密码
Configurar el archivo MinioInfo
@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioInfo {
private String endpoint;
private String accesskey;
private String secretkey;
}
Configurar el archivo 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();
}
}
2. Cargar, descargar y eliminar archivos
Clase 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());
}
}
}
A continuación, simplemente cree un controlador y úselo.
subir
/**
* 上传文件
* @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;
}
descargar
/**
* 下载文件 根据文件名
* @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();
}
}
borrar
/**
* 通过文件名删除文件
* @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;
}
3. Admite acceso https
Debido al proyecto de la empresa, el método de acceso al proyecto es https. El servidor minio es http cuando se integra al principio. En el artículo anterior, minio activó https.
Enlace del artículo: https://blog.csdn.net/weixin_53799443/article/details/129335521
Pero en el proceso de utilizar el servicio minio https, descubrí que se informó el error de carga del archivo.
El siguiente error ha ocurrido
sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
causas del problema
La aplicación de origen no confía en el certificado de la aplicación de destino porque el certificado o la cadena de certificados no se encuentra en el almacén de confianza JVM de la aplicación de origen (en pocas palabras, el servicio minio no confía en la emisión del certificado)
Solución
Cancele la autenticación SSL mediante código Java y actualice el archivo 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();
}
}