持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
使用docker安装minio(spring boot使用)
查看docker环境是否正常
docker search minIO
下载minIO的镜像
docker pull minio/minio
创建minIO容器
查看所有镜像
docker images
创建目录:
mkdir -p /data/minio/config
mkdir -p /data/minio/data
创建并启动minIO容器: 这里的 \ 指的是命令还没有输入完,还需要继续输入命令,先不要执行的意思。 这里的9090端口指的是minio的客户端端口。虽然设置9090,但是我们在访问9000的时候,他会自动跳到9090。
docker run -p 9091:9091 -p 9090:9090 \
--net=host \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=admin" \
-e "MINIO_SECRET_KEY=Cjw970404" \
-v /docker/minio/data:/docker/minio/data \
-v /docker/minio/config:/docker/minio/config \
minio/minio server \
/data --console-address ":9090" -address ":9091"
# 设置为和 docker 绑定启动,docker 启动则 minio 就启动
docker update --restart=always
访问地址
到这里。minio就算安装完成了
SpringBoot整合Minio
首先我们先要导入项目依赖
导入依赖
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.2</version>
</dependency>
application.properties配置信息
这边的配置,需要自己根据需求进行配置。
# 限制上传文件大小
spring.servlet.multipart.max-file-size=200MB
spring.servlet.multipart.max-request-size=200MB
# minio配置
minio.endpoint=http://*.*.*.*:9001
minio.bucketName=taluohui
minio.accessKey=admin
minio.secretKey=Cjw970404
MinioConfig.class配置类
将配置文件中的配置读取出来,并进行MinioClient的配置申明。
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
@Value("${minio.url}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Value("${minio.bucketName}")
private String bucketName;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
minio工具类
实现minio的配置方法,更加方便我们之后的时候。
@Component
@Slf4j
public class MinioUtil {
@Autowired
private MinioConfig prop;
@Resource
private MinioClient minioClient;
/**
* 查看存储bucket是否存在
* @return boolean
*/
public Boolean bucketExists(String bucketName) {
Boolean found;
try {
found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return found;
}
/**
* 创建存储bucket
* @return Boolean
*/
public Boolean makeBucket(String bucketName) {
try {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 删除存储bucket
* @return Boolean
*/
public Boolean removeBucket(String bucketName) {
try {
minioClient.removeBucket(RemoveBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 获取全部bucket
*/
public List<Bucket> getAllBuckets() {
try {
List<Bucket> buckets = minioClient.listBuckets();
return buckets;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 文件上传
*
* @param file 文件
* @return Boolean
*/
public String upload(MultipartFile file) {
String originalFilename = file.getOriginalFilename();
if (StringUtils.isBlank(originalFilename)){
throw new RuntimeException();
}
String fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String objectName = formatter.format(new Date()) + "/" + fileName;
try {
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(prop.getBucketName()).object(objectName)
.stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
//文件名称相同会覆盖
minioClient.putObject(objectArgs);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return objectName;
}
/**
* 预览图片
* @param fileName
* @return
*/
public String preview(String fileName){
// 查看文件地址
GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(prop.getBucketName()).object(fileName).method(Method.GET).build();
try {
String url = minioClient.getPresignedObjectUrl(build);
return url;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 文件下载
* @param fileName 文件名称
* @param res response
* @return Boolean
*/
public void download(String fileName, HttpServletResponse res) {
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(prop.getBucketName())
.object(fileName).build();
try (GetObjectResponse response = minioClient.getObject(objectArgs)){
byte[] buf = new byte[1024];
int len;
try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){
while ((len=response.read(buf))!=-1){
os.write(buf,0,len);
}
os.flush();
byte[] bytes = os.toByteArray();
res.setCharacterEncoding("utf-8");
// 设置强制下载不打开
// res.setContentType("application/force-download");
res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
try (ServletOutputStream stream = res.getOutputStream()){
stream.write(bytes);
stream.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查看文件对象
* @return 存储bucket内文件对象信息
*/
public List<Item> listObjects() {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(prop.getBucketName()).build());
List<Item> items = new ArrayList<>();
try {
for (Result<Item> result : results) {
items.add(result.get());
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return items;
}
/**
* 删除
* @param fileName
* @return
* @throws Exception
*/
public boolean remove(String fileName){
try {
minioClient.removeObject( RemoveObjectArgs.builder().bucket(prop.getBucketName()).object(fileName).build());
}catch (Exception e){
return false;
}
return true;
}
}
文件处理接口
实现文件增删改查等操作的接口。
@Api(tags = "文件相关接口")
@Slf4j
@RestController
@RequestMapping("/product/file")
public class FileController {
@Autowired
private MinioUtil minioUtil;
@Autowired
private MinioConfig prop;
@ApiOperation(value = "查看存储bucket是否存在")
@GetMapping("/bucketExists")
public JsonResponse bucketExists(@RequestParam("bucketName") @Validated @NotBlank(message = "存储桶名不能为空") String bucketName) {
if (minioUtil.bucketExists(bucketName)) {
return JsonResponse.success("存储bucket存在");
} else {
return JsonResponse.fail(500, "存储bucket不存在");
}
}
@ApiOperation(value = "创建存储bucket")
@GetMapping("/makeBucket")
public JsonResponse makeBucket(@RequestParam("bucketName") @Validated @NotBlank(message = "存储桶名不能为空") String bucketName) {
if (minioUtil.makeBucket(bucketName)) {
return JsonResponse.success("存储bucket创建成功");
} else {
return JsonResponse.fail(500, "存储bucket创建失败");
}
}
@ApiOperation(value = "删除存储bucket")
@GetMapping("/removeBucket")
public JsonResponse removeBucket(String bucketName) {
if (minioUtil.removeBucket(bucketName)) {
return JsonResponse.success("存储bucket删除成功");
} else {
return JsonResponse.fail(500, "存储bucket删除失败");
}
}
@ApiOperation(value = "获取全部bucket")
@GetMapping("/getAllBuckets")
public JsonResponse getAllBuckets() {
List<Bucket> allBuckets = minioUtil.getAllBuckets();
return new JsonResponse<>(allBuckets);
}
@ApiOperation(value = "文件上传返回url")
@PostMapping("/upload")
public JsonResponse upload(@RequestParam("file") MultipartFile file) {
String objectName = minioUtil.upload(file);
if (null != objectName) {
return JsonResponse.success(prop.getEndpoint() + "/" + prop.getBucketName() + "/" + objectName);
}
return JsonResponse.fail();
}
@ApiOperation(value = "图片/视频预览")
@GetMapping("/preview")
public JsonResponse preview(@RequestParam("fileName") String fileName) {
return JsonResponse.success(minioUtil.preview(fileName));
}
@ApiOperation(value = "文件下载")
@GetMapping("/download")
public JsonResponse download(@RequestParam("fileName") String fileName, HttpServletResponse res) {
minioUtil.download(fileName,res);
return JsonResponse.success();
}
@ApiOperation(value = "删除文件", notes = "根据url地址删除文件")
@PostMapping("/delete")
public JsonResponse remove(String url) {
String objName = url.substring(url.lastIndexOf(prop.getBucketName()+"/") + prop.getBucketName().length()+1);
minioUtil.remove(objName);
return JsonResponse.success(objName);
}
}
解决链接7天失效问题
访问minio的管理界面,点击对应的存储桶的设置
Access Policy选项选择custom
将其中的ListBucket配置删除掉,这样别人就没办法通过存储桶地址获取所有图片,并删除图片了。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Action": [
"s3:GetBucketLocation",
"s3:ListBucketMultipartUploads"
],
"Resource": [
"arn:aws:s3:::taluohui"
]
},
{
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Action": [
"s3:AbortMultipartUpload",
"s3:DeleteObject",
"s3:GetObject",
"s3:ListMultipartUploadParts",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::taluohui/*"
]
}
]
}