minio部署启用
参考官方,根据不同的操作系统,按照步骤部署
minio官网地址https://www.minio.org.cn/docs/minio/windows/index.html
minio权限添加
minio权限添加https://blog.csdn.net/xnian_/article/details/130841657
安装最小IO服务器
从以下 URL 下载 MinIO 可执行文件:cmd 复制下面的下载
https://dl.min.io/server/minio/release/windows-amd64/minio.exe
下一步包括运行可执行文件的说明。 不能从资源管理器或通过双击文件来运行可执行文件。 相反,您调用可执行文件来启动服务器。
启动
在 PowerShell 或命令提示符下,导航到可执行文件的位置或将文件的路径添加到系统。minio.exe
$PATH
使用此命令在文件夹中启动本地 MinIO 实例。 您可以替换为本地计算机上的另一个驱动器或文件夹路径。d:\minio
d:\minio (自己下载的目录)
.\minio.exe server d:\minio --console-address :9090
该过程将其输出打印到系统控制台,类似于以下内容:
初始的登录账号:
RootUser: minioadmin
RootPass: minioadmin
API: http://192.0.2.10:9000 http://127.0.0.1:9000
RootUser: minioadmin
RootPass: minioadmin
Console: http://192.0.2.10:9090 http://127.0.0.1:9090
RootUser: minioadmin
RootPass: minioadmin
Command-line: https://min.io/docs/minio/linux/reference/minio-mc.html
$ mc alias set myminio http://192.0.2.10:9000 minioadmin minioadmin
Documentation: https://min.io/docs/minio/linux/index.html
WARNING: Detected default credentials 'minioadmin:minioadmin', we recommend tha
创建自己的minio目录
mkdir minio
1远程拉取:
wget https://dl.min.io/server/minio/release/linux-amd64/minio
安装minio
2 文件赋权
给minio二进制文件赋权限,否则无法执行:
chmod +x minio
3启动minio
MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin nohup ./minio server --console-address ":9000" --address ":9001" /data/ > /minio.log 2>&1 &
或
./minio server --console-address ":9000" --address ":9001" /data/ > ./minio.log 2>&1 &
浏览器访问服务器minio,地址ip:9000,默认账号minioadmin 密码minioadmin
需要关闭防火墙linux防火墙操作命令https://blog.csdn.net/xnian_/article/details/130847602
pom.xm
io.minio
minio
7.1.0
配置文件.yml
minio:
access-key: minio用户名
secret-key: minio密码
bucket-name: 桶名
endpoint: minio地址
1. controller
package com.setsail.setsailcusserver.controller;
import com.alibaba.fastjson.JSONObject;
import com.setsail.setsailcusserver.entity.UserLoginAccEntity;
import com.setsail.setsailcusserver.service.UserRegisService;
import com.setsail.setsailcusserver.uatils.MinioUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.annotation.sql.DataSourceDefinition;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Result;
import java.util.List;
/**
* @Description:
* @Title: UserRegisController
* @Author hello
* @Date: 2023/4/10 9:49
* @Version 1.0
*/
@Slf4j
@RestController
@RequestMapping("/regis")
public class UserRegisController {
@Resource
private UserRegisService userRegisService;
@Resource
private MinioUtils minioUtils;
/**
* 上传
* @param multipart
* @throws Exception
*/
@RequestMapping("uploadFile")
public void uploadFile(@RequestBody JSONObject multipart) throws Exception{
minioUtils.uploadFile(multipart);
}
/**
* 删除
* @param fileName
* @throws Exception
*/
@GetMapping("deleteObject")
public void deleteObject(@RequestParam String fileName) throws Exception{
minioUtils.deleteObject(fileName);
}
/**
* 下载
* reakFileName 需要带后缀名
* @param response
* @throws Exception
*/
@GetMapping("downLoad")
public void downLoad(HttpServletRequest request, HttpServletResponse response) throws Exception{
minioUtils.downLoad("file_7355b51d-2a1a-4fc9-83b2-f6066dfd329d.png","cccc.jpg",response,request);
}
/**
* 下载图片
* reakFileName 需要带后缀名
* @param response
* @throws Exception
*/
@GetMapping("downloadImg")
public void downloadImg( HttpServletResponse response) throws Exception{
minioUtils.downloadImg("file_7355b51d-2a1a-4fc9-83b2-f6066dfd329d.png","imggsss.jpg",response);
}
/**
*查看图片
* @param response
* @throws Exception
*/
@GetMapping("getImage")
public void getImage( HttpServletResponse response) throws Exception{
minioUtils.getImage("file_7355b51d-2a1a-4fc9-83b2-f6066dfd329d.png",response);
}
/**
* 获取权限策略
* @param
* @throws Exception
*/
@GetMapping("getStrategy")
public void getStrategy() throws Exception{
minioUtils.getStrategy();
}
}
2.MinioConfig
package com.setsail.setsailcusserver.config;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description:
* @Title: MinioConfig
* @Author hello
* @Date: 2023/5/23 15:42
* @Version 1.0
*/
@Configuration
public class MinioConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.access-key}")
private String accesskey;
@Value("${minio.secret-key}")
private String secretKey;
@Bean
public MinioClient minioClient(){
MinioClient minioClient = MinioClient.builder().endpoint(endpoint).
credentials(accesskey, secretKey).region("china").build();
return minioClient;
}
}
3.MinioUtils工具类
package com.setsail.setsailcusserver.uatils;
/**
* @Description:
* @Title: MinioUtil
* @Author hello
* @Date: 2023/5/23 15:41
* @Version 1.0
*/
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.util.UuidUtils;
import com.setsail.setsailcusserver.config.MinioConfig;
import io.minio.*;
import io.minio.errors.MinioException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import sun.nio.ch.IOUtil;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* @Author smallhou
* @Date 2022-08-15 14:31
* @Version V1.0
*/
@Slf4j
@Component
public class MinioUtils {
@Autowired
private MinioClient minioClient;
@Value("${minio.bucket-name}")
private String bucketName="file";
/**
* @Author smallhou
* @Description //TODO 判断桶存在不存在,不存在创建桶
* @Date 10:49 2022-08-16
* @Param [bucketName]
* @return void
**/
@SneakyThrows
public void createBucket(String bucketName) {
if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
@SneakyThrows
public InputStream getObjectInputStream(String objectName,String bucketName){
GetObjectArgs getObjectArgs = GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build();
return minioClient.getObject(getObjectArgs);
}
public JSONObject uploadFile(JSONObject fileObj) throws Exception {
JSONObject res = new JSONObject();
res.put("code", 0);
// 判断上传文件是否为空
if (null == fileObj ) {
res.put("msg", "上传文件不能为空");
return res;
}
InputStream is=null;
try {
// 判断存储桶是否存在
createBucket(bucketName);
// 文件名
String originalFilename = fileObj.getString("originalFilename");
// 新的文件名 = 存储桶名称_时间戳.后缀名
String fileName = bucketName + "_" + UuidUtils.generateUuid() + originalFilename.substring(originalFilename.lastIndexOf("."));
// 开始上传 文件的绝对路径
is=new FileInputStream(fileObj.getString("inputStream"));
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.contentType(fileObj.getString("contentType"))
.stream(is, is.available(), -1)
.build();
this.minioClient.putObject(putObjectArgs);
res.put("code", 1);
res.put("msg", bucketName + "/" + fileName);
res.put("bucket", bucketName);
res.put("fileName", fileName);
return res;
} catch (Exception e) {
e.printStackTrace();
log.error("上传文件失败:{}", e.getMessage());
}finally {
is.close();
}
res.put("msg", "上传失败");
return res;
}
public void downLoad(String fileName,String realFileName, HttpServletResponse response, HttpServletRequest request) {
InputStream is=null;
OutputStream os =null;
try {
is=getObjectInputStream(fileName,bucketName);
if(is!=null){
byte buf[] = new byte[1024];
int length = 0;
String codedfilename = "";
String agent = request.getHeader("USER-AGENT");
System.out.println("agent:" + agent);
if ((null != agent && -1 != agent.indexOf("MSIE")) || (null != agent && -1 != agent.indexOf("Trident"))) {
String name = URLEncoder.encode(realFileName, "UTF8");
codedfilename = name;
} else if (null != agent && -1 != agent.indexOf("Mozilla")) {
codedfilename = new String(realFileName.getBytes("UTF-8"), "iso-8859-1");
} else {
codedfilename = new String(realFileName.getBytes("UTF-8"), "iso-8859-1");
}
response.reset();
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(realFileName.substring(realFileName.lastIndexOf("/") + 1), "UTF-8"));
response.setContentType("application/x-msdownload");
response.setCharacterEncoding("UTF-8");
os = response.getOutputStream();
// 输出文件
while ((length = is.read(buf)) > 0) {
os.write(buf, 0, length);
}
// 关闭输出流
os.close();
}else{
log.error("下载失败");
}
}catch (Exception e){
e.printStackTrace();
log.error("错误:"+e.getMessage());
}finally {
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void downloadImg(String filename,String realFileName, HttpServletResponse httpResponse) {
try{
//imgBucket--桶名称 filename-- 图片名称
InputStream files = minioClient.getObject(bucketName, filename);
InputStream ism = new BufferedInputStream(files);
// 调用statObject()来判断对象是否存在。
// 如果不存在, statObject()抛出异常,
// 否则则代表对象存在
minioClient.statObject(bucketName, filename);
byte buf[] = new byte[1024];
int length = 0;
httpResponse.reset();
//Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。
// Content-disposition其实可以控制用户请求所得的内容存为一个文件的时候提供一个默认的文件名,
// 文件直接在浏览器上显示或者在访问时弹出文件下载对话框。
httpResponse.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(realFileName, "UTF-8"));
httpResponse.setContentType("application/x-msdownload");
httpResponse.setCharacterEncoding("utf-8");
OutputStream osm = new BufferedOutputStream(httpResponse.getOutputStream());
while ((length = ism.read(buf))>0) {
osm.write(buf,0, length);
}
//关闭流
osm.close();
} catch (MinioException ex) {
ex.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 图片查看
* @param fileName
* @param response
* @throws IOException
*/
public void getImage( String fileName, HttpServletResponse response) throws IOException {
InputStream in = null;
try {
in = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build()
);
} catch (Exception e) {
e.printStackTrace();
}
if (in == null){
response.sendError(404, "未能找到图片");
}
//图片类型
String[] fileArr = fileName.split("\\.");
String contentType = "";
StringBuilder originalFileName = new StringBuilder();
if (fileArr.length > 1){
contentType = "image/" + fileArr[fileArr.length - 1];
for (int i = 0; i < fileArr.length - 1; i++) {
originalFileName.append(fileArr[i]);
if (i != fileArr.length - 2){
originalFileName.append(".");
}
}
}else {
contentType = "application/octet-stream";
originalFileName = new StringBuilder(fileName);
}
try {
response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.addHeader("X-Original-File-Name", originalFileName.toString());
response.setContentType(contentType);
ServletOutputStream outputStream = response.getOutputStream();
IOUtils.copy(in, outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void deleteObject(String fileName) {
try {
RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build();
minioClient.removeObject(removeObjectArgs);
}catch (Exception e){
log.error("错误:"+e.getMessage());
}
}
public void getStrategy() {
try {
String bucketPolicy =
minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());
System.out.println(bucketPolicy);
}catch (Exception e){
log.error("错误:"+e.getMessage());
}
}
}
权限策略打印结果
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Action": [
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:ListBucketMultipartUploads"
],
"Resource": [
"arn:aws:s3:::file"
]
},
{
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Action": [
"s3:GetObject",
"s3:ListMultipartUploadParts",
"s3:PutObject",
"s3:AbortMultipartUpload",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::file/tess*",
"arn:aws:s3:::file/*"
]
},
{
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::file"
],
"Condition": {
"StringEquals": {
"s3:prefix": [
"tess"
]
}
}
}
]
}
可以直接将保存图片的地址返回前端,通过地址直接支持查看图片,不需要调用后台代码