一、服务器安装minio
1.进行下载
下载地址:
GNU/Linux
https://dl.min.io/server/minio/release/linux-amd64/minio2.新建minio安装目录,执行如下命令
mkdir -p /home/minio/data
把二进制文件上传到安装目录后,执行:
chmod +x minio //给予权限 export MINIO_ACCESS_KEY=minioadmin //创建账号 export MINIO_SECRET_KEY=minioadmin //创建密码 ./minio server /home/minio/data //启动后台启动,并打印日志
nohup ./minio server /home/minio/data > /home/minio/data/minio.log &默认的端口为:9000
自定义端口方式:自定义启动端口号以及控制台端口号,不设置则控制台会自动配置其他端口号,非常不方便
nohup ./minio server --address :9000 --console-address :9001 /home/minio/data > /home/minio/data/minio.log &查看状态
ps -ef|grep minio二、进行访问,并设置桶
1.访问
地址:http://127.0.0.1:9000
输入账号密码后:
进行创建桶,名字自取,创建完成后服务器home/minio/data下也会创建这个文件目录
进行设置:
必须将规则设置成readwrite,才可进行读取文件,否则只存或者只能读。
三、springboot进行实现
1.引入依赖
<!-- minio 相关依赖 --> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>3.0.10</version> </dependency> <!-- alibaba的fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.51</version> </dependency> <!-- thymeleaf模板引擎 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>2.在 application.yml 文件中加入 MinIO 服务器的相关信息
# minio 文件存储配置信息 minio: endpoint: http://127.0.0.1:9000 accesskey: minioadmin secretKey: minioadmin3.创建实体类
这一步,我们将配置文件中 minio 的配置信息通过注解的方式注入到 MinioProp 这个实体中,方便后面我们使用
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * minio 属性值 */ @Data @Component @ConfigurationProperties(prefix = "minio") public class MinioProp { /** * 连接url */ private String endpoint; /** * 用户名 */ private String accesskey; /** * 密码 */ private String secretKey; }4、创建核心配置类
通过注入 MinIO 服务器的相关配置信息,得到 MinioClient 对象,我们上传文件依赖此对象
import io.minio.MinioClient; import io.minio.errors.InvalidEndpointException; import io.minio.errors.InvalidPortException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * minio 核心配置类 */ @Configuration @EnableConfigurationProperties(MinioProp.class) public class MinioConfig { @Autowired private MinioProp minioProp; /** * 获取 MinioClient * * @return * @throws InvalidPortException * @throws InvalidEndpointException */ @Bean public MinioClient minioClient() throws InvalidPortException, InvalidEndpointException { return new MinioClient(minioProp.getEndpoint(), minioProp.getAccesskey(), minioProp.getSecretKey()); } }5、上传工具类
import com.alibaba.fastjson.JSONObject; import com.zyxx.email.common.redis.RedisUtil; import com.zyxx.email.utils.DateUtils; import io.minio.MinioClient; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; @Slf4j @Component public class MinioUtils { @Autowired private MinioClient client; @Autowired private MinioProp minioProp; /** * 创建bucket * * @param bucketName bucket名称 */ @SneakyThrows public void createBucket(String bucketName) { if (!client.bucketExists(bucketName)) { client.makeBucket(bucketName); } } /** * 上传文件 * * @param file 文件 * @param bucketName 存储桶 * @return */ public JSONObject uploadFile(MultipartFile file, String bucketName) throws Exception { JSONObject res = new JSONObject(); res.put("code", 0); // 判断上传文件是否为空 if (null == file || 0 == file.getSize()) { res.put("msg", "上传文件不能为空"); return res; } try { // 判断存储桶是否存在 createBucket(bucketName); // 文件名 String originalFilename = file.getOriginalFilename(); // 新的文件名 = 存储桶名称_时间戳.后缀名 String fileName = bucketName + "_" + System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf(".")); // 开始上传 client.putObject(bucketName, fileName, file.getInputStream(), file.getContentType()); res.put("code", 1); res.put("msg", minioProp.getEndpoint() + "/" + bucketName + "/" + fileName); return res; } catch (Exception e) { log.error("上传文件失败:{}", e.getMessage()); } res.put("msg", "上传失败"); return res; } }6.controller接口
import com.alibaba.fastjson.JSONObject; import com.zyxx.email.common.minio.MinioUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; @Controller public class MinioController { @Autowired private MinioUtils minioUtils; /** * 上传 * * @param file * @param request * @return */ @PostMapping("/upload") @ResponseBody public String upload(@RequestParam(name = "file", required = false) MultipartFile file, HttpServletRequest request) { JSONObject res = null; try { res = minioUtils.uploadFile(file, "product"); } catch (Exception e) { e.printStackTrace(); res.put("code", 0); res.put("msg", "上传失败"); } return res.toJSONString(); } }测试
通过网址进行访问:
PostMan进行测试上传;
删除文件:
//文件删除 @DeleteMapping public String delete(String name) { try { MinioClient minioClient = new MinioClient(ENDPOINT, ACCESSKEY, SECRETKEY); minioClient.removeObject(BUCKETNAME, name); } catch (Exception e) { return "删除失败"+e.getMessage(); } return "删除成功"; }适用于minio的文件内容文件路径加解密工具类(AES对称加密)
在使用minio的情况下,官方提供两种方案来做对象加密,分别是SSE-C、SSE-S3。但是在某些情况下我们受限于条件没法快速的通过以上方案实现加密,那么这个工具类可以帮助你,此加密过程经测试效率很不错,5MB的文件加密解密整个过程在800ms以内。
import cn.hutool.crypto.symmetric.SymmetricAlgorithm; import cn.hutool.crypto.symmetric.SymmetricCrypto; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Base64; import io.minio.MinioClient; public class EncryptionUtil { static final String originKeyStr = "0123456789Abc@@@"; // 必须16个字符 private static SymmetricCrypto aes; // 加密并编码字符串 public static String encryptURLEncodeStr(String str) { try { if (aes == null) { SecretKey aesKey = new SecretKeySpec(originKeyStr.getBytes(StandardCharsets.UTF_8), "AES"); byte[] key = aesKey.getEncoded(); //构建 aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key); } //加密 byte[] encrypt = aes.encrypt(str.getBytes(StandardCharsets.UTF_8)); String s = Base64.getUrlEncoder().encodeToString(encrypt); return s; }catch (Exception e){ e.printStackTrace(); } return ""; } // 解码并解密字符串 public static String decryptURLDecodeStr(String encStr) { try { if (aes == null) { SecretKey aesKey = new SecretKeySpec(originKeyStr.getBytes(StandardCharsets.UTF_8), "AES"); byte[] key = aesKey.getEncoded(); //构建 aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key); } //加密 byte[] bytes = Base64.getUrlDecoder().decode(encStr); String s = aes.decryptStr(bytes); return s; }catch (Exception e){ e.printStackTrace(); } return ""; } // 加密并上传文件 @SneakyThrows public static void encryptUpload(MinioClient minioClient, String bucketName, String objectName, InputStream inputStream) { if (aes == null) { SecretKey aesKey = new SecretKeySpec(originKeyStr.getBytes(StandardCharsets.UTF_8), "AES"); byte[] key = aesKey.getEncoded(); //构建 aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key); } byte[] bytes = new byte[inputStream.available()]; inputStream.read(bytes, 0, bytes.length); //加密 byte[] encrypt = aes.encrypt(bytes); ByteArrayInputStream bais = new ByteArrayInputStream(encrypt); PutObjectOptions putObjectOptions = new PutObjectOptions(bais.available(), bais.available()< 5*1024*1024 ? 5*1024*1024 : bais.available()*8); minioClient.putObject(bucketName, objectName, bais, putObjectOptions); } // 下载文件并解密 @SneakyThrows public static byte[] decryptDownload(MinioClient minioClient, String bucketName, String objectName) { if (aes == null) { SecretKey aesKey = new SecretKeySpec(originKeyStr.getBytes(StandardCharsets.UTF_8), "AES"); byte[] key = aesKey.getEncoded(); aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key); } InputStream inputStream = minioClient.getObject(bucketName, objectName); byte[] decrypt = aes.decrypt(inputStream); return decrypt; } }