一.linux安装minio
我是安装到opt目录下的:
cd opt 进入opt目录
执行:
wget https://dl.min.io/server/minio/release/linux-amd64/minio
下载完成后,出现 minio文件。
赋予权限:chmod +x minio 或者 直接 chmod 777 minio
chmod +x minio
minio需要一个存放静态文件的路径
mkdir -p /var/minio/data (用于存放静态文件)
mkdir -p /var/minio/data
启动运行:
./minio server /var/minio/data
配置安全组,开放端口,这里的40485每次启动都会变化,所以需要在启动的时候设置固定的端口号:
./minio server /var/minio/data --console-address ":9001"
其中RootUser和RootPass可以自定义,默认是minioadmin,
执行以下命令自定义账号密码:
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=admin
设置minio后台启动:
vim start.sh
输入:
nohup /opt/minioserver /var/minio/data --console-address ":9001" > /opt/minio.log 2>&1 &
日志输入到minio.log文件中。
执行:
sh start.sh
到这里minio就安装启动完毕了,可以直接访问 http://ip:9001进行访问了。
以minio作为OSS管理文件,需要配置桶权限,保证文件可以访问,需要进入minio管理页面进行设置。
其中access keys 生成后需要单独记录,以便后续使用。
配置通的访问权限为public,公共权限。
设置操作权限
到这里整个minio就配置完成了。
二.接入到springboot
引入依赖:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.0</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.9.2</version>
</dependency>
yml配置minio(这里ip替换成自己的):
minio:
endpoint: http://ip:9000
access-key: Ej4QABHajetm8wTMUwbc
secret-key: vnF89O6wFNxNQEsSLSPJxFhsfxYkfoQcsIttnpML
bucket-name: test
创建minio配置类:
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinIOConfig {
/**
* 服务地址
*/
private String endpoint;
/**
* 用户名
*/
private String accessKey;
/**
* 密码
*/
private String secretKey;
/**
* 存储桶名称
*/
private String bucketName;
/**
* 预览到期时间(小时)
*/
private Integer previewExpiry;
@Bean
public MinioClient getMinIOClient() {
return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
}
service:
public interface MinIOFileService {
List<String> uploadFile(MultipartFile[] files);
String getPreviewUrl(String fileName, String bucketName);
void downloadFile(HttpServletResponse response, String fileName, String bucketName);
String delFile(String fileName, String bucketName);
}
serviceImpl:
@Service
@Slf4j
public class MinIOFileServiceImpl implements MinIOFileService {
@Autowired
private MinIOConfig minIOConfig;
@Autowired
private MinioClient minioClient;
@Override
public List<String> uploadFile(MultipartFile[] files) {
if (Objects.nonNull(files) && files.length > 0) {
String bucketName = minIOConfig.getBucketName();
List<String> resultList = new ArrayList<>();
for (MultipartFile file : files) {
try {
log.info("file: " + file);
if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
String fileName = file.getOriginalFilename();
StringBuffer fileNameSB = new StringBuffer();
fileNameSB.append(System.currentTimeMillis()).append("_").append(bucketName).append("_");
if (StrUtil.isNotBlank(fileName)) {
fileNameSB.append(fileName.replaceAll(",", ""));
}
fileName = fileNameSB.toString();
PutObjectArgs args = PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build();
minioClient.putObject(args);
resultList.add(getPreviewUrl(fileName, bucketName));
} catch (Exception e) {
log.info("上传图片失败:", e.getMessage());
}
}
return resultList;
}
return Collections.emptyList();
}
@Override
public String getPreviewUrl(String fileName, String bucketName) {
if (StrUtil.isNotBlank(fileName)) {
bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minIOConfig.getBucketName();
try {
minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
if (null != minIOConfig.getPreviewExpiry()) {
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).expiry(minIOConfig.getPreviewExpiry(), TimeUnit.HOURS).build());
} else {
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).build());
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
public void downloadFile(HttpServletResponse response, String fileName, String bucketName) {
if (StrUtil.isNotBlank(fileName)) {
bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minIOConfig.getBucketName();
try {
StatObjectResponse objectStat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
response.setContentType(objectStat.contentType());
response.setCharacterEncoding("UTF-8");
InputStream inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
IOUtils.copy(inputStream, response.getOutputStream());
} catch (Exception e) {
}
}
}
@Override
public String delFile(String fileName, String bucketName) {
if (StrUtil.isNotBlank(fileName)) {
bucketName = StrUtil.isNotBlank(bucketName) ? bucketName : minIOConfig.getBucketName();
try {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
return "success";
} catch (Exception e) {
return "删除文件失败,请刷新后重试";
}
}
return "文件不能为空";
}
}
controller:
@RestController
@RequestMapping("/files")
public class FileController {
@Autowired
private MinIOFileService fileService;
@PostMapping("/minio/upload")
public ApiResult<?> uploadTest(MultipartFile[] files) {
List<String> list;
try {
list = fileService.uploadFile(files);
} catch (Exception e) {
return ApiResult.fail("上传失败,请刷新后重试!");
}
return ObjectUtils.isNull(list) ? ApiResult.fail("上传文件不能为空") : ApiResult.ok(list, "上传成功");
}
}
到这里集成到springboot就完成了。
三.集成问题以及解决方式
启动报错:
***************************
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:105)
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:/Program%20Files/Java/maven_repository/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jar!/okhttp3/RequestBody.class
The class hierarchy was loaded from the following locations:
okhttp3.RequestBody: file:/D:/Program%20Files/Java/maven_repository/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of okhttp3.RequestBody
明明引入的okhttp3的版本号是4.9.2,这里出现错误的地方是3.14.9。
minio 8.0以上的包和okhttp3的版本有兼容性问题,必须对应okhttp3 4.*以上的包。
这里的 okhttp3 出现3.14.9,而不是我们引入的4.9.2,是因为spring-boot-starter-parent的问题,parent 2.4.3中的spring-boot-dependencies有指定okhttp3的版本,
所以我们需要在项目中覆盖parent 引入的okhttp3的版本,在我们项目的根 pom文件中的properties中指定okhttp3的版本,
<okhttp3.version>4.9.2</okhttp3.version>
重新运行,问题解决。