为什么用 minio ,因为 oss 收费。
minio 官网
maven minio
最新版依赖
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.5</version>
</dependency>
如果只添加minio依赖启动项目大概率会碰到如下的报错信息
***************************
APPLICATION FAILED TO START
***************************
Description:
An attempt was made to call a method that does not exist. The attempt was made from the following location:
io.minio.S3Base.<clinit>(S3Base.java:104)
The following method did not exist:
okhttp3.RequestBody.create([BLokhttp3/MediaType;)Lokhttp3/RequestBody;
The method's class, okhttp3.RequestBody, is available from the following locations:
jar:file:/D:/maven/repository/com/squareup/okhttp3/okhttp/3.14.4/okhttp-3.14.4.jar!/okhttp3/RequestBody.class
The class hierarchy was loaded from the following locations:
okhttp3.RequestBody: file:/D:/maven/repository/com/squareup/okhttp3/okhttp/3.14.4/okhttp-3.14.4.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of okhttp3.RequestBody
进程已结束,退出代码为 1
从 io.minio.S3Base.(S3Base.java:104) 这一行点进去可以看到错误原因。
static {
try {
RequestBody.create(new byte[] {}, null);
} catch (NoSuchMethodError ex) {
throw new RuntimeException("Unsupported OkHttp library found. Must use okhttp >= 4.8.1", ex);
}
}
pom minio 依赖点进去可以找到 okhttp的依赖
 这里已经定义了 4.10.0版本,为什么到了外面不生效呢 ?
我们找到 spring-boot-starter-parent 依赖搜索 okhttp
 发现没有结果,于是进入到 spring-boot-dependencies 中搜索 okhttp  我们来约束一下版本
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
</dependencies>
</dependencyManagement>
可以看到版本已经成功使用 4.10.0  第二种方法
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.5</version>
<exclusions>
<exclusion>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
使用
在 yml 定义几个配置
minio:
enable: true
endpoint: 127.0.0.1:9000
accessKey: account
secretKey: password
bucketName: mkdir1
定义一个config来读取yml配置
@Configuration
public class MinIoClientConfig {
private final static Logger logger = LoggerFactory.getLogger(MinIoClientConfig.class);
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Value("${minio.enable}")
private boolean enable;
@Value("${minio.bucketName}")
private String bucketName;
@Bean
public MinioClient minioClient() {
if (enable) {
MinioClient client = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
try {
client.listBuckets();
} catch (Exception e) {
logger.error("minio client error {}", e.getMessage());
return null;
}
logger.info("minio client build SUCCESS");
return client;
}
return null;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public String getBucketName() {
return bucketName;
}
public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}
}
创建bean的时候引入连接测试获取 listBuckets ,如果获取失败则提示如下效果。  定义上传文件工具类
@Service
public class MinioUtils {
private final static Logger logger = LoggerFactory.getLogger(MinioUtils.class);
@Autowired
MinIoClientConfig clientConfig;
@Autowired(required = false)
MinioClient client;
public String upload(MultipartFile file) throws Exception {
if (client == null) {
throw new RuntimeException("minio enable is false or connection failure ");
}
String saveFileName = preUpload(file, null);
String bucketName = clientConfig.getBucketName();
BucketExistsArgs args = BucketExistsArgs.builder().bucket(bucketName).build();
boolean exists = client.bucketExists(args);
if (!exists) {
MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(bucketName).build();
client.makeBucket(makeBucketArgs);
}
PutObjectArgs put = PutObjectArgs.builder()
.stream(file.getInputStream(), file.getSize(), -1)
.bucket(bucketName).object(saveFileName).build();
ObjectWriteResponse response = client.putObject(put);
GetObjectArgs get = GetObjectArgs.builder().bucket(bucketName).object(saveFileName).build();
GetObjectResponse getResponse = client.getObject(get);
GetPresignedObjectUrlArgs urlArg = GetPresignedObjectUrlArgs.builder()
.bucket(bucketName).object(saveFileName).method(Method.GET).build();
return client.getPresignedObjectUrl(urlArg).split("\\?")[0];
}
public String preUpload(MultipartFile file, String mkdir) {
String fileAllName = file.getOriginalFilename();
String prefix = LocalDateTime.now().toString().replaceAll(":", "-");
String suffix = fileAllName.substring(fileAllName.lastIndexOf("."));
if (mkdir == null) {
return prefix + suffix;
}
return mkdir + "/" + prefix + suffix;
}
}
根据业务扩展即可
定义一个测试controller
@RestController
@RequestMapping("file")
public class FileController {
@Autowired
MinioUtils service;
@PostMapping(value = "upload", headers = "content-type=multipart/form-data")
public String upload(@RequestPart("file") MultipartFile file) throws Exception {
return service.upload(file);
}
}
上传效果图如下  关于 Buckets 需要手动将权限改为 public  如果是 private 生成的 url 会带有默认的 7天时间,超过会过期。  如果是 private 权限,生成的 url 就不要做 split 截取,否则可能会无法访问 
|