启动类
// minio
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Value("${minio.bucket}")
private String bucket;
@Bean
public RabbitMinio minio() throws Exception {
return new RabbitMinio(endpoint, accessKey, secretKey, bucket);
}
实现类
package com.huiren.common.minio;
import com.alibaba.fastjson.JSON;
import com.huiren.common.exception.RabbitMinioException;
import com.huiren.common.exception.RabbitMinioNotFoundException;
import com.huiren.common.exception.RabbitMinioParamException;
import com.huiren.common.utils.RabbitResponse;
import com.huiren.common.utils.RabbitResponseEnums;
import io.minio.*;
import io.minio.errors.ErrorResponseException;
import io.minio.http.Method;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;
import sun.misc.BASE64Encoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Slf4j
public class RabbitMinio {
// 桶名称WS3标准
private String bucket;
// minio客户端
private MinioClient client;
public MinioClient getClient() {
return this.client;
}
public RabbitMinio(String endpoint, String accessKey, String secretKey, String bucket) throws Exception {
// 创建客户端
this.client = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
log.info("MINIO服务器连接成功。[" + endpoint + "]");
// 检查桶是否存在,不存在创建桶
this.bucket = bucket;
boolean isExist = client.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
if (!isExist) {
client.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
log.info("桶创建成功。[" + bucket + "]");
} else {
log.info("桶已经存在。[" + bucket + "]");
}
}
/**
* 查询文件-递归查询
*
* @param request 前缀
* 业务ID
* 业务ID/文件类别
* @return 文件相对路径列表
*/
public List<String> listObjects(HttpServletRequest request) {
final String path = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
final String bestMatchingPattern = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)
.toString();
String prefix = new AntPathMatcher().extractPathWithinPattern(bestMatchingPattern, path);
try {
Iterable<Result<Item>> results = client
.listObjects(ListObjectsArgs.builder().bucket(bucket).prefix(prefix).recursive(true).build());
List<String> objects = new ArrayList<>();
for (Result<Item> result : results) {
Item item = result.get();
objects.add(URLDecoder.decode(item.objectName(), "utf-8"));
}
return objects;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 上传文件-UUID 非业务绑定
*
* @param path 层级目录 例子参照下方
* iamges
* tools
* @param file 文件
* @return UUID文件名
* @throws RabbitMinioException
*/
public String upload4Uuid(String path, MultipartFile file) throws RabbitMinioException {
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
StringBuilder filename = new StringBuilder();
if (!StringUtils.isEmpty(path)) {
if (!path.endsWith("/")) {
filename.append(path);
filename.append("/");
}
}
filename.append(UUID.randomUUID().toString().replace("-", ""));
filename.append(suffix);
this.upload(filename.toString(), file);
return filename.toString();
}
/**
* 上传文件-自定义名称
*
* @param path 层级目录 例子参照下方
* iamges
* tools
* @param file 文件
* @return UUID文件名
* @throws RabbitMinioException
*/
public String upload4Name(String path, MultipartFile file,String name) throws RabbitMinioException {
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
StringBuilder filename = new StringBuilder();
if (!StringUtils.isEmpty(path)) {
if (!path.endsWith("/")) {
filename.append(path);
filename.append("/");
}
}
filename.append(name);
filename.append(suffix);
this.upload(filename.toString(), file);
return filename.toString();
}
/**
* 上传文件-相对路径 业务绑定
*
* @param path 层级目录 例子参照下方
* 业务ID
* 业务ID/文件类别
* @param file 文件
* @return 文件相对路径 业务ID/文件类别/文件名
* @throws RabbitMinioException
*/
public String upload4Path(String path, MultipartFile file) throws RabbitMinioException, RabbitMinioParamException {
if (StringUtils.isEmpty(path)) {
throw new RabbitMinioParamException();
}
StringBuilder filename = new StringBuilder();
if (!path.endsWith("/")) {
filename.append(path);
filename.append("/");
}
int pos = file.getOriginalFilename().lastIndexOf(File.separator);
if (pos > 0) {
String realName = file.getOriginalFilename().substring(pos + 1);
filename.append(realName);
} else {
filename.append(file.getOriginalFilename());
}
this.upload(filename.toString().replaceAll(" ", ""), file);
return filename.toString();
}
/**
* 上传文件-相对路径 业务绑定
*
* @param path 层级目录 例子参照下方
* 业务ID
* 业务ID/文件类别
* @param file 文件
* @return 文件相对路径 业务ID/文件类别/文件名
* @throws RabbitMinioException
*/
public String upload4WPS(String path, MultipartFile file) throws RabbitMinioException, RabbitMinioParamException {
if (StringUtils.isEmpty(path)) {
throw new RabbitMinioParamException();
}
StringBuilder filename = new StringBuilder();
if (!path.endsWith("/")) {
filename.append(path);
filename.append("/");
}
filename.append(file.getOriginalFilename());
this.upload(filename.toString(), file);
return filename.toString();
}
/**
* 上传文件 业务绑定
*
* @param object 文件名称
* @param file 文件
* @return 文件相对路径 业务ID/文件类别/文件名
* @throws RabbitMinioException
*/
public String upload(String object, MultipartFile file) throws RabbitMinioException {
try {
// 获取文件类型
String contentType = file.getContentType();
// 获取文件流
InputStream ips = file.getInputStream();
// 上传文件
client.putObject(
PutObjectArgs.builder().bucket(bucket).object(object).stream(ips, -1, 5 * 1024 * 1024 * 1024L)
.contentType(contentType).build());
return object;
} catch (Exception e) {
e.printStackTrace();
throw new RabbitMinioException();
}
}
/**
* 下载文件-支持分块下载和断点续
*
* @param object 业务ID/文件类别/文件名
* @return 文件流
* @throws RabbitMinioException
*/
public void download(HttpServletRequest request, HttpServletResponse response, String object) throws IOException {
downloadTotal(request, response, object);
}
/**
* 下载文件-支持分块下载和断点续
*
* @return 文件流
* @throws RabbitMinioException
*/
public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
final String path = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
final String bestMatchingPattern = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)
.toString();
String object = new AntPathMatcher().extractPathWithinPattern(bestMatchingPattern, path);
downloadTotal(request, response, object);
}
/**
* 载文件-一次性下载
*
* @param response
* @param object
*/
private void downloadTotal(HttpServletRequest request, HttpServletResponse response, String object)
throws IOException {
try {
ObjectStat stat = client.statObject(StatObjectArgs.builder().bucket(bucket).object(object).build());
long length = stat.length();
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Length", Long.toString(length));
String filename = stat.name().substring(stat.name().lastIndexOf("/") + 1);
String clientFileName = "";
String header = request.getHeader("User-Agent");
// 火狐浏览器,使用Base64Encoder类进行编码
if (header.contains("Firefox")) {
BASE64Encoder base = new BASE64Encoder();
clientFileName =
"=?utf-8?B?" + base.encode(filename.getBytes("utf-8")).replaceAll("\r|\n", "") + "?=";
} else {
clientFileName = URLEncoder.encode(filename, "utf-8");
}
response.setHeader("Content-Disposition", "attachment;filename=" + clientFileName);
InputStream stream = client.getObject(GetObjectArgs.builder().bucket(bucket).object(object).build());
FileCopyUtils.copy(stream, response.getOutputStream());
stream.close();
} catch (Exception e) {
RabbitResponse responseBody;
if (e instanceof ErrorResponseException) {
responseBody = new RabbitResponse(RabbitResponseEnums.MINIO_FILE_NOTFOUND_ERROR);
} else {
responseBody = new RabbitResponse(RabbitResponseEnums.MINIO_FILE_DOWNLOAD_ERROR);
}
response.setHeader("Content-type", "application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(responseBody));
}
}
/**
* 载文件-支持分块下载和断点续
*
* @param response
* @param object
*/
private void downloadBreakpoint(HttpServletRequest request, HttpServletResponse response, String object)
throws IOException {
try {
ObjectStat stat = client.statObject(StatObjectArgs.builder().bucket(bucket).object(object).build());
long residue = stat.length();
long offset = 0;
response.reset();
response.setHeader("Accept-Ranges", "byte");
//断点续传的信息就存储在这个Header属性里面: range:bytes=3-100;200 (从3开始,读取长度为100,总长度为200)
String range = request.getHeader("Range");
if (range != null) {
// SC_PARTIAL_CONTENT 206 表示服务器已经成功处理了部分 GET 请求。
// 类似于 FlashGet 或者迅雷这类的 HTTP下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
range = range.substring("bytes=".length());
String[] rangeInfo = range.split("-");
offset = new Long(rangeInfo[0]);
if (offset > stat.length()) {
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return;
}
if (rangeInfo.length > 1) {
residue = Long.parseLong(rangeInfo[1]) - offset + 1;
} else {
residue = residue - offset;
}
if (residue + offset > stat.length()) {
residue = stat.length() - offset;
}
}
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Length", Long.toString(residue));
if (range != null) {
response.setHeader("Content-Range",
"bytes " + offset + "-" + (offset + residue - 1) + "/" + stat.length());
}
String header = request.getHeader("User-Agent");
String clientFileName = "";
// 火狐浏览器,使用Base64Encoder类进行编码
if (header.contains("Firefox")) {
BASE64Encoder base = new BASE64Encoder();
clientFileName =
"=?utf-8?B?" + base.encode(stat.name().getBytes("utf-8")).replaceAll("\r|\n", "") + "?=";
} else {
clientFileName = URLEncoder.encode(stat.name(), "utf-8");
}
response.setHeader("Content-Disposition", "attachment;filename=" + clientFileName);
// 一次读取2M
long buffer = 2 * 1024 * 1024L;
long length = Math.min(residue, buffer);
if (length < buffer) {
InputStream stream = client.getObject(
GetObjectArgs.builder().bucket(bucket).object(object).offset(offset).length(length).build());
FileCopyUtils.copy(stream, response.getOutputStream());
stream.close();
} else {
while (length > 0) {
InputStream stream = client.getObject(
GetObjectArgs.builder().bucket(bucket).object(object).offset(offset).length(length)
.build());
FileCopyUtils.copy(stream, response.getOutputStream());
stream.close();
offset += length;
residue -= length;
length = Math.min(residue, buffer);
}
}
} catch (Exception e) {
RabbitResponse responseBody;
if (e instanceof ErrorResponseException) {
responseBody = new RabbitResponse(RabbitResponseEnums.MINIO_FILE_NOTFOUND_ERROR);
} else {
responseBody = new RabbitResponse(RabbitResponseEnums.MINIO_FILE_DOWNLOAD_ERROR);
}
response.setHeader("Content-type", "application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(responseBody));
}
}
/**
* 文件下载链接 有效期默认7天
*
* @param request HttpServletRequest
* @return 下载链接URL
* @throws RabbitMinioException
*/
public String getDownloadUrl(HttpServletRequest request) throws RabbitMinioException, RabbitMinioNotFoundException {
final String path = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
final String bestMatchingPattern = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)
.toString();
String object = new AntPathMatcher().extractPathWithinPattern(bestMatchingPattern, path);
try {
// 判断对象是否存在
client.statObject(StatObjectArgs.builder().bucket(bucket).object(object).build());
return client.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder().bucket(bucket).object(object).method(Method.GET).build());
} catch (Exception e) {
if (e instanceof ErrorResponseException) {
throw new RabbitMinioNotFoundException();
} else {
e.printStackTrace();
throw new RabbitMinioException();
}
}
}
/**
* 删除文件
*
* @param request HttpServletRequest
* @throws RabbitMinioException
*/
public void remove(HttpServletRequest request) {
final String path = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
final String bestMatchingPattern = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)
.toString();
String object = new AntPathMatcher().extractPathWithinPattern(bestMatchingPattern, path);
List<String> deleteObjects = new ArrayList<>();
deleteObjects.add(object);
try {
// 判断对象是否存在
client.statObject(StatObjectArgs.builder().bucket(bucket).object(object).build());
} catch (Exception e) {
// 按照前缀查找对象
deleteObjects = listObjects(request);
}
try {
// 删除
for (String deleteObject : deleteObjects) {
client.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(deleteObject).build());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除文件
*
* @param param 前缀
* 业务ID
* 业务ID/文件类别
* @throws RabbitMinioException
*/
public void remove(String param) {
List<String> deleteObjects = new ArrayList<>();
deleteObjects.add(param);
try {
// 判断对象是否存在
client.statObject(StatObjectArgs.builder().bucket(bucket).object(param).build());
} catch (Exception e) {
// 按照前缀查找对象
Iterable<Result<Item>> results = client
.listObjects(ListObjectsArgs.builder().bucket(bucket).prefix(param).recursive(true).build());
List<String> objects = new ArrayList<>();
for (Result<Item> result : results) {
Item item = null;
try {
item = result.get();
objects.add(URLDecoder.decode(item.objectName(), "utf-8"));
} catch (Exception exception) {
e.printStackTrace();
}
}
deleteObjects = objects;
}
try {
// 删除
for (String deleteObject : deleteObjects) {
client.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(deleteObject).build());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* weboffice 取得文件流
*
* @return 文件相对路径列表
*/
public InputStream getObject(String object) {
try {
return client.getObject(GetObjectArgs.builder().bucket(bucket).object(object).build());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* weboffice 上传文件
*
* @param object 文件名称
* @param inputStream 文件流
* @return 文件相对路径 业务ID/文件类别/文件名
* @throws RabbitMinioException
*/
public void putObject(String object, InputStream inputStream) {
try {
client.putObject(PutObjectArgs.builder().bucket(bucket).object(object)
.stream(inputStream, -1, 5 * 1024 * 1024 * 1024L).build());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 下载链接 -默认
*
* @param object 文件名称
* @param expiry 过期时间(秒)
* @return
*/
public String getPresignedObjectUrl(String object, int expiry) {
try {
// 判断对象是否存在
client.statObject(StatObjectArgs.builder().bucket(bucket).object(object).build());
return client.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder().bucket(bucket).object(object).expiry(expiry).method(Method.GET)
.build());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 查询文件-递归查询
*
* @param prefix 前缀
* 业务ID
* 业务ID/文件类别
* @return 文件相对路径列表
*/
public List<String> listObjects(String prefix) {
try {
Iterable<Result<Item>> results = client
.listObjects(ListObjectsArgs.builder().bucket(bucket).prefix(prefix).recursive(true).build());
List<String> objects = new ArrayList<>();
for (Result<Item> result : results) {
Item item = result.get();
objects.add(URLDecoder.decode(item.objectName(), "utf-8"));
}
return objects;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
调用方法
package com.huiren.core.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huiren.common.component.WechatComponent;
import com.huiren.common.exception.RabbitMinioException;
import com.huiren.common.minio.RabbitMinio;
import com.huiren.core.entity.SysQr;
import com.huiren.core.service.SysQrService;
import com.huiren.core.mapper.SysQrMapper;
import com.huiren.core.vo.QrVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.concurrent.atomic.AtomicReference;
public class MinioTest {
@Autowired
private RabbitMinio minio;
@Override
public boolean delete(Long id) {
minio.remove("qr/"+id.toString());
return true;
}
}