HUAWEI CLOUD クラウドサーバーの評価 | クラウドサーバーに基づく Minio 導入マニュアル

HUAWEI CLOUD クラウドサーバーの評価 |クラウドサーバーに基づく Minio 導入マニュアル

[ソフトウェアのインストールバージョン] [クラスタインストール(はい)(いいえ)]

                                 

バージョン

創設者

によって編集

作成時間

述べる

1.0

ジェイズ

ジェイズ

2023.9.2

minio HUAWEI Yunyao サーバー

1. 導入計画とアーキテクチャ

1. 計画: (クラスター: ネットワーク計画、サーバー計画)

  インストール方法:非クラスタインストール

  サーバー:   Huawei クラウド: 192.168.0.147

  ポート番号: A.minio 管理インターフェイス: 9000、33806 B.デモ アプリケーション: 8081

2. アーキテクチャ(クラスタ:トポロジ図)

   

  3. サポート事業

  小規模ファイル サーバー: 写真、ファイル、ビデオのストレージ管理。

2. 動作環境のインストール

  1. ハードウェア

   Huawei Yunyao サーバー、2 コア 2G 3m ネットワーク

     2. オペレーティングシステム

 うなめ -a

   springbootのデモを実行するには、事前にJava実行環境をインストールする必要があります。ここでは繰り返しません

    3. 環境構築

        ソフトウェアのインストール パス: /opt/software/minio

        

mkdir -p /opt/ソフトウェア/minio

   

   データ ファイル パス: /opt/data/minio

mkdir -p /opt/data/minio

   ログ ファイル パス: /opt/data/minio/logs

mkdir -p /opt/data/minio/logs

 

3. スタンドアロン導入手順 

  1. インストールパッケージの取得とインストール

  ダウンロードアドレス; https://min.io/download#/linux

cd /opt/ソフトウェア/minio/

wget https://dl.min.io/server/minio/release/linux-amd64/minio

 

インストールの成功:

ダウンロード ファイルを表示します。

ls

     2. 設定変更

  

/etc/default/minio を強制します

# 起動時に新しいバージョンのプロンプトを確認します

MINIO_ROOT_USER=ユーザー名

MINIO_ROOT_PASSWORD=パスワード

# MinIO のバージョンが古い場合は、ユーザー名とパスワードを次のように変更します。

MINIO_ACCESS_KEY=ユーザー名

MINIO_SECRET_KEY=パスワード

注: 作成されるファイルは新しいファイルです。

環境変数を変更する

vim /etc/profile

2行追加

import   MINIO_ROOT_USER=ユーザー名

import   MINIO_ROOT_PASSWORD=パスワード

# MinIO のバージョンが古い場合は、ユーザー名とパスワードを次のように変更します。

e xport  MINIO_ACCESS_KEY=ユーザー名

e xport  MINIO_SECRET_KEY=パスワード

設定ファイルが有効になります

ソース/etc/profile

 

    3. 依存環境の準備ができているかどうかを確認する

   

java -バージョン

    4. インストール

   ファイルのインストール権限を付与します。

   

chmod 777 ミニオ

 ls -l

 

デーモンプロセスとして起動し、指定ポートは固定ポート9000、データファイルパスは/opt/data/minio/

nohup /opt/software /minio/minio サーバー --console-address :33806 --address 0.0.0.0:9 000  / opt / data/ minio >  /opt/data/minio/logs/minio.log  &

ps -ef |grep minio

more minio.log

 

Minio启动成功

    5. 云服务器开通公网端口号:9000

   登录华为云账号:https://auth.huaweicloud.com/

配置到服务器

进入控制台,更改安全组

选择刚才创建的安全组

  1. 验证

 浏览器输入:公网ip:9000

会自动跳转到33806端口上。

用username/password登录

 四.应用部署

    1. 安装java

  请自行安装jdk文件,保证java -version可用。

  2.编写项目

  Pom文件中增加配置

<!--MinIO JAVA SDK-->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>${minio.version}</version>
</dependency>

Yaml中增加配置

minio:
  endpoint: http://192.168.0.213:9000 #MinIO服务所在地址
  bucketName: mall #存储桶名称
  bucketImg: img # 图片桶
  bucketVideo: video # 视频桶
  accessKey: fileadmin #访问的key
  secretKey: fileadmin #访问的秘钥

编写工具类

package top.fairy.global.globalfairytoppi4j.utils;

import io.minio.*;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import top.fairy.global.globalfairytoppi4j.beans.ResultEntity;
import top.fairy.global.globalfairytoppi4j.config.MinioClientConfig;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;


@Slf4j
@Component
public class MinioUtil {

