MinIO 文件服务器使用笔记

官网SDK没更新,真坑啊,都是不能用和过期的

看的大佬的文章,讲的特别清楚:https://www.jianshu.com/p/913a069e755a

根据自己需求简单处理记录

配置文件

spring:
  application:
    name: aaa
  minio:
    configs:
      #你搭建的MinIO服务器地址
      minIOUrl: http://22.22.22.22:8080
      #你搭建的MinIO服务器账号
      accessKey: M9999		
       #你搭建的MinIO服务器密码
      secretKey: 123456
      #文件大小 单位M
      maxFileSize: 10
      #签名有效时间  单位秒
      expires: 36000
      #后端接口地址
      serviceUrl: https://zheshihaowangzhan.org.cn
  gateway:
    httpUrl: http://192.168.1.13:10004

配置文件映射实体类

@Data
@Component
@ConfigurationProperties(prefix = "spring.minio.configs")
public class MinIoFileProperties {
    private String minIOUrl;
    private String accessKey;
    private String secretKey;
    private Integer maxFileSize;
    private Integer expires;
    private String serviceUrl;
}

封装工具类


public class MinIoFileUtil {

    private static final Logger logger = LoggerFactory.getLogger(Threads.class);


    private static final String NAME_HEAD = "J";
    private static final String CONTENT_TYPE = "image/jpeg";
    //MinIO服务的URL
    private String minIOUrl;
    //Access key
    private String accessKey;
    //Secret key
    private String secretKey;
    //存储桶名称
    private String bucketName;
    //文件大小(最大)
    private Integer maxFileSize = 10;
    //签名有效时间  单位秒
    private Integer expires;

    private MinioClient client;

    /**
     * 桶占位符
     */
    private static final String BUCKET_PARAM = "${bucket}";
    /**
     * bucket权限-读写
     */
    private static final String READ_WRITE = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";


    public MinIoFileUtil() {
        this.client = getMinioClient();
    }


    public MinIoFileUtil(String bucketName, MinIoFileProperties minIoFileProperties) {
        this.minIOUrl = minIoFileProperties.getMinIOUrl();
        this.accessKey = minIoFileProperties.getAccessKey();
        this.secretKey = minIoFileProperties.getSecretKey();
        this.bucketName = bucketName;
        this.maxFileSize = minIoFileProperties.getMaxFileSize();
        this.expires = minIoFileProperties.getExpires();
        this.client = getMinioClient();
    }

    private MinioClient getMinioClient() {
        return MinioClient.builder().endpoint(this.minIOUrl).credentials(this.accessKey, this.secretKey).build();
    }

