zoukankan      html  css  js  c++  java
  • MinIO的简单使用实践

    MinIO是一款高性能高可用的文件系统服务,可以用来替换FastDFS,这里介绍一下简单安装与使用。部署方式采用单机单硬盘模式。

    安装与启动

    wget https://dl.minio.io/server/minio/release/linux-amd64/minio
    nuhup /root/minio server /data > /data/minio/minio.log 2>&1 &
    

    通过环境变量可以修改控制台管理员密码

    export MINIO_ACCESS_KEY=root
    export MINIO_SECRET_KEY=root_1234
    

    控制台:http://127.0.0.1:9000

    几个概念:

    • bucket minio里边object存储位置的最上一级目录,object要存储都要指定一个bucket
    • objectName 如果只指定"文件名.扩展名"则直接存放在bucket目录下,但还可以带路径、比如"/abc/文件名.扩展名"则会存放在bucket/abc/目录下
    • 一般客户端另外配置用户而不是直接使用控制台管理员账户,使用控制台创建用户账号并分配权限(读、写、控制台等)即可。

    与spring搭配开发

    简单实现文件的上传、下载、预览等功能。
    引入依赖

    implementation group: 'io.minio', name: 'minio', version: '7.1.0'
    

    配置类与工具类:

    @Configuration
    public class MinioConfig {
    	
    	@Value("${minio.ip}")
    	private String ip;
    	
    	@Value("${minio.port}")
    	private int port;
    	
    	@Value("${minio.access-key}")
    	private String accessKey;
    	
    	@Value("${minio.secret-key}")
    	private String secretKey;
    	
    	@Bean
    	public MinioClient minioClient() {
    		return MinioClient.builder()
                              .endpoint(ip, port, false) //https or not
                              .credentials(accessKey, secretKey)
                              .build();
    	}
    }
    
    @Component
    public class MinioUtil {
    	private Logger logger = LoggerFactory.getLogger(MinioUtil.class);
    	
    	@Autowired
    	private MinioClient minioClient;
    	
    	/**
    	 * 创建bucket
    	 * */
    	private void createBucket(String bucketName) throws Exception {
    		BucketExistsArgs existsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
    		if(!minioClient.bucketExists(existsArgs)) {
    			MakeBucketArgs makeArgs = MakeBucketArgs.builder().bucket(bucketName).build();
    			minioClient.makeBucket(makeArgs);
    			logger.info("bucket {} 不存在, 自动创建该bucket", bucketName);
    		}
    	}
    	
    	/**
    	 * 从给定输入流中传输对象并放入bucket
    	 * */
    	public ObjectWriteResponse putObject(String bucketName, String objectName, InputStream stream, long objectSize, String contentType) throws Exception {
            if (StringUtils.isEmpty(bucketName)) {
                throw new RuntimeException("保存的bucketName为空");
            }
            createBucket(bucketName);
            //long objSize = -1;
            long partSize = -1; //objectSize已知,partSize设为-1意为自动设置
            PutObjectArgs putArgs = PutObjectArgs.builder()
            				.bucket(bucketName)
            				.object(objectName)
            				.stream(stream, objectSize, partSize)
            				.contentType(contentType)
            				.build();
            ObjectWriteResponse response = minioClient.putObject(putArgs);
            
            return response;
    	}
    	
    	/**
    	 * 从bucket获取指定对象的输入流,后续可使用输入流读取对象
    	 * getObject与minio server连接默认保持5分钟,
    	 * 每隔15s由minio server向客户端发送keep-alive check,5分钟后由客户端主动发起关闭连接
    	 * */
    	public InputStream getObject(String bucketName, String objectName) throws Exception{
    		GetObjectArgs args = GetObjectArgs.builder()
    						.bucket(bucketName)
    						.object(objectName)
    						.build();
            return minioClient.getObject(args);
        }
    	
    	/**
    	 * 获取对象的临时访问url,有效期5分钟
    	 * */
        public String getObjectURL(String bucketName, String objectName) throws Exception{
            GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
    								.bucket(bucketName)
    								.object(objectName)
            							.expiry(5, TimeUnit.MINUTES)
    							        .method(Method.GET)
            							.build();
            return minioClient.getPresignedObjectUrl(args);
        }
        
        /**
         * 删除对象
         * */
        public void removeObject(String bucketName, String objectName) throws Exception {
        	RemoveObjectArgs args = RemoveObjectArgs.builder()
        						.bucket(bucketName)
        						.object(objectName)
        						.build();
        	minioClient.removeObject(args);
        	logger.info("bucket:{}文件{}已删除", bucketName , objectName);
        }
        
        /**
         * 上传MultipartFile
         * @param bucketName 文件存放的bucket
         * @param filePath 文件在bucket里的全目录
         * */
        public ObjectWriteResponse uploadFile(String bucketName, String filePath, MultipartFile file) throws Exception{
        	return putObject(bucketName, filePath, file.getInputStream(), file.getSize(), file.getContentType());
        }
        
        /**
         * 从minio下载文件,直接通过response传输
         * */
        public void downloadFile(String bucketName, String filePath, HttpServletResponse response) throws Exception {
        	
    		try (InputStream is = getObject(bucketName, filePath);
    			 BufferedInputStream bis = new BufferedInputStream(is); 
    			 OutputStream os = response.getOutputStream()) {
    		//try {	
    			/*InputStream is = getObject(bucketName, filePath);
    			BufferedInputStream bis = new BufferedInputStream(is);
    			OutputStream os = response.getOutputStream();*/
    			response.setContentType("application/force-download;charset=utf-8");// 设置强制下载而不是直接打开
                response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(filePath, "UTF-8"));// 设置文件名
                
                
                byte[] buffer = new byte[1024*1024*1024]; //buffer 1M
                int offset = bis.read(buffer);
                while (offset != -1) {
                    os.write(buffer, 0, offset);
                    offset = bis.read(buffer);
                }
                os.flush();
    		} catch (Exception e) {
    			logger.error("下载文件失败"+e.getMessage(), e);
    			throw new RuntimeException("下载文件失败" , e);
    		}
        }
    }
    

    记录一下几个问题:
    1、springboot 2.1.13.RELEASE环境下集成了MinIO客户端7.1.0版本,最新的版本貌似集成不进去
    2、文件下载也就是minioClient.getObject(args)场景下,客户端与MinIO server连接默认保持5分钟,每隔15s由MinIO server向客户端发送keep-alive check,5分钟后由客户端主动发起关闭连接。
    3、文件下载时使用流的方式传输,上述代码里使用try-with-resource的方式确保finally关闭流,但是通过wireshark观测貌似直接普通try-catch最后也没有造成连接的泄露,应该是底层的okio做了优化、5分钟后直接发起了连接关闭。但作为好习惯还是应该主动去关闭流。

  • 相关阅读:
    Calibrating & Undistorting with OpenCV in C++ (Oh yeah)
    opencv中标定函数calibrateCamera
    3D 障碍物感知
    在ubuntu18.04一键安装opencv3.4.1的脚本
    How to run yolov5 model using TensorRT.
    花费 3 天时间整理的代码规范示例代码,你确定不进来看看吗?
    企业级自定义表单引擎解决方案(六)--工作流挂接表单
    企业级自定义表单引擎解决方案(五)--自定义表单典型业务案例
    企业级自定义表单引擎解决方案(四)--实体对象模型实现
    企业级自定义表单引擎解决方案(三)--实体对象模型设计
  • 原文地址:https://www.cnblogs.com/lyhero11/p/15313823.html
Copyright © 2011-2022 走看看