minio简单的上传下载及展示

最近在学习minio相关知识,小小的记录一下学习内容

MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。

MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。目前支持JavaScript 、Java、Python、Golang、.NET。

官网:https://min.io/    中文文档:http://www.minio.org.cn/

源码地址:https://github.com/minio/minio

由于使用的是windows10的电脑,因此下载的是windows版本的可查考官方提供文档进行操作https://min.io/download#/windows 

也可以直接下载可执行exehttps://dl.min.io/server/minio/release/windows-amd64/minio.exe

下载完成后不要不要双击minio.exe文件,在存放minio.exe文件夹中新建一个minioData文件夹,用来储存minio上传的文件目录,在地址栏里输入cmd按下回车键输入minio.exe server E:\minio\minioData(启动minio的命令)

 

 至此就可以在浏览器上进行创建bucket,文件的上传、下载、删除等一系列操作了。

使用springboot进行minio的相关操作,首先需要添加minio依耐

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.4</version>
</dependency>

 在yml或properties进行minio配置

minio:
  endpoint: http://192.168.1.102:9000 #Minio服务所在地址
  bucketName: test #存储桶名称(文件夹名称)
  accessKey: minioadmin #访问的key(类似用户名)
  secretKey: minioadmin #访问的秘钥(类似密码)

minio基本配置

@Component
@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {
    private String endpoint;
    private String bucketName;
    private String accessKey;
    private String secretKey;

}

简单的上传、下载文件及压缩包、查询列表等访问操作

@Slf4j
@RestController
@RequestMapping("/minio")
public class MinioController {
    @Autowired
    private MinioClient minioClient;
    
    @Autowired
    private MinioProperties minioProperties;

    private List<String> docList = new ArrayList<>();

    /**
     * 获取文件列表
     * @param map
     * @return
     * @throws Exception
     */
    @GetMapping("/list")
    public List<Object> list(ModelMap map) throws Exception {
        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder().bucket(minioProperties.getBucketName()).build();
        Iterable<Result<Item>> myObjects = minioClient.listObjects(listObjectsArgs);
//        Iterable<Result<Item>> myObjects = minioClient.listObjects(minioProperties.getBucketName());
        Iterator<Result<Item>> iterator = myObjects.iterator();
        List<Object> items = new ArrayList<>();
        String format = "{'fileName':'%s','fileSize':'%s'}";
        while (iterator.hasNext()) {
            Item item = iterator.next().get();
            items.add(JSON.parse(String.format(format, item.objectName(), formatFileSize(item.size()))));
        }
        return items;
    }

