springboot如何整合minio呢?
下文笔者讲述SpringBoot中整合minio的方法及示例分享,如下所示
SpringBoot整合minio的实现思路
1.添加依赖 2.设置相应的配置文件 3.编写minio配置类 4.编写minio工具类 5.编写控制器代码例:SpringBoot使用minio的示例
第一步:添加依赖
<dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.4.3</version> </dependency>
第二步:application.yml配置
spring: # 配置文件上传大小限制 servlet: multipart: max-file-size: 200MB max-request-size: 200MB minio: endpoint: http://127.0.0.1:9005 accessKey: minioadmin secretKey: minioadmin bucketName: java265-simple
第三步:编写minio配置类
@Configuration public class MinioClientConfig { @Value("${minio.endpoint}") private String endpoint; @Value("${minio.accessKey}") private String accessKey; @Value("${minio.secretKey}") private String secretKey; /** * 注入minio 客户端 * @return */ @Bean public MinioClient minioClient() { return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } }
第四步:minio工具类
@Slf4j @Component public class MinioUtil { @Resource private MinioClient minioClient; @Value("${minio.bucketName}") private String bucketName; 桶操作 / /** * 查看bucket是否存在 * @return boolean */ public boolean bucketExists(String bucketName) { try { return minioClient.bucketExists(BucketExistsArgs.builder() .bucket(bucketName) .build()); } catch (Exception e) { log.error("查看bucket是否存在", e); return false; } } /** * 创建存储bucket * @return Boolean */ public boolean createBucket(String bucketName) { if (bucketExists(bucketName)) { return true; } try { minioClient.makeBucket(MakeBucketArgs.builder() .bucket(bucketName) .build()); return true; } catch (Exception e) { log.error("创建桶失败", e); return false; } } /** * 删除存储bucket * * @return boolean */ public boolean removeBucket(String bucketName) { if (!bucketExists(bucketName)) { return true; } //获取桶中所有的对象 list<Item> items = getBucketObjects(bucketName); if (items.size() > 0) { //有对象文件,则删除失败 return false; } try { minioClient.removeBucket(RemoveBucketArgs.builder() .bucket(bucketName) .build()); return true; } catch (Exception e) { log.error("根据名称删除桶失败", e); return false; } } /** * 获取存储桶策略 * * @param bucketName 存储桶名称 * @return json */ public String getBucketPolicy(String bucketName) { String bucketPolicy = null; try { bucketPolicy = minioClient.getBucketPolicy(GetBucketPolicyArgs.builder() .bucket(bucketName) .build()); } catch (Exception e) { log.error("获取存储桶策略失败", e); } return bucketPolicy; } /** * 根据bucketName获取信息 * * @param bucketName bucket名称 * * return 如果不存在返回null */ public Bucket getBucket(String bucketName) { try { return minioClient.listBuckets() .stream() .filter(b -> b.name().equals(bucketName)) .findFirst() .orElse(null); } catch (Exception e) { log.error("根据bucketName获取桶信息", e); } return null; } /** * 获取全部bucket */ public List<Bucket> getAllBuckets() { try { return minioClient.listBuckets(); } catch (Exception e) { log.error("获取所有的桶信息", e); } return null; } /** * 创建文件夹或目录 * * @param directoryName 目录路径 */ public boolean createDirectory(String bucketName, String directoryName) { if (!bucketExists(bucketName)) { createBucket(bucketName); } try { minioClient.putObject(PutObjectArgs.builder() .bucket(bucketName) .object(directoryName) .stream(new ByteArrayInputStream(new byte[]{}), 0, -1) .build()); return true; } catch (Exception e) { log.error("创建文件夹或目录失败", e); return false; } } / 文件操作 /// /** * 判断文件是否存在 * * @param bucketName 存储桶 * @param objectName 对象 * @return 存在返回true,不存在发生异常返回false */ public boolean objectExist(String bucketName, String objectName) { if (!bucketExists(bucketName)) { return false; } try { minioClient.statObject(StatObjectArgs.builder() .bucket(bucketName) .object(objectName) .build()); return true; } catch (Exception e) { log.error("判断文件是否存在失败", e); return false; } } /** * 判断文件夹是否存在【注意是文件夹而不是目录】 * @param folderName 文件夹名称(去掉前后的/) * @return */ public boolean folderExist(String bucketName, String folderName) { if (!bucketExists(bucketName)) { return false; } try { Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder() .bucket(bucketName) .prefix(folderName) .recursive(false) .build()); if (results != null) { for (Result<Item> result : results) { Item item = result.get(); folderName += "/"; if (item.isDir() && folderName.equals(item.objectName())) { return true; } } } } catch (Exception e) { log.error("判断文件夹是否存在失败", e); return false; } return false; } /** * 文件上传 * @param multipartFile 待上传文件 * @param folderName 目录 * @param aimFileName 最终保存到minio中的文件名,不需要后缀 * @return */ public String putObject(String bucketName, MultipartFile multipartFile, String folderName, String aimFileName) { if (!bucketExists(bucketName)) { createBucket(bucketName); } if (!StringUtils.hasText(aimFileName)) { aimFileName = UUID.randomUUID().toString(); } //获取文件后缀 String originalFilename = multipartFile.getOriginalFilename(); String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); aimFileName += suffix; //带路径的文件名 String lastFileName = ""; if (StringUtils.hasText(folderName)) { lastFileName = "/" + folderName + "/" + aimFileName; } else { lastFileName = aimFileName; } try (InputStream inputStream = multipartFile.getInputStream();) { //上传文件到指定目录,文件名称相同会覆盖 minioClient.putObject(PutObjectArgs.builder() .bucket(bucketName) .object(lastFileName) .stream(inputStream, multipartFile.getSize(), -1) .contentType(multipartFile.getContentType()) .build()); return getObjectUrl(bucketName, lastFileName); } catch (Exception e) { log.error("文件上传失败", e); return null; } } /** * 上传文件【不指定文件夹】 * @param multipartFile * @param fileName * @return */ public String putObject(String bucketName, MultipartFile multipartFile, String fileName) { return putObject(bucketName, multipartFile, null, fileName); } /** * 上传文件【不指定文件夹,不指定目标文件名】 * @param multipartFile * @return */ public String putObject(String bucketName, MultipartFile multipartFile) { return putObject(bucketName, multipartFile, null, null); } /** * 自动创建桶并存储文件 * * @param inputStream * @param aimFileName 必须,minio桶中文件的名字,需要带后缀 * @return */ public String putObject(String bucketName, InputStream inputStream, String aimFileName) { if (!bucketExists(bucketName)) { createBucket(bucketName); } try { PutObjectArgs putObjectArgs = PutObjectArgs.builder() .bucket(bucketName) .object(aimFileName) .stream(inputStream, inputStream.available(), -1) .build(); minioClient.putObject(putObjectArgs); inputStream.close(); return getObjectUrl(bucketName, aimFileName); } catch (Exception e) { log.error("文件上传失败", e); return null; } } /** * 拷贝文件 * * @param bucketName bucket名称 * @param objectName 文件名称 * @param srcBucketName 目标bucket名称 * @param srcObjectName 目标文件名称 */ public boolean copyObject(String srcBucketName, String srcObjectName, String bucketName, String objectName) { try { minioClient.copyObject( CopyObjectArgs.builder() .source(CopySource.builder() .bucket(srcBucketName) .object(srcObjectName) .build()) .bucket(bucketName) .object(objectName) .build()); return true; } catch (Exception e) { log.error("拷贝文件失败", e); return false; } } /** * 文件下载 * @param fileName 文件名称 * @param response response * @return Boolean */ public void getObject(String bucketName, String fileName, HttpServletResponse response) { if (!bucketExists(bucketName)) { return; } GetObjectArgs getObjectArgs = GetObjectArgs.builder() .bucket(bucketName) .object(fileName) .build(); try (ServletOutputStream outputStream = response.getOutputStream(); GetObjectResponse objectResponse = minioClient.getObject(getObjectArgs)) { response.setCharacterEncoding("utf-8"); //设置强行下载不打开 //response.setContentType("application/force-download"); //response.setContentType("APPLICATION/OCTET-STREAM"); response.addHeader("Content-Disposition", "attachment;filename=" + fileName); ByteStreams.copy(objectResponse, outputStream); outputStream.flush(); } catch (Exception e) { log.error("文件下载失败", e); } } /** * 以流的形式获取一个文件对象 * * @param objectName 对象名称 * @return {@link InputStream} */ public InputStream getObject(String bucketName, String objectName) { if (!bucketExists(bucketName)) { return null; } try { StatObjectResponse statObjectResponse = minioClient.statObject(StatObjectArgs.builder() .bucket(bucketName) .object(objectName) .build()); if (statObjectResponse.size() > 0) { // 获取objectName的输入流。 return minioClient.getObject(GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .build()); } } catch (Exception e) { log.error("文件下载失败", e); } return null; } /** * 获取文件信息, 如果抛出异常则说明文件不存在 * * @param objectName 文件名称 */ public StatObjectResponse getObjectInfo(String bucketName, String objectName) { if (!bucketExists(bucketName)) { return null; } StatObjectResponse statObjectResponse = null; try { statObjectResponse = minioClient.statObject(StatObjectArgs.builder() .bucket(bucketName) .object(objectName) .build()); } catch (Exception e) { log.error("获取文件信息失败", e); } return statObjectResponse; } /** * 获取图片的路径 * * @param fileName * @return */ public String getObjectUrl(String bucketName, String fileName) { try { if (fileName.startsWith("/")) { fileName = fileName.substring(1); } GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder() .bucket(bucketName) .object(fileName) .method(Method.GET) //过期时间(分钟数) .expiry(60 * 60) .build(); return minioClient.getPresignedObjectUrl(build); } catch (Exception e) { log.error("获取文件路径失败", e); } return null; } /** * 断点下载 * * @param objectName 文件名称 * @param offset 起始字节的位置 * @param length 要读取的长度 * @return 流 */ public InputStream getObject(String bucketName, String objectName, long offset, long length) { if (!bucketExists(bucketName)) { return null; } GetObjectResponse objectResponse = null; try { objectResponse = minioClient.getObject(GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .offset(offset) .length(length) .build()); } catch (Exception e) { e.printStackTrace(); } return objectResponse; } /** * 获取指定桶中的所有文件对象 * * @return 存储bucket内文件对象信息 */ public List<Item> getBucketObjects(String bucketName) { if (!bucketExists(bucketName)) { return null; } List<Item> items = new ArrayList<>(); Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder() .bucket(bucketName) .build()); if (results != null) { try { for (Result<Item> result : results) { items.add(result.get()); } } catch (Exception e) { log.error("获取指定桶中的所有文件对象", e); } } return items; } /** * 获取路径下文件列表 * * @param prefix 路径名称 * @param recursive 是否递归查找,如果是false,就模拟文件夹结构查找 * @return 二进制流 */ public Iterable<Result<Item>> getObjects(String bucketName, String prefix, boolean recursive) { if (!bucketExists(bucketName)) { return null; } Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder() .bucket(bucketName) .prefix(prefix) .recursive(recursive) .build()); return results; } /** * 根据文件前置查询文件 * * @param prefix 前缀 * @param recursive 是否递归查询 * @return MinioItem 列表 */ public List<Item> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) { if (!bucketExists(bucketName)) { return null; } List<Item> items = new ArrayList<>(); Iterable<Result<Item>> objectsIterator = minioClient.listObjects( ListObjectsArgs.builder() .bucket(bucketName) .prefix(prefix) .recursive(recursive) .build()); if (objectsIterator != null) { try { for (Result<Item> o : objectsIterator) { Item item = o.get(); items.add(item); } } catch (Exception e) { e.printStackTrace(); } } return items; } /** * 删除文件 * @param fileName 文件名 * @return * @throws Exception */ public boolean removeObject(String bucketName, String fileName) { if (!bucketExists(bucketName)) { return false; } try { minioClient.removeObject(RemoveObjectArgs.builder() .bucket(bucketName) .object(fileName) .build()); return true; } catch (Exception e) { log.error("根据文件删除文件失败", e); return false; } } /** * 批量删除文件对象【没有测试成功】 * @param objects 需要删除的文件列表 */ public boolean removeObjects(String bucketName, String... objects) { if (!bucketExists(bucketName)) { return false; } List<DeleteObject> deleteObjects = new LinkedList<>(); Arrays.stream(objects).forEach(s -> { deleteObjects.add(new DeleteObject(s)); }); Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder() .bucket(bucketName) .objects(deleteObjects) .build()); //Minio处理批量删除的时候, 采用的延迟执行, 需要通过迭代返回的Iterable<Result<DeleteError>>以执行删除 if (results != null) { try { for (Result<DeleteError> result : results) { DeleteError error = result.get(); log.error("Error in deleting object " + error.objectName() + "; " + error.message()); } } catch (Exception e) { log.error("批量删除文件失败", e); } } return true; } }
第五步:Controller编写
@RestController @RequestMapping("/minio") public class MinioController { @Resource private MinioUtil minioUtil; /** * 添加桶 */ @GetMapping(value = "/create/{bucketName}") public String create(@PathVariable("bucketName") String bucketName) { minioUtil.createBucket(bucketName); return "创建成功"; } /** * 检查桶是否存在 */ @GetMapping(value = "/exist/{bucketName}") public String exist(@PathVariable("bucketName") String bucketName) { boolean exists = minioUtil.bucketExists(bucketName); return "存在:" + exists; } /** * 删除桶 */ @GetMapping(value = "/remove/{bucketName}") public String remove(@PathVariable("bucketName") String bucketName) { boolean res = minioUtil.removeBucket(bucketName); return "删除:" + res; } /** * 获取所有的桶 * @return */ @GetMapping(value = "/getAllBuckets") public List<Bucket> getAllBuckets() { List<Bucket> allBuckets = minioUtil.getAllBuckets(); return allBuckets; } /** * 上传图片,直接上传的跟目录 * @param file * @return */ @PostMapping("/upload1") public String upload1(MultipartFile file) { if (file.isEmpty() || file.getSize() == 0) { return "文件为空"; } try { String newName = ""; String fileUrl = minioUtil.putObject("java265-simple", file, newName); return fileUrl; } catch (Exception e) { e.printStackTrace(); return "上传失败"; } } /** * 上传图片,指定上传到的目录及重命名 * @param file * @return */ @PostMapping("/upload2") public String upload2(MultipartFile file) { if (file.isEmpty() || file.getSize() == 0) { return "文件为空"; } try { String newName = "静静"; String fileUrl = minioUtil.putObject("java265-simple", file, "haha/xixi", newName); return fileUrl; } catch (Exception e) { e.printStackTrace(); return "上传失败"; } } /** * 获取图片的路径【带问号后面的内容】 * @param filename * @return */ @GetMapping("/get1/{filename}") public String getPic1(@PathVariable("filename") String filename) { String fileUrl = minioUtil.getObjectUrl("java265-info",filename); return fileUrl; } /** * 获取图片的路径【不带问号后面的坐标】 * @param filename * @return */ @GetMapping("/get2/{filename}") public String getPic2(@PathVariable("filename") String filename) { String fileUrl = minioUtil.getObjectUrl("java265-info",filename); fileUrl = fileUrl.substring(0, fileUrl.indexOf("?")); return fileUrl; } /** * 删除图片【不带路径】 localhost/java265/minio/delete1/lisi.jpg * @param filename * @return */ @DeleteMapping("/delete1/{filename}") public String delete1(@PathVariable("filename") String filename) { boolean remove = minioUtil.removeObject("java265-simple",filename); return remove ? "删除成功" : "失败"; } /** * 删除图片【带路径】 localhost/java265/minio/delete2?filename=aa/lisi.jpg * @param filename * @return */ @DeleteMapping("/delete2") public String delete2(String filename) { boolean remove = minioUtil.removeObject("java265-simple",filename); return remove ? "删除成功" : "失败"; } /** * 批量删除,localhost/java265/minio/delete3?filename=aa.jpg&filename=bb.jpg * @param filename * @return */ @DeleteMapping("/delete3") public String delete3(String... filename) { boolean remove = minioUtil.removeObjects("java265-simple",filename); return remove ? "删除成功" : "失败"; } @GetMapping("/getBucketObjects") public List<Item> getBucketObjects() { List<Item> bucketObjects = minioUtil.getBucketObjects("java265-simple"); return bucketObjects; } /** * 下载图片 * @param filename */ @GetMapping("/download/{filename}") public void downloadPic(@PathVariable("filename") String filename) { InputStream is = minioUtil.getObject("java265-simple",filename); byte[] buffer = new byte[1024]; int len = -1; try { FileOutputStream fos = new FileOutputStream("aa32.jpg"); while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } fos.flush(); } catch (IOException e) { e.printStackTrace(); } } /** * 下载图片 * @param filename */ @GetMapping("/download2/{filename}") public void downloadPic2(@PathVariable("filename") String filename, HttpServletResponse response) { minioUtil.getObject("java265-simple",filename, response); } }
第六步:启动项目 测试Controller
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。