java之minio文件服務(wù)器的日常操作
1.java項(xiàng)目結(jié)構(gòu)
如下所示:
增加minioConfig配置,服務(wù)連接使用minioDto(包含endpoint,accesskey,serectkey)
2.minioDto代碼
如下所示:
數(shù)據(jù)引用,從application.yml中的minio節(jié)點(diǎn)獲取;
@Data @Component @ConfigurationProperties(prefix = "minio") public class minioDto { private String endpoint; private String accesskey; private String secretkwy; }
application.yml中的minio節(jié)點(diǎn)如下:
minio: endpoint: http://192.168.0.147:9000 //該地址為minio服務(wù)器的9000接口,api使用 accesskey: miniominio secretkwy: miniominio
3.minioConfig代碼
如下所示:
此種設(shè)置,可以避免直接注冊(cè)static的情況(static情況時(shí)minioDto為null,會(huì)造成接口調(diào)用失?。?/p>
/** * @Description minio客戶端單例類 * @Date 2022-07-13 16:37 * @Author xie */ @Component @Data public class MinioConfig { private static final Logger log = LoggerFactory.getLogger(DbUtils.class); @Autowired private minioDto dto; private static MinioClient minioClient; /** * @description: 獲取minioClient * @date 2021/6/22 16:55 * @return io.minio.MinioClient */ public static MinioClient getMinioClient(){ return minioClient; } /** * 判斷 bucket是否存在 * * @param bucketName: * 桶名 * @return: boolean * @date : 2020/8/16 20:53 */ @SneakyThrows(Exception.class) public static boolean bucketExists(String bucketName) { return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); } /** * 獲取全部bucket * * @param : * @return: java.util.List<io.minio.messages.Bucket> * @date : 2020/8/16 23:28 */ @SneakyThrows(Exception.class) public static List<Bucket> getAllBuckets() { return minioClient.listBuckets(); } /** * 初始化minio配置 * * @param : * @return: void * @date : 2020/8/16 20:56 */ @PostConstruct public void init() { try { minioClient = MinioClient.builder() .endpoint(dto.getEndpoint()) .credentials(dto.getAccesskey(), dto.getSecretkwy()) .build(); } catch (Exception e) { e.printStackTrace(); log.error("初始化minio配置異常: 【{}】", e.fillInStackTrace()); } } }
4.創(chuàng)建minioUtils工具類
根據(jù)需要,使用相關(guān)方法即可
/** * Minio客戶端工具類 */ @SuppressWarnings("ALL") public class MinioUtils { private static final Logger log = LoggerFactory.getLogger(DbUtils.class); /** * 創(chuàng)建文件桶(建議租戶ID為桶的名稱) */ public static boolean exitsBucket(String bucket) { boolean found = false; try { found = MinioConfig.getMinioClient().bucketExists(BucketExistsArgs.builder().bucket(bucket).build()); } catch (Exception e) { log.error("create bucket is error", e); } return found; } public static String putObjectLocalFile(String bucket, String filename, String fileFullPath) { try { boolean bucketExsit = exitsBucket(bucket); if (!bucketExsit) { //makeBucketPolicy(bucket); log.error(bucket + "-不存在"); throw new RuntimeException(bucket + "-不存在"); } //上傳目錄為當(dāng)前日期時(shí)間 String datedir = DateUtils.format(new Date(),"yyyyMMddHHmmss"); MinioConfig.getMinioClient() .uploadObject( UploadObjectArgs.builder().bucket(bucket).object(datedir + "http://" + filename).filename(fileFullPath).build() ); return MinioConfig.getMinioClient().getObjectUrl(bucket, filename); } catch (Exception e) { e.printStackTrace(); } return ""; } /** * * @param file * @param bucketName * @return */ public static String putObject(MultipartFile file, String bucketName){ InputStream inputStream = null; try{ inputStream = file.getInputStream(); //上傳目錄為當(dāng)前日期時(shí)間 String datedir = DateUtils.format(new Date(),"yyyyMMdd"); PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(datedir + "http://" + file.getOriginalFilename()) .stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build(); MinioConfig.getMinioClient().putObject(objectArgs); return MinioConfig.getMinioClient().getObjectUrl(bucketName, file.getOriginalFilename()); } catch (Exception e){ e.printStackTrace(); return ""; } finally { try{ if (inputStream!=null){ inputStream.close(); } }catch (Exception e){ e.printStackTrace(); } } } /** * 自動(dòng)創(chuàng)建桶并存儲(chǔ)文件 * * @param inputStream * @param fileName * @param bucket * @param fileSize * @return */ public static String putObjectStream(InputStream inputStream, String fileName, String bucket, Long fileSize) { try { boolean bucketExsit = exitsBucket(bucket); if (bucketExsit) { //makeBucketPolicy(bucket); log.error(bucket + "-不存在"); } MinioConfig.getMinioClient().putObject( PutObjectArgs.builder() .bucket(bucket).object(fileName).stream(inputStream, fileSize, -1).build()); inputStream.close(); return MinioConfig.getMinioClient().getObjectUrl(bucket, fileName); } catch (Exception e) { e.printStackTrace(); } return null; } /** * @param bucket 桶名稱 * @param path 文件夾路徑 [doc/] * @param file 要上傳的文件 * @param fileName 自定義文件名 * @return */ public static String putObject(String bucket, String path, MultipartFile file, String fileName) throws Exception { if (!exitsBucket(bucket)) { //makeBucketPolicy(bucket); log.error(bucket + "-不存在"); } InputStream inputStream = null; try { MinioConfig.getMinioClient().putObject( PutObjectArgs.builder().bucket(bucket).object(path).stream( new ByteArrayInputStream(new byte[]{}), 0, -1) .build()); inputStream = file.getInputStream(); if (StringUtils.isEmpty(fileName)) { fileName = file.getOriginalFilename(); } InputStream in = file.getInputStream(); PutObjectOptions options = new PutObjectOptions(in.available(), -1); options.setContentType(file.getContentType()); String objectName = path + System.currentTimeMillis() + "_" + fileName; // 生成時(shí)間戳防止重名 MinioConfig.getMinioClient().putObject(bucket, objectName, in, options); file.getInputStream().close(); in.close(); return MinioConfig.getMinioClient().presignedGetObject(bucket, objectName); } catch (Exception e) { e.printStackTrace(); } finally { if (inputStream != null) { inputStream.close(); } } return null; } /** * 自動(dòng)創(chuàng)建桶并存儲(chǔ)文件 * * @return */ public static String putObjectStream(MultipartFile file, String bucket) throws Exception { //判斷文件是否為空 if (null == file || 0 == file.getSize()) { throw new ServiceException("上傳minio文件服務(wù)器錯(cuò)誤,上傳文件為空"); } boolean exsit = exitsBucket(bucket); if (!exsit) { //makeBucketPolicy(bucket); log.error(bucket + "-不存在"); throw new ServiceException("minio文件服務(wù)器:" + bucket + " 桶不存在"); } //文件名 String originalFilename = file.getOriginalFilename(); //新的文件名 = 時(shí)間戳_隨機(jī)數(shù).后綴名 assert originalFilename != null; long now = System.currentTimeMillis() / 1000; String fileName = DateUtils.format(new Date(),"yyyyMMdd")+"_"+ now + "_" + new Random().nextInt(1000) + originalFilename.substring(originalFilename.lastIndexOf(".")); String fileHeader = null; try { InputStream inputStream = file.getInputStream(); //boolean bucketExsit = exitsBucket(bucket); //if (bucketExsit) { // MinioClientSingleton.getMinioClient().makeBucket(MakeBucketArgs.builder() // .bucket(bucket) // .build()); //} MinioConfig.getMinioClient().putObject( PutObjectArgs.builder().bucket(bucket).object(fileName).stream( inputStream, file.getSize(), -1) .contentType(file.getContentType()) .build()); //MinioClientSingleton.getMinioClient().putObject( // PutObjectArgs.builder() // .bucket(bucket).object(file.getOriginalFilename()).stream(inputStream, inputStream.available(), -1).build()); inputStream.close(); return MinioConfig.getMinioClient().getObjectUrl(bucket, fileName); } catch (Exception e) { e.printStackTrace(); } return null; } //private static void makeBucketPolicy(String bucket) throws ErrorResponseException, InsufficientDataException, InternalException, InvalidBucketNameException, InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException, RegionConflictException, ServerException, XmlParserException { // String policyJsonBuilder = "{\n" + // " "Statement": [\n" + // " {\n" + // " "Action": [\n" + // " "s3:GetBucketLocation",\n" + // " "s3:ListBucket"\n" + // " ],\n" + // " "Effect": "Allow",\n" + // " "Principal": "*",\n" + // " "Resource": "arn:aws:s3:::" + bucket + ""\n" + // " },\n" + // " {\n" + // " "Action": "s3:GetObject",\n" + // " "Effect": "Allow",\n" + // " "Principal": "*",\n" + // " "Resource": "arn:aws:s3:::" + bucket + "/*"\n" + // " }\n" + // " ],\n" + // " "Version": "2012-10-17"\n" + // "}\n"; // MinioClientSingleton.getMinioClient().makeBucket(MakeBucketArgs.builder() // .bucket(bucket) // .build()); // //noinspection deprecation // MinioClientSingleton.getMinioClient().setBucketPolicy(bucket, policyJsonBuilder); //} /** * 查詢所有桶文件 * * @return */ public static List<Bucket> getListBuckets() { try { return MinioConfig.getMinioClient().listBuckets(); } catch (Exception e) { e.printStackTrace(); } return Collections.emptyList(); } /** * 刪除文件 * * @param bucket 桶名稱 * @param objectName 對(duì)象名稱 * @return boolean */ public static boolean removeObject(String bucket, String objectName) { try { boolean exsit = exitsBucket(bucket); if (exsit) { // 從mybucket中刪除myobject。removeobjectargs.builder().bucket(bucketname).object(objectname).build() MinioConfig.getMinioClient().removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build()); return true; } } catch (Exception e) { log.error("removeObject", e); } return false; } /** * 批量刪除文件 * * @param bucket 桶名稱 * @param objectNames 對(duì)象名稱 * @return boolean */ public static boolean removeObjects(String bucket, List<String> objectNames) { boolean exsit = exitsBucket(bucket); if (exsit) { try { List<DeleteObject> deleteObjects = new LinkedList<>(); for (String objectName : objectNames) { deleteObjects.add(new DeleteObject(objectName)); } Iterable<Result<DeleteError>> results = MinioConfig.getMinioClient().removeObjects( RemoveObjectsArgs.builder() .bucket(bucket) .objects(deleteObjects) .build() ); for (Result<DeleteError> result : results) { DeleteError error = result.get(); log.error( "Error in deleting object " + error.objectName() + "; " + error.message()); } return true; } catch (Exception e) { log.error("removeObject", e); } } return false; } /** * 獲取單個(gè)桶中的所有文件對(duì)象名稱 * * @param bucket 桶名稱 * @return {@link List}<{@link String}> */ public static List<String> getBucketObjectName(String bucket) { boolean exsit = exitsBucket(bucket); if (exsit) { List<String> listObjetcName = new ArrayList<>(); try { Iterable<Result<Item>> myObjects = MinioConfig.getMinioClient().listObjects(ListObjectsArgs.builder().bucket(bucket).build()); for (Result<Item> result : myObjects) { Item item = result.get(); listObjetcName.add(item.objectName()); } return listObjetcName; } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 以流的形式獲取一個(gè)文件對(duì)象 * * @param bucket 桶名稱 * @param objectName 對(duì)象名稱 * @return {@link InputStream} */ public static InputStream getObjectInputStream(String bucket, String objectName) { boolean exsit = exitsBucket(bucket); if (exsit) { try { ObjectStat objectStat = MinioConfig.getMinioClient().statObject(StatObjectArgs.builder().bucket(bucket).object(objectName).build()); if (objectStat.length() > 0) { // 獲取objectName的輸入流。 return MinioConfig.getMinioClient().getObject(GetObjectArgs.builder().bucket(bucket).object(objectName).build()); } } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 文件下載 * @param fileName 文件名 * @param delete 是否刪除 * @throws IOException */ public static InputStream fileDownload(String bucketName, String fileName, HttpServletResponse response) { MinioClient minioClient = MinioConfig.getMinioClient(); if (minioClient == null) { return null; } InputStream inputStream = null; OutputStream outputStream = null; try { if (StringUtils.isBlank(fileName)) { response.setHeader("Content-type", "text/html;charset=UTF-8"); String data = "文件下載失敗"; OutputStream ps = response.getOutputStream(); ps.write(data.getBytes("UTF-8")); return null; } outputStream = response.getOutputStream(); // 獲取文件對(duì)象 inputStream =MinioConfig.getMinioClient().getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build()); byte buf[] = new byte[1024]; int length = 0; response.reset(); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName.substring(fileName.lastIndexOf("/") + 1), "UTF-8")); response.setContentType("application/octet-stream"); response.setCharacterEncoding("UTF-8"); // 輸出文件 while ((length = inputStream.read(buf)) > 0) { outputStream.write(buf, 0, length); } inputStream.close(); return inputStream; } catch (Throwable ex) { response.setHeader("Content-type", "text/html;charset=UTF-8"); String data = "文件下載失敗"; try { OutputStream ps = response.getOutputStream(); ps.write(data.getBytes("UTF-8")); }catch (IOException e){ e.printStackTrace(); } return null; } finally { try { outputStream.close(); if (inputStream != null) { inputStream.close(); }}catch (IOException e){ e.printStackTrace(); } } } /** * 刪除一個(gè)桶 * * @param bucket 桶名稱 */ public static boolean removeBucket(String bucket) throws Exception { // 刪除之前先檢查`my-bucket`是否存在。 boolean found = exitsBucket(bucket); if (found) { Iterable<Result<Item>> myObjects = MinioConfig.getMinioClient().listObjects(ListObjectsArgs.builder().bucket(bucket).build()); for (Result<Item> result : myObjects) { Item item = result.get(); //有對(duì)象文件,則刪除失敗 if (item.size() > 0) { return false; } } // 刪除`bucketName`存儲(chǔ)桶,注意,只有存儲(chǔ)桶為空時(shí)才能刪除成功。 MinioConfig.getMinioClient().removeBucket(RemoveBucketArgs.builder().bucket(bucket).build()); found = exitsBucket(bucket); return !found; } return false; } /** * 獲取某個(gè)桶下某個(gè)對(duì)象的URL * * @param bucket 桶名稱 * @param objectName 對(duì)象名 (文件夾名 + 文件名) * @return */ public static String getBucketObject(String bucket, String objectName) throws Exception { // 刪除之前先檢查`my-bucket`是否存在。 boolean found = exitsBucket(bucket); if (found) { return MinioConfig.getMinioClient().getObjectUrl(bucket, objectName); } return ""; } /** * 根據(jù)文件路徑得到預(yù)覽文件絕對(duì)地址 * * @param bucket 桶名稱 * @param objectName 對(duì)象名 (文件夾名+文件名) * @return */ public String getPreviewFileUrl(String bucket, String objectName) { try { return MinioConfig.getMinioClient().presignedGetObject(bucket, objectName); } catch (Exception e) { e.printStackTrace(); return ""; } } // public static void main(String[] args) { // // String bucket = "my-bucket-test01"; // String filename = System.currentTimeMillis() + "截圖.png"; // String fileFullPath = "C:\\Users\\Administrator\\Desktop\\截圖.png"; // // String fileUrl = putObjectLocalFile(bucket, filename, fileFullPath); // System.out.println(fileUrl); // } }
5.列出調(diào)用
上傳,下載,刪除接口代碼:寫(xiě)到Controller頁(yè)面即可
//上傳文件到minio @PostMapping(value = "fileUpload") public AjaxResult fileUpload( MultipartFile file){ try{ String sUrl = MinioUtils.putObject(file,"buckettest"); if(!sUrl.equals("")){ return AjaxResult.success("上傳成功。",sUrl); } else{ return AjaxResult.error("上傳失敗。"); } } catch (Exception e){ e.printStackTrace(); return AjaxResult.error("上傳失敗。"); } } //刪除文件 filelist 為數(shù)組格式 ,可以根據(jù)個(gè)人設(shè)置調(diào)整 @PostMapping(value = "/deleteFile") public AjaxResult deleteFile(@RequestBody HdRequestBody filelist){ Object list = filelist.getValueFromData("filelist"); List<String> fileList = new ArrayList<>(); if (list instanceof ArrayList<?>) { for (Object o : (List<?>) list) { fileList.add(String.class.cast(o)); } } boolean flag = MinioUtils.removeObjects("buckettest",fileList); return flag == true ? AjaxResult.success("刪除成功") : AjaxResult.error("刪除失敗"); } /** * 下載文件 * @param fileName * @param response * @return */ @PostMapping(value = "/downloadFile") public String downloadFile(@RequestParam String fileName, HttpServletResponse response) { return MinioUtils.fileDownload("buckettest",fileName,response) != null ? "下載成功" : "下載失敗"; }
以上操作后,即可解決minio服務(wù)的上傳,下載,刪除功能;
注:刪除屬于lazy方式,是延遲的,需要等會(huì)就可以看到minio服務(wù)器已經(jīng)刪除;
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot如何通過(guò)不同的策略動(dòng)態(tài)調(diào)用不同的實(shí)現(xiàn)類
這篇文章主要介紹了springboot如何通過(guò)不同的策略動(dòng)態(tài)調(diào)用不同的實(shí)現(xiàn)類,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02一篇文章教帶你了解Java Spring之自動(dòng)裝配
今天小編就為大家分享一篇關(guān)于Spring中的自動(dòng)裝配,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2021-09-09關(guān)于@SpringBootApplication詳解
這篇文章主要介紹了關(guān)于@SpringBootApplication的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08Springboot 2.x集成kafka 2.2.0的示例代碼
kafka近幾年更新非???,也可以看出kafka在企業(yè)中是用的頻率越來(lái)越高。本文主要為大家介紹了Springboot 2.x集成kafka 2.2.0的示例代碼,需要的可以參考一下2022-04-04java根據(jù)擴(kuò)展名獲取系統(tǒng)圖標(biāo)和文件圖標(biāo)示例
這篇文章主要介紹了java根據(jù)擴(kuò)展名獲取系統(tǒng)圖標(biāo)和文件圖標(biāo)示例,需要的朋友可以參考下2014-03-03Mybatis全局配置及映射關(guān)系的實(shí)現(xiàn)
本文主要介紹了Mybatis全局配置及映射關(guān)系的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03java Scanner輸入數(shù)字、字符串過(guò)程解析
這篇文章主要介紹了java Scanner輸入數(shù)字、字符串過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10