    /**
     * Minio文件上传
     *
     * @param file       文件实体
     * @param fileName   修饰过的文件名 非源文件名
     * @param bucketName 所存文件夹(桶名)
     * @return
     */
    public ResultEntity<Map<String, Object>> minioUpload(MultipartFile file, String fileName, String bucketName) {
        ResultEntity<Map<String, Object>> resultEntity = new ResultEntity();
        try {
            MinioClient minioClient = MinioClientConfig.getMinioClient();
            // fileName为空,说明要使用源文件名上传
            if (fileName == null) {
                fileName = file.getOriginalFilename();
                fileName = fileName.replaceAll(" ", "_");
            }
            InputStream inputStream = file.getInputStream();
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(fileName)
                    .stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
            return resultEntity;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 检查存储桶是否存在
     *
     * @param bucketName 存储桶名称
     * @return
     */
    public boolean bucketExists(String bucketName) {
        boolean flag = false;
        try {
            flag = MinioClientConfig.bucketExists(bucketName);
            if (flag) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }

    /**
     * 获取文件流
     *
     * @param fileName   文件名
     * @param bucketName 桶名(文件夹)
     * @return
     */
    public InputStream getFileInputStream(String fileName, String bucketName) {
        try {
            MinioClient minioClient = MinioClientConfig.getMinioClient();
            return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
        return null;
    }


    /**
     * @param bucketName:
     * @author
     * @description: 创建桶
     * @date 2022/8/16 14:36
     */
    public void createBucketName(String bucketName) {
        try {
            if (StringUtils.isBlank(bucketName)) {
                return;
            }
            MinioClient minioClient = MinioClientConfig.getMinioClient();
            boolean isExist = MinioClientConfig.bucketExists(bucketName);
            if (isExist) {
                log.info("Bucket {} already exists.", bucketName);
            } else {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }

    /**
     * 下载文件
     *
     * @param originalName 文件路径
     */
    public InputStream downloadFile(String bucketName, String originalName, HttpServletResponse response) {
        try {
            MinioClient minioClient = MinioClientConfig.getMinioClient();
            InputStream file = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(originalName).build());
            String filename = new String(originalName.getBytes("ISO8859-1"), StandardCharsets.UTF_8);
            if (StringUtils.isNotBlank(originalName)) {
                filename = originalName;
            }
            response.setHeader("Content-Disposition", "attachment;filename=" + filename);
            ServletOutputStream servletOutputStream = response.getOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = file.read(buffer)) > 0) {
                servletOutputStream.write(buffer, 0, len);
            }
            servletOutputStream.flush();
            file.close();
            servletOutputStream.close();
            return file;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param bucketName:
     * @description: 删除桶
     * @date 2022/8/16 14:36
     */
    public void deleteBucketName(String bucketName) {
        try {
            if (StringUtils.isBlank(bucketName)) {
                return;
            }
            MinioClient minioClient = MinioClientConfig.getMinioClient();
            boolean isExist = MinioClientConfig.bucketExists(bucketName);
            if (isExist) {
                minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }

    /**
     * @param bucketName:
     * @description: 删除桶下面所有文件
     * @date 2022/8/16 14:36
     */
    public void deleteBucketFile(String bucketName) {
        try {
            if (StringUtils.isBlank(bucketName)) {
                return;
            }
            MinioClient minioClient = MinioClientConfig.getMinioClient();
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (isExist) {
                minioClient.deleteBucketEncryption(DeleteBucketEncryptionArgs.builder().bucket(bucketName).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }

    /**
     * 根据文件路径得到预览文件绝对地址
     *
     * @param bucketName
     * @param fileName
     * @return
     */
    public String getPreviewFileUrl(String bucketName, String fileName) {
        try {
            MinioClient minioClient = MinioClientConfig.getMinioClient();
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
}

编写配置文件

package top.fairy.global.globalfairytoppi4j.config;

import io.minio.BucketExistsArgs;
import io.minio.MinioClient;
import io.minio.messages.Bucket;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;


@Slf4j
@Component
@Configuration
public class MinioClientConfig {

    @Autowired
    private StorageProperty storageProperty;

    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(storageProperty.getEndpoint())
                    .credentials(storageProperty.getAccessKey(), storageProperty.getSecretKey())
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("初始化minio配置异常: 【{}】", e.fillInStackTrace());
        }
    }

}

编写业务类

package top.fairy.global.globalfairytoppi4j.action;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.fairy.global.globalfairytoppi4j.api.CommonResult;
import top.fairy.global.globalfairytoppi4j.beans.BucketPolicyConfigDto;
import top.fairy.global.globalfairytoppi4j.beans.FileVo;
import top.fairy.global.globalfairytoppi4j.beans.MinioUploadDto;
import top.fairy.global.globalfairytoppi4j.beans.PageUtil;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * MinIO对象存储管理
 * Created by macro on 2019/12/25.
 */
//@Api(tags = "MinioController", description = "MinIO对象存储管理")
@Controller
@RequestMapping("/minio")
public class MinioController {

    private static final Logger LOGGER = LoggerFactory.getLogger(MinioController.class);
    @Value("${minio.endpoint}")
    private String ENDPOINT;
    @Value("${minio.bucketName}")
    private String BUCKET_NAME;
    @Value("${minio.bucketImg}")
    private String BUCKET_IMG;
    @Value("${minio.bucketVideo}")
    private String BUCKET_VIDEO;
    @Value("${minio.accessKey}")
    private String ACCESS_KEY;
    @Value("${minio.secretKey}")
    private String SECRET_KEY;

//    @ApiOperation("文件上传")
    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult upload(@RequestPart("file") MultipartFile file) {
        try {
            //创建一个MinIO的Java客户端
            MinioClient minioClient =MinioClient.builder()
                    .endpoint(ENDPOINT)
                    .credentials(ACCESS_KEY,SECRET_KEY)
                    .build();
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET_NAME).build());
            if (isExist) {
                LOGGER.info("存储桶已经存在!");
            } else {
                //创建存储桶并设置只读权限
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build());
                BucketPolicyConfigDto bucketPolicyConfigDto = createBucketPolicyConfigDto(BUCKET_NAME);
                SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder()
                        .bucket(BUCKET_NAME)
                        .config(JSONUtil.toJsonStr(bucketPolicyConfigDto))
                        .build();
                minioClient.setBucketPolicy(setBucketPolicyArgs);
            }
            String filename = file.getOriginalFilename();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            // 设置存储对象名称
            String objectName = sdf.format(new Date()) + "/" + filename;
            // 使用putObject上传一个文件到存储桶中
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(BUCKET_NAME)
                    .object(objectName)
                    .contentType(file.getContentType())
                    .stream(file.getInputStream(), file.getSize(), ObjectWriteArgs.MIN_MULTIPART_SIZE).build();
            minioClient.putObject(putObjectArgs);
            LOGGER.info("文件上传成功!");
            MinioUploadDto minioUploadDto = new MinioUploadDto();
            minioUploadDto.setName(filename);
            minioUploadDto.setUrl(ENDPOINT + "/" + BUCKET_NAME + "/" + objectName);
            return CommonResult.success(minioUploadDto);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.info("上传发生错误: {}!", e.getMessage());
        }
        return CommonResult.failed();
    }

    private BucketPolicyConfigDto createBucketPolicyConfigDto(String bucketName) {
        BucketPolicyConfigDto.Statement statement = BucketPolicyConfigDto.Statement.builder()
                .Effect("Allow")
                .Principal("*")
                .Action("s3:GetObject")
                .Resource("arn:aws:s3:::"+bucketName+"/*.**").build();
        return BucketPolicyConfigDto.builder()
                .Version("2012-10-17")
                .Statement(CollUtil.toList(statement))
                .build();
    }

    /**
     * 获取文件列表
     *
     * @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 {
        String bucketName = "img";
        //创建一个MinIO的Java客户端
        MinioClient minioClient =MinioClient.builder()
                .endpoint(ENDPOINT)
                .credentials(ACCESS_KEY,SECRET_KEY)
                .build();
        DecimalFormat df = new DecimalFormat("0.00");
        List<Bucket> buckets = minioClient.listBuckets();
        List<FileVo> list = new ArrayList<>(32);
        if (!buckets.isEmpty()) {
            buckets.forEach(s -> {
                try {
                    // 得到bucket下的文件
                    Iterable<Result<Item>> results = minioClient.listObjects(s.name());

                    // 循环遍历获取每一个文件对象

                    results.forEach(g -> {
                        try {
                            FileVo fileVo = new FileVo();
                            fileVo.setBucketName(s.name());  // 文件夹名称
                            fileVo.setFileName(g.get().objectName());  // 文件名称
                            fileVo.setUpdateTime(localDateTime2Date(g.get().lastModified().toLocalDateTime()));  // 文件上传时间
                            Long size = g.get().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 (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 (XmlParserException e) {
                            e.printStackTrace();
                        } catch (ServerException e) {
                            e.printStackTrace();
                        }
                    });
                } catch (XmlParserException e) {
                    e.printStackTrace();
                }
            });
        }
        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;
    }

    private Date localDateTime2Date(LocalDateTime toLocalDateTime) {
        Date date = Date.from( toLocalDateTime.atZone( ZoneId.systemDefault()).toInstant());
        return date;
    }

    //    @ApiOperation("文件删除")文件删除
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult delete(@RequestParam("objectName") String objectName) {
        try {
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(ENDPOINT)
                    .credentials(ACCESS_KEY,SECRET_KEY)
                    .build();
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(BUCKET_NAME).object(objectName).build());
            return CommonResult.success(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return CommonResult.failed();
    }
}

业务类service,dao入库等操作请自行补充。

源码下载地址:

global-fairy-top-pi4j: java语言读取dth11温湿度传感器参数,通过接口对外提供

具体版本参考:v0.3.1

  1. 打包部署

  Idea中maven package项目之后,拷贝jar包到云服务器

  1. 启动

  nohup java -jar global-fairy-top-pi4j-0.0.1-SNAPSHOT.jar &

  1. 测试:

  localhost:8082/minio/fileList

  • 注意事项
  1. 常见问题

 部署demo前请先安装mysql,并配置好地址。

    

おすすめ

転載: blog.csdn.net/jiao_zg/article/details/132693869