设计模式实战-Minio服务存储图片
2023-02-22 本文已影响0人
CoderInsight
1,Minio简介
提供对象存储的服务,适合存储非机构化的数据,例如一些图片、视频、日志文件等。
2,Minio服务部署
- 1,从官网下载对应的文件;
- 2,修改权限,直接启动即可;
# 注意这里要切换成你自己的安装目录 nohup /home/install/minioSoft/minio server /home/install/minioSoft/data > /home/install/minioSoft/minio.log 2>&1 &
- 3,其内置了默认密码,也根据自己实际需求进行修改
#修改Minio的初始账号密码(也可以不修改) #初始账号:minioadmin #初始密码:minioadmin export MINIO_ROOT_USER=minio #注意密码至少八位 export MINIO_ROOT_PASSWORD=12345678
- 4,补充启动和关闭的脚本(
minioRestart.sh
)[root@nacos bin]# cat minioRestart.sh #!/bin/sh # flush Profile source /etc/profile case $1 in "start"){ nohup /home/install/minioSoft/minio server /home/install/minioSoft/data > /home/install/minioSoft/minio.log 2>&1 & echo "============Starting Minio===============" };; "stop"){ minioPIDS=$(ps ax | grep -i 'minio' | grep -v grep | awk '{print $1}') for pid in $minioPIDS do if [ -z "$pid" ]; then echo "No Minio server to stop" else kill -s TERM $pid fi done echo "============Stoped Minio===============" };; esac
3,Java代码的基础操作
在基本操作的演示基础上,增加了模板类的封装;
(1),MinioConfiguration
import io.minio.MinioClient;
import io.minio.errors.InvalidEndpointException;
import io.minio.errors.InvalidPortException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author wangyq
* @date 2022/4/19 18:10
* 将Minio的配置信息通过属性注入的方法交给springboot进行管理
*/
@Configuration
public class MinioConfiguration {
@Value("${minio.endpoint:http://192.168.73.156:9000}")
private String endPoint;
@Value("${minio.accessKey:minioadmin}")
private String accessKey;
@Value("${minio.secretKey:minioadmin}")
private String secretKey;
@Value("${minio.bucketName:test}")
public String bucketName;
/**
* @return 初始化minio操作的客户端
* @throws InvalidPortException 端口异常
* @throws InvalidEndpointException 连接地址异常
* @author wangyq
* @date 2023年2月22日 10:43:58
*/
@Bean
@ConditionalOnMissingBean({MinioClient.class})
public MinioClient minioClient() throws InvalidPortException, InvalidEndpointException {
return new MinioClient(this.endPoint, this.accessKey, this.secretKey);
}
/**
* @author wangyq
* @date 2022/4/19 18:11
* @return 初始化模版方法
*/
@Bean
@ConditionalOnBean({MinioClient.class})
@ConditionalOnMissingBean({MinioTemplate.class})
public MinioTemplate minioTemplate(final MinioClient minioClient) {
// 这里是直接new的对象,本质上是一样的
return new MinioTemplate(minioClient, this.endPoint, this.bucketName);
}
}
(2),MinioTemplate
import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.ServerSideEncryption;
import io.minio.messages.Bucket;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* @author wangyongqiang
* Minio 的操作模板类
*/
public class MinioTemplate {
/**minio连接地址*/
private final String endPoint;
/** 默认的桶名称*/
private final String defaultBucket;
/**minio客户端*/
private final MinioClient client;
public MinioTemplate(MinioClient client, String endPoint, String defaultBucket) {
this.endPoint = endPoint;
this.defaultBucket = defaultBucket;
this.client = client;
}
public void makeBucket(String bucketName) throws Exception {
if (!this.client.bucketExists(bucketName)) {
this.client.makeBucket(bucketName);
this.client.setBucketPolicy(bucketName, getPolicyType(bucketName, PolicyType.READ_WRITE));
}
}
public Bucket getBucket(String bucketName) throws Throwable{
try {
Optional<Bucket> bucketOptional = this.client.listBuckets().stream().filter((bucket) -> {
return bucket.name().equals(bucketName);
}).findFirst();
return (Bucket)bucketOptional.orElse((Bucket) null);
} catch (Throwable var3) {
throw var3;
}
}
public List<Bucket> listBuckets() throws Exception{
return this.client.listBuckets();
}
public void removeBucket(String bucketName) throws Exception{
try {
this.client.removeBucket(bucketName);
} catch (Throwable var3) {
throw var3;
}
}
public boolean bucketExists(String bucketName) throws Exception {
try {
return this.client.bucketExists(bucketName);
} catch (Throwable var3) {
throw var3;
}
}
public void copyFile(String bucketName, String fileName, String destBucketName) throws Exception{
try {
this.client.copyObject(bucketName, fileName, destBucketName);
} catch (Throwable var5) {
throw var5;
}
}
public void copyFile(String bucketName, String fileName, String destBucketName, String destFileName) throws Exception{
try {
this.client.copyObject(bucketName, fileName, destBucketName, destFileName);
} catch (Throwable var6) {
throw var6;
}
}
public MinioFile statFile(String fileName) throws Exception{
return this.statFile(this.defaultBucket, fileName);
}
/**
* @author wangyq
* @date 2022/4/19 15:38
* @Description 判断对象是否存在
*/
private MinioFile statFile(String bucketName, String fileName) throws Exception{
ObjectStat stat = this.client.statObject(bucketName, fileName);
MinioFile minioFile = new MinioFile();
minioFile.setName(StringUtils.isBlank(stat.name()) ? fileName : stat.name());
minioFile.setLink(this.fileLink(minioFile.getName()));
minioFile.setHash(String.valueOf(stat.hashCode()));
minioFile.setLength(stat.length());
minioFile.setPutTime(stat.createdTime());
minioFile.setContentType(stat.contentType());
return minioFile;
}
public String filePath(String fileName) {
return this.defaultBucket.concat("/").concat(fileName);
}
public String filePath(String bucketName, String fileName) {
return bucketName.concat("/").concat(fileName);
}
private String fileLink(String fileName) {
return this.endPoint.concat("/").concat(this.defaultBucket).concat("/").concat(fileName);
}
/**
* @author wangyq
* @date 2022/4/18 17:46
* @Description 获取图片的完整访问路径
*/
public String fileLink(String bucketName, String fileName) {
return this.endPoint.concat("/").concat(bucketName).concat("/").concat(fileName);
}
public MinioFile putFile(MultipartFile file) throws Exception{
try {
return this.putFile(this.defaultBucket, file.getOriginalFilename(), file);
} catch (Throwable var3) {
throw var3;
}
}
public MinioFile putFile(String fileName, MultipartFile file) throws Exception {
try {
return this.putFile(this.defaultBucket, fileName, file);
} catch (Throwable var4) {
throw var4;
}
}
public MinioFile putFile(String bucketName, String fileName, MultipartFile file) throws Exception{
return this.putFile(bucketName, fileName, file.getInputStream());
}
public MinioFile putFile(String fileName, InputStream stream) throws Exception {
return this.putFile(this.defaultBucket, fileName, stream);
}
public MinioFile putFile(String bucketName, String fileName, InputStream stream) throws Exception{
this.makeBucket(bucketName);
this.client.putObject(bucketName, fileName, stream, (long)stream.available(), (Map)null, (ServerSideEncryption)null, "application/octet-stream");
MinioFile file = new MinioFile();
file.setName(fileName);
file.setLink(this.fileLink(bucketName, fileName));
file.setPutTime(new Date());
return file;
}
public void removeFile(String fileName) throws Exception{
try {
this.removeFile(this.defaultBucket, fileName);
} catch (Throwable var3) {
throw var3;
}
}
public void removeFile(String bucketName, String fileName) throws Exception{
this.client.removeObject(bucketName, fileName);
}
public void removeFiles(String bucketName, List<String> fileNames) {
this.client.removeObjects(bucketName, fileNames);
}
/**
* @author wangyq
* @date 2022/4/18 16:01
* @Description 经过测试可以实现图片文件的下载
*/
public void downLoadFile(HttpServletResponse response, String bucketName, String fileName) throws Exception{
InputStream inputStream = this.client.getObject(StringUtils.isBlank(bucketName) ? this.defaultBucket : bucketName, fileName);
Throwable var5 = null;
try {
ServletOutputStream servletOutputStream = response.getOutputStream();
Throwable var7 = null;
try {
response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(fileName, "UTF-8"));
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/force-download");
response.setCharacterEncoding("UTF-8");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "No-cache");
response.setDateHeader("Expires", 0L);
IOUtils.copy(inputStream, servletOutputStream);
} catch (Throwable var32) {
var7 = var32;
throw var32;
} finally {
if (servletOutputStream != null) {
if (var7 != null) {
try {
servletOutputStream.close();
} catch (Throwable var31) {
var7.addSuppressed(var31);
}
} else {
servletOutputStream.close();
}
}
}
} catch (Throwable var34) {
var5 = var34;
throw var34;
} finally {
if (inputStream != null) {
if (var5 != null) {
try {
inputStream.close();
} catch (Throwable var30) {
var5.addSuppressed(var30);
}
} else {
inputStream.close();
}
}
}
}
public void downLoadFile(HttpServletResponse response, String fileName) throws Exception{
try {
this.downLoadFile(response, this.defaultBucket, fileName);
} catch (Throwable var4) {
throw var4;
}
}
public void showImage(HttpServletResponse response, String bucketName, String fileName) throws Exception{
InputStream inputStream = this.client.getObject(StringUtils.isBlank(bucketName) ? this.defaultBucket : bucketName, fileName);
Throwable var5 = null;
try {
ServletOutputStream servletOutputStream = response.getOutputStream();
Throwable var7 = null;
try {
String imageSuffix = fileName.substring(fileName.lastIndexOf(".") + 1);
response.setContentType("image/" + imageSuffix);
//int len = false;
byte[] buffer = new byte[10240];
int len;
while((len = inputStream.read(buffer)) != -1) {
servletOutputStream.write(buffer, 0, len);
}
servletOutputStream.flush();
} catch (Throwable var34) {
var7 = var34;
throw var34;
} finally {
if (servletOutputStream != null) {
if (var7 != null) {
try {
servletOutputStream.close();
} catch (Throwable var33) {
var7.addSuppressed(var33);
}
} else {
servletOutputStream.close();
}
}
}
} catch (Throwable var36) {
var5 = var36;
throw var36;
} finally {
if (inputStream != null) {
if (var5 != null) {
try {
inputStream.close();
} catch (Throwable var32) {
var5.addSuppressed(var32);
}
} else {
inputStream.close();
}
}
}
}
public void showImage(HttpServletResponse response, String fileName) throws Exception{
try {
this.showImage(response, this.defaultBucket, fileName);
} catch (Throwable var4) {
throw var4;
}
}
public String getUrl(String bucketName, String fileName) throws Exception{
try {
String url = this.client.getObjectUrl(StringUtils.isBlank(bucketName) ? this.defaultBucket : bucketName, fileName);
return url;
} catch (Throwable var4) {
throw var4;
}
}
public static String getPolicyType(String bucketName, PolicyType policyType) {
StringBuilder builder = new StringBuilder();
builder.append("{\n");
builder.append(" \"Statement\": [\n");
builder.append(" {\n");
builder.append(" \"Action\": [\n");
switch(policyType) {
case WRITE:
builder.append(" \"s3:GetBucketLocation\",\n");
builder.append(" \"s3:ListBucketMultipartUploads\"\n");
break;
case READ_WRITE:
builder.append(" \"s3:GetBucketLocation\",\n");
builder.append(" \"s3:ListBucket\",\n");
builder.append(" \"s3:ListBucketMultipartUploads\"\n");
break;
default:
builder.append(" \"s3:GetBucketLocation\"\n");
}
builder.append(" ],\n");
builder.append(" \"Effect\": \"Allow\",\n");
if (PolicyType.READ.equals(policyType)) {
builder.append(" {\n");
builder.append(" \"Action\": [\n");
builder.append(" \"s3:ListBucket\"\n");
builder.append(" ],\n");
builder.append(" \"Effect\": \"Deny\",\n");
}
builder.append(" \"Principal\": \"*\",\n");
builder.append(" \"Resource\": \"arn:aws:s3:::");
builder.append(bucketName);
builder.append("\"\n");
builder.append(" },\n");
builder.append(" {\n");
builder.append(" \"Action\": ");
switch(policyType) {
case WRITE:
builder.append("[\n");
builder.append(" \"s3:AbortMultipartUpload\",\n");
builder.append(" \"s3:DeleteObject\",\n");
builder.append(" \"s3:ListMultipartUploadParts\",\n");
builder.append(" \"s3:PutObject\"\n");
builder.append(" ],\n");
break;
case READ_WRITE:
builder.append("[\n");
builder.append(" \"s3:AbortMultipartUpload\",\n");
builder.append(" \"s3:DeleteObject\",\n");
builder.append(" \"s3:GetObject\",\n");
builder.append(" \"s3:ListMultipartUploadParts\",\n");
builder.append(" \"s3:PutObject\"\n");
builder.append(" ],\n");
break;
default:
builder.append("\"s3:GetObject\",\n");
}
builder.append(" \"Effect\": \"Allow\",\n");
builder.append(" \"Principal\": \"*\",\n");
builder.append(" \"Resource\": \"arn:aws:s3:::");
builder.append(bucketName);
builder.append("/*\"\n");
builder.append(" }\n");
builder.append(" ],\n");
builder.append(" \"Version\": \"2012-10-17\"\n");
builder.append("}\n");
return builder.toString();
}
}
(3),MinioFile
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
/**
* 控制返回的实体类信息
* @author wangyq
* @date 2022/4/19 10:55
*/
public class MinioFile {
private String link;
private String name;
public String hash;
private long length;
@JsonFormat(
pattern = "yyyy-MM-dd HH:mm:ss",
timezone = "GMT+8"
)
private Date putTime;
private String contentType;
public MinioFile() {
}
public String getLink() {
return this.link;
}
public String getName() {
return this.name;
}
public String getHash() {
return this.hash;
}
public long getLength() {
return this.length;
}
public Date getPutTime() {
return this.putTime;
}
public String getContentType() {
return this.contentType;
}
public void setLink(String link) {
this.link = link;
}
public void setName(String name) {
this.name = name;
}
public void setHash(String hash) {
this.hash = hash;
}
public void setLength(long length) {
this.length = length;
}
public void setPutTime(Date putTime) {
this.putTime = putTime;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof MinioFile)) {
return false;
} else {
MinioFile other = (MinioFile)o;
if (!other.canEqual(this)) {
return false;
} else {
label75: {
Object thisLink = this.getLink();
Object otherLink = other.getLink();
if (thisLink == null) {
if (otherLink == null) {
break label75;
}
} else if (thisLink.equals(otherLink)) {
break label75;
}
return false;
}
Object thisName = this.getName();
Object otherName = other.getName();
if (thisName == null) {
if (otherName != null) {
return false;
}
} else if (!thisName.equals(otherName)) {
return false;
}
Object thisHash = this.getHash();
Object otherHash = other.getHash();
if (thisHash == null) {
if (otherHash != null) {
return false;
}
} else if (!thisHash.equals(otherHash)) {
return false;
}
if (this.getLength() != other.getLength()) {
return false;
} else {
Object thisPutTime = this.getPutTime();
Object otherPutTime = other.getPutTime();
if (thisPutTime == null) {
if (otherPutTime != null) {
return false;
}
} else if (!thisPutTime.equals(otherPutTime)) {
return false;
}
Object thisContentType = this.getContentType();
Object otherContentType = other.getContentType();
if (thisContentType == null) {
return otherContentType == null;
} else {
return thisContentType.equals(otherContentType);
}
}
}
}
}
private boolean canEqual(Object other) {
return other instanceof MinioFile;
}
@Override
public int hashCode() {
int result = 17;
// 这里的hashCode的顺序是和equals方法里的顺序保持一致的
// String link;
Object link = this.getLink();
result = result * 31 + (link == null ? 43 : link.hashCode());
// String name;
Object name = this.getName();
result = result * 31 + (name == null ? 43 : name.hashCode());
// String hash;
Object hash = this.getHash();
result = result * 31 + (hash == null ? 43 : hash.hashCode());
// long length;
long length = this.getLength();
result = result * 31 + (int)(length >>> 32 ^ length);
// Date putTime;
Object putTime = this.getPutTime();
result = result * 31 + (putTime == null ? 43 : putTime.hashCode());
// String contentType;
Object contentType = this.getContentType();
result = result * 31 + (contentType == null ? 43 : contentType.hashCode());
return result;
}
@Override
public String toString() {
return "MinioFile(link=" + this.getLink() + ", name=" + this.getName() + ", hash=" + this.getHash() + ", length=" + this.getLength() + ", putTime=" + this.getPutTime() + ", contentType=" + this.getContentType() + ")";
}
}
(4),PolicyType
/**
* 文件上传权限控制枚举类
* @author wangyongqiang
*/
public enum PolicyType {
/**
* 文件上传的权限
* */
READ("read", "只读"),
WRITE("write", "只写"),
READ_WRITE("read_write", "读写");
private final String type;
private final String policy;
public String getType() {
return this.type;
}
public String getPolicy() {
return this.policy;
}
PolicyType(String type, String policy) {
this.type = type;
this.policy = policy;
}
}
(5),基础API简介
只列举个别api其他重载方法可以查看模版方法
- 0, 依赖注入
@Resource private MinioConfiguration minioConfiguration;
MinioTemplate minioTemplate = minioConfiguration.minioTemplate(minioConfiguration.minioClient());
- 1, 上传文件
minioTemplate.putFile(minioConfiguration.bucketName, minioObjectName, multipartFile);
- 2, 获取文件全路径
minioTemplate.fileLink(fileName);
- 3, 下载文件
minioTemplate.downLoadFile(response, fileName);
- 4, 展示图片
minioTemplate.showImage(response, fileName);
- 5, 获取文件详情对象
minioTemplate.statFile(fileName);