    /**
     * 查看所有的上传文件列表
     * @param pageNum
     * @param pageSize
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/fileList", method = RequestMethod.GET, produces = {"application/json;charset=utf-8"})
    public String getFileList(Integer pageNum, Integer pageSize) throws Exception {
        List<Bucket> buckets = minioClient.listBuckets();
        List<FileVo> list = new ArrayList<>();
        if (!buckets.isEmpty()) {
            for (int i = 0; i < buckets.size(); i++) {
                Bucket s = buckets.get(i);
                listDocs(s.name(),"", list);
            }
        }
        JSONObject res = new JSONObject();
        res.put("code", 200);
        res.put("message", "获取文件列表成功");
        // 按最后上传时间排序
        list.sort(new Comparator<FileVo>() {
            @Override
            public int compare(FileVo o1, FileVo o2) {
                return o2.getUpdateTime().compareTo(o1.getUpdateTime());
            }
        });
        // 分页
        List returnList = PageUtil.startPage(list, pageNum, pageSize);
        res.put("list", returnList);
        ObjectMapper mapper = new ObjectMapper();
        String s = mapper.writeValueAsString(res);
        return s;
    }

    public void listDocs(String bucketName,String prefix, List<FileVo> list){
        DecimalFormat df = new DecimalFormat("0.00");
        Iterable<Result<Item>> listObjects=new ArrayList<>();
        if(StringUtils.hasLength(prefix)){
            listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .prefix(prefix)
                    .build());
        }else {
            listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .build());
        }
        try{
            for (Result<Item> result : listObjects) {
                Item item = result.get();
                if(item.isDir()){
                    docList.add(item.objectName());
                    listDocs(bucketName,item.objectName(),list);
                }else{
                    FileVo fileVo = new FileVo();
                    fileVo.setBucketName(bucketName);  // 文件夹名称
                    String name = URLDecoder.decode(item.objectName(),"utf-8");
                    fileVo.setFileName(name);  // 文件名称
                    fileVo.setUpdateTime(localDateTime2Date(item.lastModified().toLocalDateTime()));  // 文件上传时间
                    Long size = item.size();
                    if (size > (1024 * 1024)) {
                        fileVo.setFileSize(df.format(((double) size / 1024 / 1024)) + "MB");  // 文件大小,如果超过1M,则把单位换成MB
                    } else if (size > 1024) {
                        fileVo.setFileSize(df.format(((double) size / 1024)) + "KB"); // 文件大小,如果没超过1M但是超过1000字节,则把单位换成KB
                    } else {
                        fileVo.setFileSize(size + "bytes");  // // 文件大小,如果没超过1000字节,则把单位换成bytes
                    }
                    list.add(fileVo);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public Iterable<Result<Item>> listObjects(String bucketName,String prefix,String title,boolean recursive){
        try {
            Iterable<Result<Item>> listObjects=new ArrayList<>();
            if(StringUtils.hasLength(title)){
                listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .startAfter(title)
                        .build());
            }
            else if(StringUtils.hasLength(prefix)){
                listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .recursive(recursive) // 递归
                        .build());
            }else {
                listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .recursive(recursive) // 递归
                        .build());
            }
            return listObjects;
        } catch (Exception e) {
            System.out.println("Error occurred: " + e);
            e.printStackTrace();
            return null;
        }
    }

    public Date localDateTime2Date( LocalDateTime localDateTime){
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        Date date = Date.from(zdt.toInstant());
        Calendar cal=Calendar.getInstance();
        cal.setTime(date);
        // 由于获取的时间存在时间差,我这里手动加上16小时
        cal.add(Calendar.HOUR_OF_DAY, 16);
        date = cal.getTime();
        return date;
    }


    /**
     * 上传文件
     * @param file 要上传的文件
     * @return
     */
    @PostMapping("/upload")
    public Res upload(@RequestParam(name = "file", required = false) MultipartFile[] file) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException, RegionConflictException, ServerException {
        Res res = new Res();
        res.setCode(500);

        if (file == null || file.length == 0) {
            res.setMessage("上传文件不能为空");
            return res;
        }

        //存入bucket不存在则创建,并设置为只读
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProperties.getBucketName()).build())){
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProperties.getBucketName()).build());
//        if (!minioClient.bucketExists(minioProperties.getBucketName())) {
//            minioClient.makeBucket(minioProperties.getBucketName());
            //minioClient.setBucketPolicy(minioProperties.getBucketName(), "*.*", PolicyType.READ_ONLY);
        }

        List<String> orgfileNameList = new ArrayList<>(file.length);

        for (MultipartFile multipartFile : file) {
            // 获取真实文件名
            String orgfileName = multipartFile.getOriginalFilename();
            // 父目录名
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            // 文件存储的目录结构
            String objectName = sdf.format(new Date()) + "/" + orgfileName;

            try {
                InputStream in = multipartFile.getInputStream();
                // 开始上传
                PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName).bucket(minioProperties.getBucketName()).contentType("application/octet-stream").stream(in,in.available(),-1).build();
                minioClient.putObject(objectArgs);
//                minioClient.putObject(minioProperties.getBucketName(), objectName, in, new PutObjectOptions(in.available(), -1));
                in.close();
                // 完成上传以后再保存文件完整路径
                String fullFilePath = minioProperties.getEndpoint() + "/" + minioProperties.getBucketName() + "/" + objectName;
                orgfileNameList.add(fullFilePath);
            } catch (Exception e) {
                log.error(e.getMessage());
                res.setMessage("上传失败");
                return res;
            }
        }

        Map<String, Object> data = new HashMap<String, Object>();
        data.put("bucketName", minioProperties.getBucketName());
        data.put("fileName", orgfileNameList);
        res.setCode(200);
        res.setMessage("上传成功");
        res.setData(data);
        return res;
    }

    /**
     * 将指定文件以压缩包下载
     * @param response
     * @param fileName 要下载的文件名
     */
    @RequestMapping("/downLoadZip")
    public void downLoadZip(HttpServletResponse response, @RequestParam("fileName") String fileName){
        ZipOutputStream zipos = null;
        DataOutputStream os = null;
        InputStream is = null;
        try {
            response.reset();
            String zipName = new String(URLEncoder.encode(fileName, "UTF-8").getBytes(), StandardCharsets.ISO_8859_1);
            response.setHeader("Content-Disposition", "attachment;fileName=\"" + zipName + ".zip\"");
            response.setContentType("application/octet-stream; charset=UTF-8");
            zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法
            try {
                zipos.putNextEntry(new ZipEntry(fileName));
                os = new DataOutputStream(zipos);
                GetObjectArgs getObjectArgs = GetObjectArgs.builder().object(fileName).bucket(minioProperties.getBucketName()).build();
                is = minioClient.getObject(getObjectArgs);
//                is = minioClient.getObject(minioProperties.getBucketName(), fileName);
                byte[] b = new byte[1024];
                int length = 0;
                while((length = is.read(b))!= -1){
                    os.write(b, 0, length);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            is.close();
            os.flush();
            os.close();
            zipos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (zipos != null) {
                try {
                    zipos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 将bucket下所有文件以压缩包下载
     * @param response
     * @param bucket 要下载的bucket
     */
    @RequestMapping("/batchDownLoadZip")
    public void batchDownLoadZip(HttpServletResponse response, @RequestParam("bucket") String bucket) {
        List<String> filePaths = new ArrayList<>();
        listZips(bucket,"2023",filePaths);
        ZipOutputStream zipos = null;
        DataOutputStream os = null;
        InputStream is = null;
        try {
            response.reset();
            String zipName = new String(URLEncoder.encode(bucket, "UTF-8").getBytes(), StandardCharsets.ISO_8859_1);
            response.setHeader("Content-Disposition", "attachment;fileName=\"" + zipName + ".zip\"");
            response.setContentType("application/octet-stream; charset=UTF-8");
            zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法
            for(int i = 0;i < filePaths.size();i++) {
                String file = filePaths.get(i);
                String packageName = filePaths.get(i).replace(bucket+"/", "");
                try {
                    zipos.putNextEntry(new ZipEntry(packageName));
                    os = new DataOutputStream(zipos);
                    GetObjectArgs getObjectArgs = GetObjectArgs.builder().object(file).bucket(minioProperties.getBucketName()).build();
                    is = minioClient.getObject(getObjectArgs);
                    byte[] b = new byte[1024];
                    int length = 0;
                    while((length = is.read(b))!= -1){
                        os.write(b, 0, length);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            is.close();
            os.flush();
            os.close();
            zipos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (zipos != null) {
                try {
                    zipos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 遍历bucket下所有文件名
     * @param bucketName 要下载的bucket
     * @param prefix 前缀
     * @param filePaths 文件名列表
     */
    public void listZips(String bucketName,String prefix, List<String> filePaths){
        Iterable<Result<Item>> listObjects=new ArrayList<>();
        if(StringUtils.hasLength(prefix)){
            listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .prefix(prefix)
                    .build());
        }else {
            listObjects = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .build());
        }
        try{
            for (Result<Item> result : listObjects) {
                Item item = result.get();
                if(item.isDir()){
                    listZips(bucketName,item.objectName(),filePaths);
                }else{
                    String name = URLDecoder.decode(item.objectName(),"utf-8");
                    filePaths.add(name);  // 文件名称
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 下载指定文件
     * @param response
     * @param fileName 要下载的文件名
     */
    @RequestMapping("/download")
    public void download(HttpServletResponse response, @RequestParam("fileName") String fileName) {
        InputStream in = null;
        try {
            String name = "";
            //文件名截取
            if(fileName.lastIndexOf("/") != -1 ){
                name = fileName.substring(fileName.lastIndexOf("/") + 1);
            }else{
                name = fileName;
            }
            StatObjectArgs statObjectArgs = StatObjectArgs.builder().object(fileName).bucket(minioProperties.getBucketName()).build();
//            ObjectStat stat = minioClient.statObject(minioProperties.getBucketName(), fileName);
            ObjectStat stat = minioClient.statObject(statObjectArgs);
            response.setContentType(stat.contentType());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name, "UTF-8"));

            GetObjectArgs getObjectArgs = GetObjectArgs.builder().object(fileName).bucket(minioProperties.getBucketName()).build();
//            in = minioClient.getObject(minioProperties.getBucketName(), fileName);
            in = minioClient.getObject(getObjectArgs);
            IOUtils.copy(in, response.getOutputStream());

        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
    }

    /**
     * 删除文件
     * @param fileName 要删除的文件名
     * @return
     */
    @DeleteMapping("/delete")
    public Res delete(@RequestParam("fileName") String fileName) {
        Res res = new Res();
        res.setCode(200);
        try {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().object(fileName).bucket(minioProperties.getBucketName()).build();
            minioClient.removeObject(removeObjectArgs);
//            minioClient.removeObject(minioProperties.getBucketName(), fileName);
        } catch (Exception e) {
            res.setCode(500);
            log.error(e.getMessage());
        }
        return res;
    }


    /**
     * 生成可以预览的文件链接
     * @return
     * @throws XmlParserException
     * @throws NoSuchAlgorithmException
     * @throws InsufficientDataException
     * @throws InternalException
     * @throws InvalidResponseException
     * @throws InvalidKeyException
     * @throws InvalidBucketNameException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws InvalidExpiresRangeException
     */
    @GetMapping("/previewList")
    public List<Object> getPreviewList() throws XmlParserException, NoSuchAlgorithmException, InsufficientDataException, InternalException, InvalidResponseException, InvalidKeyException, InvalidBucketNameException, ErrorResponseException, IOException, InvalidExpiresRangeException, ServerException {
        ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder().bucket(minioProperties.getBucketName()).build();
        Iterable<Result<Item>> myObjects = minioClient.listObjects(listObjectsArgs);
//        Iterable<Result<Item>> myObjects = minioClient.listObjects(minioProperties.getBucketName());
        Iterator<Result<Item>> iterator = myObjects.iterator();
        List<Object> items = new ArrayList<>();
        String format = "{'fileName':'%s'}";
        while (iterator.hasNext()) {
            Item item = iterator.next().get();
            // TODO 根据文件后缀名,过滤哪些是可以预览的文件
            //String bucketName, 桶名称
            // String objectName, 文件路径
            // Integer expires, 链接过期时间
            // Map<String, String> reqParams 请求参数
            // 开始生成
            String filePath = minioClient.presignedGetObject(minioProperties.getBucketName(), item.objectName());
            items.add(JSON.parse(String.format(format, filePath)));
        }
        return  items;
    }



    /**
     * 显示文件大小信息单位
     * @param fileS
     * @return
     */
    private static String formatFileSize(long fileS) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        String wrongSize = "0B";
        if (fileS == 0) {
            return wrongSize;
        }
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + " B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + " KB";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + " MB";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + " GB";
        }
        return fileSizeString;
    }
}

此项目demo已上传gitee,jdk使用的是17,下载地址:https://gitee.com/jameszj/springboot-minio-demo.git

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值