java之minio文件服务器的日常操作
作者:violetlength
本文介绍如何在Java项目中配置Minio服务,通过创建minioConfig和minioDto来管理连接信息,并通过minioUtils工具类实现文件的上传、下载和删除功能,详细说明了如何从application.yml文件中读取配置,并强调了避免static情况下minioDto为null的问题,另外,提到删除操作是延迟的
1.java项目结构
如下所示:
增加minioConfig配置,服务连接使用minioDto(包含endpoint,accesskey,serectkey)
2.minioDto代码
如下所示:
数据引用,从application.yml中的minio节点获取;
@Data @Component @ConfigurationProperties(prefix = "minio") public class minioDto { private String endpoint; private String accesskey; private String secretkwy; }
application.yml中的minio节点如下:
minio: endpoint: http://192.168.0.147:9000 //该地址为minio服务器的9000接口,api使用 accesskey: miniominio secretkwy: miniominio
3.minioConfig代码
如下所示:
此种设置,可以避免直接注册static的情况(static情况时minioDto为null,会造成接口调用失败)
/** * @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.创建minioUtils工具类
根据需要,使用相关方法即可
/** * Minio客户端工具类 */ @SuppressWarnings("ALL") public class MinioUtils { private static final Logger log = LoggerFactory.getLogger(DbUtils.class); /** * 创建文件桶(建议租户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 + "-不存在"); } //上传目录为当前日期时间 String datedir = DateUtils.format(new Date(),"yyyyMMddHHmmss"); MinioConfig.getMinioClient() .uploadObject( UploadObjectArgs.builder().bucket(bucket).object(datedir + "//" + 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(); //上传目录为当前日期时间 String datedir = DateUtils.format(new Date(),"yyyyMMdd"); PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(datedir + "//" + 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(); } } } /** * 自动创建桶并存储文件 * * @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; // 生成时间戳防止重名 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; } /** * 自动创建桶并存储文件 * * @return */ public static String putObjectStream(MultipartFile file, String bucket) throws Exception { //判断文件是否为空 if (null == file || 0 == file.getSize()) { throw new ServiceException("上传minio文件服务器错误,上传文件为空"); } boolean exsit = exitsBucket(bucket); if (!exsit) { //makeBucketPolicy(bucket); log.error(bucket + "-不存在"); throw new ServiceException("minio文件服务器:" + bucket + " 桶不存在"); } //文件名 String originalFilename = file.getOriginalFilename(); //新的文件名 = 时间戳_随机数.后缀名 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 对象名称 * @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 对象名称 * @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; } /** * 获取单个桶中的所有文件对象名称 * * @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; } /** * 以流的形式获取一个文件对象 * * @param bucket 桶名称 * @param objectName 对象名称 * @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(); // 获取文件对象 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(); } } } /** * 删除一个桶 * * @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(); //有对象文件,则删除失败 if (item.size() > 0) { return false; } } // 删除`bucketName`存储桶,注意,只有存储桶为空时才能删除成功。 MinioConfig.getMinioClient().removeBucket(RemoveBucketArgs.builder().bucket(bucket).build()); found = exitsBucket(bucket); return !found; } return false; } /** * 获取某个桶下某个对象的URL * * @param bucket 桶名称 * @param objectName 对象名 (文件夹名 + 文件名) * @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 ""; } /** * 根据文件路径得到预览文件绝对地址 * * @param bucket 桶名称 * @param objectName 对象名 (文件夹名+文件名) * @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.列出调用
上传,下载,删除接口代码:写到Controller页面即可
//上传文件到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 为数组格式 ,可以根据个人设置调整 @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服务的上传,下载,删除功能;
注:删除属于lazy方式,是延迟的,需要等会就可以看到minio服务器已经删除;
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。