1.引入pom,okhttp有版本要求,最低4.8.3
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.2</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
2.新增客户端配置类MinioConfig.java
package com.fast.file;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MinioConfig {
@Autowired
private MinioProperties minioProperties;
@Bean
public MinioClient minioClient(){
return MinioClient.builder()
.endpoint(minioProperties.getEndpoint())
.credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
.build();
}
}
3.在application.yml中新增minio配置
minio:
endpoint: http://localhost:9000
accesskey: minioadmin
secretKey: minioadmin
bucketName: test
4.新增属性接收类MinioProperties.java
package com.fast.file;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
}
5.新增MinioController.java
package com.fast.file;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.fast.common.result.common.R;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Api(tags = "Minio文件管理")
@RestController
@Slf4j
public class MinioController {
@Autowired
private MinioClient minioClient;
@Autowired
private MinioProperties minioProperties;
@Value("${minio.bucketName}")
private String bucketName;
@ApiOperation("查看文件列表")
@GetMapping("/list")
public List<Object> list() throws Exception {
//获取bucket列表
Iterable<Result<Item>> myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());
Iterator<Result<Item>> iterator = myObjects.iterator();
List<Object> items = new ArrayList<>();
String format = "{'bucketName':'%s','fileName':'%s','fileSize':'%s','path':'%s'}";
while (iterator.hasNext()) {
Item item = iterator.next().get();
String path = minioProperties.getEndpoint() + '/' + bucketName + '/' + item.objectName();
items.add(JSONUtil.parse(String.format(format, bucketName, item.objectName(), formatFileSize(item.size()), path)));
}
return items;
}
@ApiOperation("文件上传-支持批量")
@PostMapping("/upload")
public R upload(@RequestParam(name = "file", required = false) MultipartFile[] file) {
if (file == null || file.length == 0) {
return R.fail("上传文件不能为空");
}
List<Map<String, Object>> orgfileNameList = new ArrayList<>(file.length);
for (MultipartFile multipartFile : file) {
String orgfileName = multipartFile.getOriginalFilename();
//bucket得开启public策略,Manage->Summary->Access Policy:设置成public
String path = minioProperties.getEndpoint() + '/' + bucketName + '/' + orgfileName;
Map<String, Object> fileMap = new HashMap<>();
fileMap.put("fileName", orgfileName);
fileMap.put("path", path);
orgfileNameList.add(fileMap);
try {
//文件上传
InputStream in = multipartFile.getInputStream();
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(orgfileName)
.stream(in, multipartFile.getSize(), -1)
.contentType(multipartFile.getContentType())
.build());
in.close();
} catch (Exception e) {
return R.fail("上传失败");
}
}
Map<String, Object> data = new HashMap<>();
data.put("bucketName", bucketName);
data.put("fileList", orgfileNameList);
return R.data(data);
}
@ApiOperation("文件下载")
@GetMapping("/download/{fileName}")
public void download(HttpServletResponse response, @PathVariable("fileName") String fileName) {
InputStream in = null;
try {
// 获取对象信息
StatObjectResponse stat = minioClient.statObject(
StatObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
response.setContentType(stat.contentType());
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
//文件下载
in = minioClient.getObject(GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
IOUtils.copy(in, response.getOutputStream());
} catch (Exception e) {
log.error(e.getMessage());
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
}
@ApiOperation("文件删除")
@DeleteMapping("/delete/{fileName}")
public R delete(@PathVariable("fileName") String fileName) {
try {
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
} catch (Exception e) {
log.error(e.getMessage());
return R.fail("删除失败");
}
return R.success("删除成功");
}
@ApiOperation("获取文件预览地址-7天过期-用于分享")
@GetMapping("/getFilePreUrl/{fileName}")
public R getFilePreUrl(@PathVariable("fileName") String fileName) {
try {
String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(fileName)
.method(Method.GET)
//过期时间1天:60 * 60 * 24
//默认最大7天失效:.expiry(7, TimeUnit.DAYS)
.expiry(7, TimeUnit.DAYS).build());
return R.data(url);
} catch (Exception e) {
e.printStackTrace();
return R.fail("获取文件预览地址失败!");
}
}
private static String formatFileSize(long fileS) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
String wrongSize = "0B";
if (fileS == 0) {
return wrongSize;
}
if (fileS < 1024) {
fileSizeString = df.format((double) fileS) + " B";
} else if (fileS < 1048576) {
fileSizeString = df.format((double) fileS / 1024) + " KB";
} else if (fileS < 1073741824) {
fileSizeString = df.format((double) fileS / 1048576) + " MB";
} else {
fileSizeString = df.format((double) fileS / 1073741824) + " GB";
}
return fileSizeString;
}
}
注意:
如果想通过ip:9000/bucketname/filename来访问图片,则需要对bucket进行设置。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5iN2gjMyEzN5M2YmJTY2gzYyYzXxMjMzEDM5AzLcdDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)