我们经常接触到的关于minio的上传下载都是在项目中导入minio依赖,然后给配置一个MinioConfig,配置minio服务的地址账号密码等,如下图。
一、根据minio依赖实现上传下载
1.导入依赖
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.4</version>
</dependency>
2.application.yml 配置信息
minio:
endpoint: http://127.0.0.1:19000 #Minio服务所在地址
bucketName: test-01 #存储桶名称
accessKey: minioadmin #访问的key
secretKey: minioadmin111 #访问的秘钥
3.MinioConfig.class配置类
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
4.minio工具类
@Component
@Slf4j
public class MinioUtil {
@Autowired
private MinioConfig prop;
@Resource
private MinioClient minioClient;
@Autowired
private CodeService codeService;
/**
* 查看存储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 = UuidUtils.generateUuid() + originalFilename.substring(originalFilename.lastIndexOf("."));
String objectName = CommUtils.getNowDateLongStr("yyyy-MM/dd") + "/" + 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;
}
}
5.文件上传接口
@Api(tags = "文件相关接口")
@Slf4j
@RestController
@RequestMapping(value = "/sys/file/v1/")
public class FileController {
@Autowired
private MinioUtil minioUtil;
@Autowired
private MinioConfig prop;
@ApiOperation(value = "查看存储bucket是否存在")
@GetMapping("/bucketExists")
public Result bucketExists(String bucketName) {
return Result.success(minioUtil.bucketExists(bucketName));
}
@ApiOperation(value = "创建存储bucket")
@GetMapping("/makeBucket")
public Result makeBucket(String bucketName) {
minioUtil.makeBucket(bucketName);
return Result.success();
}
@ApiOperation(value = "删除存储bucket")
@GetMapping("/removeBucket")
public Result removeBucket(String bucketName) {
minioUtil.removeBucket(bucketName);
return Result.success();
}
@ApiOperation(value = "获取全部bucket")
@GetMapping("/getAllBuckets")
public Result<List<Bucket>> getAllBuckets() {
List<Bucket> allBuckets = minioUtil.getAllBuckets();
return Result.success(allBuckets);
}
@ApiOperation(value = "文件上传返回url")
@PostMapping("/upload")
public Result<String> upload(@RequestParam(value = "file") MultipartFile file) {
String objectName = minioUtil.upload(file);
if (null != objectName) {
return Result.success(prop.getEndpoint() + "/" + prop.getBucketName() + "/" + objectName);
}
return Result.fail();
}
@ApiOperation(value = "图片/视频预览")
@GetMapping("/preview")
public Result preview(@RequestParam("fileName") String fileName) {
return Result.success(minioUtil.preview(fileName));
}
@ApiOperation(value = "文件下载")
@GetMapping("/download")
public Result download(@RequestParam("fileName") String fileName, HttpServletResponse res) {
minioUtil.download(fileName,res);
return Result.success();
}
@ApiOperation(value = "删除文件", notes = "根据url地址删除文件")
@PostMapping("/delete")
public Result remove(String url) {
String objName = url.substring(url.lastIndexOf(prop.getBucketName()+"/") + prop.getBucketName().length()+1);
minioUtil.remove(objName);
return Result.success();
}
}
二、根据minio-client依赖实现上传下载
1.引入依赖
<dependency>
<groupId>com.kotei.framework</groupId>
<artifactId>minio-client</artifactId>
<version>0.0.2-SNAPSHOT</version>
</dependency>
2.配置地址
3.MinioUtils
注意,这里download返回的是一个JSONObject对象,他的data值格式为一个下载链接,所以我们要直接下载链接还要再写 一点,见下面controller层。
@Component
@Slf4j
public class MinIoUtils {
@Resource
private MinIoService minIoService;
@Resource
private TokenService tokenService;
public static final String K11 = "k11-";
/**
* 上传文件到 minIo
*
* @param file 上传的文件
* @param siteId 站点id
*/
public String minIoUpload(MultipartFile file, Long siteId) {
try {
String extName = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf(".")).toLowerCase();
String dataFileName = UUID.randomUUID().toString();
String fileName = dataFileName + extName;
log.info(">>>>>>>>>>>>>>>>>>> file uploading...");
JSONObject jsonObject = minIoService.uploadByStream(K11 + siteId, fileName, file);
if ("200".equalsIgnoreCase(jsonObject.getString("code"))) {
log.info(">>>>>>>>>>>>>>>>>>> file upload success {}", jsonObject.get("data"));
}
return fileName;
} catch (Exception e) {
e.printStackTrace();
log.error(">>>>>>>>>>>>>> file upload failed");
return null;
}
}
/**
* 下载
*/
public JSONObject download(KProjectFileEntity form) {
JSONObject object = null;
//文件路径
String fileUrl = form.getFileUrl();
try {
log.error("Excel download: {} file uploading...", form.getFileName());
object = minIoService.getFileUrl(K11 + tokenService.getSiteId().toString(), fileUrl, 60 * 60);
log.error("Excel download: {} file upload success", form.getFileName());
} catch (Exception e) {
e.printStackTrace();
log.error("Excel download: {} file upload failed", form.getFileName());
}
return object;
}
}
4.MinioService
@Component
public class MinIoService {
// 这个是minio服务部署的地址,自己去配置类配置一下。
@Value("${gossUrl}")
private String URL;
private MinIoHttpUtil minIoHttpUtil;
@PostConstruct
public void init(){
minIoHttpUtil=new MinIoHttpUtil();
minIoHttpUtil.setURL(URL);
}
/**
* 文件上传(返回URL下载地址)
*
* @param bucketName 桶名
* @param fileName 文件名
* @param file
* @return: 文件url下载地址
*/
@SneakyThrows(Exception.class)
public JSONObject uploadByStream(String bucketName, String fileName, MultipartFile file) {
JSONObject object = minIoHttpUtil.uploadFile("/uploadByStream", bucketName, fileName, file);
return object;
}
/**
* 获取文件下载地址
*
* @param bucketName 桶名
* @param fileName 文件名
* @param expires Expiry in seconds; defaults to 7 days.
*/
public JSONObject getFileUrl(String bucketName, String fileName, Integer expires) {
String https = minIoHttpUtil.getHttps("/getFileUrl?bucketName=" + bucketName + "&fileName=" + fileName+"&expires=" + expires);
JSONObject object = JSONObject.parseObject(https);
return object;
}
}
5.MinioHttpUtil
public class MinIoHttpUtil {
private String URL;
public String getURL() {
return URL;
}
public void setURL(String URL) {
this.URL = URL;
}
public JSONObject uploadFile(String urlStr,String bucketName,String fileName, MultipartFile file) throws IOException {
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setSocketTimeout(1000000)
.setConnectTimeout(1000000)
.setConnectionRequestTimeout(1000000)
.setStaleConnectionCheckEnabled(true)
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(defaultRequestConfig)
.build();
HttpPost uploadFile = new HttpPost(URL+urlStr);
DecimalFormat df = new DecimalFormat("#.##");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
// HTTP.PLAIN_TEXT_TYPE,HTTP.UTF_8
builder.addTextBody("bucketName", bucketName, ContentType.TEXT_PLAIN);
builder.addTextBody("fileName", fileName, ContentType.TEXT_PLAIN);
// 把文件加到HTTP的post请求中
// String filepath = "/user/test/123.png"
// File f = new File(filepath);
builder.addBinaryBody(
"file",
file.getInputStream(),
// new FileInputStream(f),
ContentType.APPLICATION_OCTET_STREAM,
file.getOriginalFilename()
);
HttpEntity multipart = builder.build();
uploadFile.setEntity(multipart);
CloseableHttpResponse response = httpClient.execute(uploadFile);
HttpEntity responseEntity = response.getEntity();
String sResponse= EntityUtils.toString(responseEntity, "UTF-8");
JSONObject jsonObject = JSONObject.parseObject(sResponse);
// {"code":1,"data":"7efb19980373dd90f5077576afa7481a","message":""}
// {"code":401,"httpStatus":null,"data":"373656a2-baff-423a-93fb-704f51003509","message":"error"}
return jsonObject;
}
public String getHttps(String urlParam) {
HttpURLConnection con = null;
BufferedReader buffer = null;
StringBuffer resultBuffer = null;
try {
URL url = new URL(URL+urlParam);
//得到连接对象
con = (HttpURLConnection) url.openConnection();
//设置请求类型
con.setRequestMethod("GET");
//设置请求需要返回的数据类型和字符集类型
con.setRequestProperty("Content-Type", "application/json;charset=GBK");
//允许写出
con.setDoOutput(true);
//允许读入
con.setDoInput(true);
//不使用缓存
con.setUseCaches(false);
//得到响应码
int responseCode = con.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK){
//得到响应流
InputStream inputStream = con.getInputStream();
//将响应流转换成字符串
resultBuffer = new StringBuffer();
String line;
buffer = new BufferedReader(new InputStreamReader(inputStream, "GBK"));
while ((line = buffer.readLine()) != null) {
resultBuffer.append(line);
}
return resultBuffer.toString();
}
}catch(Exception e) {
e.printStackTrace();
}
return "";
}
}
6.controller层
这里是取出JSONObject中字符串形式的下载链接,转换为URL,用代码在服务中打开链接或自动下载,再把文件转换为流形式去储存为一个流数组,对应文件名称数组,最后用hutool中的ZipUtil工具实现多个文件压缩返回。
这里有一个问题要注意,就是文件名称最好不要有汉字,会报错!!!应该是编码格式没有设置,我在这里就不演示了,希望能对你有帮助。
@RequestMapping("/download")
public ResultBody<T> downloadByProjectId(Long projectId, HttpServletResponse response) throws IOException {
List<KProjectFileEntity> entities = kProjectFileService.downloadFileByProject(projectId);
if (entities != null && entities.size() > 0) {
//被压缩文件InputStream
InputStream[] fileStreams = new InputStream[entities.size()];
//被压缩文件名称
String[] fileNames = new String[entities.size()];
for (int i = 0; i < entities.size(); i++) {
JSONObject object = minIoUtils.download(entities.get(i));
if (object != null) {
String data = object.getString("data");
URL url = new URL(data);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置超时间为3秒
conn.setConnectTimeout(3 * 1000);
// 防止屏蔽程序抓取而返回403错误
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
// 得到输入流
InputStream is = conn.getInputStream();
fileStreams[i] = is;
fileNames[i] = entities.get(i).getFileUrl();
}
}
//多个文件压缩成压缩包返回
ZipUtil.zip(response.getOutputStream(), fileNames, fileStreams);
return ResultBody.success(null, "文件下载成功");
}
return ResultBody.failed(200, "没有可下载文件");
}