    /**
     * 获取文件签名url
     *
     * @param fileName 文件名称
     * @return 文件签名地址
     */
    public String getSignedUrl(String fileName) throws Exception {
        if (StringUtils.isBlank(fileName)) {
            throw new CustomException("文件名称不能为空");
        }
        MinioClient client = MinioClient.builder().endpoint(this.minIOUrl).credentials(accessKey, secretKey).build();
        return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(getFileName(fileName)).expiry(expires).build());
    }

    /**
     * 根据图片路径
     *
     * @param response
     * @param imgUrl   网络(服务器)图片路径
     */
    public void getFileIO(HttpServletResponse response, String imgUrl) throws IOException {
        OutputStream out = null;
        InputStream inputStream = null;
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(imgUrl).openConnection();
            connection.setReadTimeout(5000);
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                inputStream = connection.getInputStream();
                response.setContentType("image/jpeg");
                out = response.getOutputStream();
                //读取文件流
                int len = 0;
                byte[] buffer = new byte[1024 * 10];
                while ((len = inputStream.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
                out.flush();
            }
        } catch (IOException e) {
            System.out.println("获取图片出现异常,图片路径为:" + imgUrl);
            e.printStackTrace();
        } finally {
            if (null != out) {
                out.close();
            }
            if (null != inputStream) {
                inputStream.close();
            }
        }

    }

    /**
     * 返回文件URL
     *
     * @return
     */
    public String setFile(MultipartFile multipartFile) throws Exception {
        return uploadFiles(setFileName(null, multipartFile), fileVerify(multipartFile));
    }


    /**
     * 返回文件名称
     *
     * @return
     */
    public String upFile(MultipartFile multipartFile) throws Exception {
        String fileName = setFileName(null, multipartFile);
        uploadFiles(fileName, fileVerify(multipartFile));
        return fileName;
    }


    /**
     * 返回文件URL
     *
     * @param fileName    图片名称
     * @param inputStream
     * @return
     */
    public String setFile(String fileName, InputStream inputStream) throws Exception {
        if (StringUtils.isBlank(fileName)) {
            throw new CustomException("文件名称不能为空");
        }
        return uploadFiles(fileName, inputStream);
    }

    /**
     * 返回文件URL
     *
     * @param fileName      图片名称
     * @param multipartFile 文件
     * @return 文件路径字符串(不可直接访问)
     * @throws IOException
     */
    public String setFile(String fileName, MultipartFile multipartFile) throws Exception {
        return uploadFiles(setFileName(fileName, multipartFile), fileVerify(multipartFile));
    }


    /**
     * 文件校验
     */
    private InputStream fileVerify(MultipartFile multipartFile) throws IOException {
        if (null == multipartFile) {
            throw new CustomException("请选择文件");
        }
        // 文件不大于10M
        if (!checkFileSize(multipartFile.getSize(), this.maxFileSize, "M")) {
            throw new CustomException("文件大小超限制");
        }
        return multipartFile.getInputStream();
    }


    /**
     * 上传文件 (流的形式)
     *
     * @return
     */
    private String uploadFiles(String fileName, InputStream inputStream) throws Exception {
        makeBucket(client, this.bucketName);
        //设置桶的读写权限
        client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(READ_WRITE.replace(BUCKET_PARAM, bucketName)).build());

        client.putObject(PutObjectArgs.builder().bucket(this.bucketName).object(fileName).stream(inputStream, inputStream.available(), -1)
                .contentType(CONTENT_TYPE).build());
        return getObjectPrefixUrl(this.bucketName) + fileName;

    }

    /**
     * 校验创建桶
     *
     * @param bucketName 桶
     */
    private static void makeBucket(MinioClient minioClient, String bucketName) throws Exception {
        // 判断桶是否存在
        boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (!isExist) {
            logger.info("存储桶{}不存在", bucketName);
            // 新建桶
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            logger.info("新建存储桶{}", bucketName);
        }
    }


    /**
     * 删除文件
     *
     * @param fileNames
     * @return
     */
    public boolean deleteFile(String... fileNames) {
        return this.deleteToAll(Arrays.asList(fileNames));
    }

    public boolean deleteFile(List<String> fileNames) {
        return this.deleteToAll(fileNames);
    }

    private Boolean deleteToAll(List<String> fileNames) {
        List<DeleteObject> deleteObjects = new ArrayList<>(fileNames.size());
        for (String fileName : fileNames) {
            String name = getFileName(fileName);
            deleteObjects.add(new DeleteObject(name));
        }
        Iterable<Result<DeleteError>> results = client.removeObjects(
                RemoveObjectsArgs.builder()
                        .bucket(bucketName)
                        .objects(deleteObjects)
                        .build()
        );
        for (Result<DeleteError> result : results) {
            DeleteError error = null;
            try {
                error = result.get();
            } catch (ErrorResponseException e) {
                e.printStackTrace();
            } catch (InsufficientDataException e) {
                e.printStackTrace();
            } catch (InternalException e) {
                e.printStackTrace();
            } catch (InvalidBucketNameException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (InvalidResponseException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (ServerException e) {
                e.printStackTrace();
            } catch (XmlParserException e) {
                e.printStackTrace();
            }
            logger.error(
                    "Error in deleting object " + error.objectName() + "; " + error.message());
        }
        return !results.iterator().hasNext();
    }

    /**
     * 文件url前半段
     *
     * @param bucket 桶
     * @return 前半段
     */
    private String getObjectPrefixUrl(String bucket) {
        return String.format("%s/%s/", this.minIOUrl, bucket);
    }


    private static String setFileName(String fileName, MultipartFile multipartFile) {
        if (StringUtils.isNotBlank(fileName)) {
            return fileName;
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String[] originalFilename = multipartFile.getOriginalFilename().split("\\.");
        return NAME_HEAD + simpleDateFormat.format(new Date()) + getRandom() + "." + originalFilename[originalFilename.length - 1];
    }

    private static int getRandom() {
        double ran = Math.random() * 9000 + 1000;
        return (int) ran;
    }


    /**
     * 判断文件大小
     *
     * @param len  文件长度
     * @param size 限制大小
     * @param unit 限制单位(B,K,M,G)
     * @return
     */
    public static boolean checkFileSize(Long len, int size, String unit) {
//        long len = file.length();
        double fileSize = 0;
        if ("B".equals(unit.toUpperCase())) {
            fileSize = (double) len;
        } else if ("K".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1024;
        } else if ("M".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1048576;
        } else if ("G".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1073741824;
        }
        if (fileSize > size) {
            return false;
        }
        return true;
    }


    /**
     * 处理文件名称(当fileName 不是文件名称为文件存储路径地址时)
     *
     * @return
     */
    public static String getFileName(String fileName) {
        if (fileName.contains("/")) {
            String[] split = fileName.split("/");
            return split[split.length - 1];
        } else {
            return fileName;
        }
    }
}


调用


@Slf4j
@RestController
@RequestMapping("/digitization/minIoFile")
@Api(value = "Web - MinioFileDisposeController", tags = {"获取、查看文件"})
public class MinioFileDisposeController extends BaseController {


    public final static String SERVICE_UTL = "/digitization/minIoFile/getFile/io/";
    @Autowired
    private MinIoFileProperties minIoFileProperties;

    @PostMapping("/getFileUrl")
    @ApiOperation(value = "获取访问路径")
    public AjaxResult getFileUrl(@RequestBody MinIoFileDto minIoFileDto) throws Exception {
        log.info("getFileUrl获取图片访问路径 minIoFileDto={}", JSON.toJSONString(minIoFileDto));
        MinIoFileUtil minIoFileUtil = new MinIoFileUtil(minIoFileProperties.getBucketName(), minIoFileProperties);
        String imgUrl = minIoFileUtil.getSignedUrl(minIoFileDto.getFileNameOrUrl());
        logger.info(" 图片路径为{}", imgUrl);
        return AjaxResult.success("", imgUrl);
    }

    /**
     * 上传图片/文件
     */
    @ApiOperation(value = "上传图片/文件")
    @PostMapping(value = "/setFile")
    public AjaxResult getInfo(MultipartFile file) throws Exception {
        log.info(" setFile上传图片 ");
        MinIoFileUtil minIoFileUtil = new MinIoFileUtil(minIoFileProperties.getBucketName(), minIoFileProperties);
//        return AjaxResult.success("", httpUrl + IMG_UTL + minIoFileUtil.upFile(file));
        System.out.println(minIoFileProperties.getServiceUrl());
        System.out.println(SERVICE_UTL);
        String s = minIoFileUtil.upFile(file);
        System.out.println(s);
        System.out.println(minIoFileProperties.getServiceUrl() + SERVICE_UTL + s);
        return AjaxResult.success("", minIoFileProperties.getServiceUrl() + SERVICE_UTL + s);
    }


    /**
     * 根据图片名称返回图片流
     *
     * @param fileName
     * @return
     * @throws Exception
     */
    @GetMapping(value = "/getFile/io/{fileName}")
    @ApiOperation(value = "根据图片/文件名称返回流")
    public void getFile(@PathVariable String fileName, HttpServletResponse response) throws Exception {
        log.info(" getFileIO 根据图片名称返回图片流,名称{}", fileName);
        MinIoFileUtil minIoFileUtil = new MinIoFileUtil(minIoFileProperties.getBucketName(), minIoFileProperties);
        String imgUrl = minIoFileUtil.getSignedUrl(fileName);
        minIoFileUtil.getFileIO(response, imgUrl);
    }


    /**
     * 根据图片名称返回图片流
     *
     * @param fileName
     * @return
     * @throws Exception
     */
    @GetMapping(value = "/deleteFile")
    @ApiOperation(value = "删除图片/文件")
    public AjaxResult delete(@RequestParam("fileName") String fileName) throws Exception {
        log.info(" deleteFile 删除图片/文件,名称{}", fileName);
        MinIoFileUtil minIoFileUtil = new MinIoFileUtil(minIoFileProperties.getBucketName(), minIoFileProperties);
        boolean flag = minIoFileUtil.deleteFile(fileName);
        return AjaxResult.success(flag);
    }

}
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值