SpringBoot+Minio实现文件上传服务器
服务器:百度云Centos7
docker安装minio镜像
- Centos上启动minio镜像
docker run -p 9000:9000 -p 9001:9001 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio123" -v /home/data:/data -v /home/config:/root/.minio minio/minio server /data --console-address ":9001"
- 输入网址http://ip:9001/login,登录minio
- 创建用户,保存ACCESSKEY和SECRETKYEY,后面要用。
- 创建桶。相当于一个文件夹,用来管理上传的文件
- 创建Spring Boot项目,在yaml文件中配置minio
server:
port: 10010
minio:
url: http://ip:9000
accessKey: accessKey //第三步中创建的ACCESSKEY
secretKey: secretKey //第三步中创建的SECRETKEY
bucketName: blog
- 创建MinioConfig配置类,将MinioClient交给Spring来统一管理
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
private String url;
private String accessKey;
private String secretKey;
private String bucketName;
@Bean
public MinioClient minioClient(){
return MinioClient.builder().endpoint(url).credentials(accessKey,secretKey).build();
}
}
- 创建MinioUtils工具类,编写minio文件操作、桶操作的相关代码
package com.study.utils;
import com.study.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.UUID;
@Component
@Slf4j
public class MinioUtils {
@Autowired
private MinioConfig prop;
@Resource
private MinioClient minioClient;
/**
* 判断桶是否存在
* param:bucketName
*/
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.isEmpty(originalFilename)){
throw new RuntimeException();
}
// if (StringUtils.isBlank(originalFilename)){
// throw new RuntimeException();
// }
String fileName = UUID.randomUUID().toString().replace("-","") + originalFilename.substring(originalFilename.lastIndexOf("."));
// String objectName = CommUtils.getNowDateLongStr("yyyy-MM/dd") + "/" + fileName;
try {
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(prop.getBucketName()).object(fileName)
.stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
//文件名称相同会覆盖
minioClient.putObject(objectArgs);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return fileName;
}
/**
* 预览图片
* @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();
}
}
}
- 创建FileController控制器,编写文件上传接口
package com.study.controller;
import com.study.dto.response.R;
import com.study.utils.MinioUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/admin")
public class FileController {
@Autowired
private MinioUtils minioUtils;
@PostMapping("/upload")
public R<String> fileupload(@RequestParam("file") MultipartFile file){
// 上传文件
String filename = minioUtils.upload(file);
// 获取文件预览的链接
String preview = minioUtils.preview(filename);
System.out.println(preview);
return R.ok(preview);
}
}
测试
使用搭建好的vue项目来进行测试,文件上传部分代码如下:
<div class="main">
<el-button type="danger" @click="send">危险按钮</el-button>
<el-upload action="http://127.0.0.1:10010/admin/upload" list-type="picture-card"
:on-preview="handlePictureCardPreview" :on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
</div>