是在 Apache License v2.0 下發布的對象存儲服務器,學習成本低,安裝運維簡單,主流語⾔的客戶端整合都有,號稱最強的對象存儲⽂件服務器,且能夠和容器化技術docker/k8s等結合,優勢:功能強、能夠根據業務作二次的定製,新一代分佈式文件存儲系統。java
下載
wget http://dl.minio.org.cn/server/minio/release/linux-amd64/miniolinux
賦權
chmod +x minioweb
啓動 (指定的url是文件存儲地址)
./minio server /usr/local/wulei/minio_store 2>&1 &spring
訪問
http:192.168.200.100:9000docker
界面很是友好,登錄成功後右下角能夠 create bucket 也能夠直接上傳文件。create bucket 有點相似分組的概念,建議每一個項目都各自一個分組。api
還能夠在分組下面繼續建立文件夾,右邊還提供了各類功能(視頻、文檔 等資源不支持預覽)。服務器
1. 加入配置和依賴app
<!--文件存儲--> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.0.3</version> </dependency> minio: # 地址 endpoint: http://192.168.200.100:9000 # 帳號 accessKey: minioadmin # 密碼 secretKey: minioadmin
2. 配置客戶端運維
import io.minio.MinioClient; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Data @Configuration @ConfigurationProperties(prefix = "minio") /** * 文件服務器配置類 */ public class MinioConfig { private String endpoint; private String accessKey; private String secretKey; @Bean public MinioClient minioClient(){ return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } }
3. 工具類分佈式
import io.minio.*; import io.minio.http.Method; import io.minio.messages.Bucket; import io.minio.messages.DeleteError; import io.minio.messages.DeleteObject; import io.minio.messages.Item; import org.springframework.stereotype.Component; import org.springframework.util.FastByteArrayOutputStream; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * 文件服務器工具類 */ @Component public class MinioUtil { private String bucketName = "wulei-service"; @Resource private MinioClient minioClient; /** * 查看存儲bucket是否存在 * @return boolean */ public Boolean bucketExists(String bucketName) { Boolean found; try { found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); } catch (Exception e) { //e.printStackTrace(); return false; } return found; } /** * 建立存儲bucket * @return Boolean */ public Boolean makeBucket(String bucketName) { try { minioClient.makeBucket(MakeBucketArgs.builder() .bucket(bucketName) .build()); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * 刪除存儲bucket * @return Boolean */ public Boolean removeBucket(String bucketName) { try { minioClient.removeBucket(RemoveBucketArgs.builder() .bucket(bucketName) .build()); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * 獲取所有bucket */ public List<Bucket> getAllBuckets() { try { return minioClient.listBuckets(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 文件上傳 * @param file 文件 * @return Boolean */ public Boolean upload(MultipartFile file) { // 修飾過的文件名 非源文件名 String fileName = "2021-07/21/"; fileName = fileName+file.getOriginalFilename(); try { PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(fileName) .stream(file.getInputStream(),file.getSize(),-1).contentType(file.getContentType()).build(); //文件名稱相同會覆蓋 minioClient.putObject(objectArgs); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * 預覽圖片 * @param fileName * @return */ public String preview(String fileName){ // 查看文件地址 GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(bucketName).object(fileName).method(Method.GET).build(); try { String url = minioClient.getPresignedObjectUrl(build); return url; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 文件下載 * @param fileName 文件名稱 * @param res response * @return Boolean */ public void download(String fileName, HttpServletResponse res) { GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName) .object(fileName).build(); try (GetObjectResponse response = minioClient.getObject(objectArgs)){ byte[] buf = new byte[1024]; int len; try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){ while ((len=response.read(buf))!=-1){ os.write(buf,0,len); } os.flush(); byte[] bytes = os.toByteArray(); res.setCharacterEncoding("utf-8"); //設置強制下載不打開 //res.setContentType("application/force-download"); res.addHeader("Content-Disposition", "attachment;fileName=" + fileName); try (ServletOutputStream stream = res.getOutputStream()){ stream.write(bytes); stream.flush(); } } } catch (Exception e) { e.printStackTrace(); } } /** * 查看文件對象 * @return 存儲bucket內文件對象信息 */ public List<Item> listObjects() { Iterable<Result<Item>> results = minioClient.listObjects( ListObjectsArgs.builder().bucket(bucketName).build()); List<Item> items = new ArrayList<>(); try { for (Result<Item> result : results) { items.add(result.get()); } } catch (Exception e) { e.printStackTrace(); return null; } return items; } /** * 刪除 * @param fileName * @return * @throws Exception */ public boolean remove(String fileName){ try { minioClient.removeObject( RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build()); }catch (Exception e){ return false; } return true; } /** * 批量刪除文件對象(沒測試) * @param objects 對象名稱集合 */ public Iterable<Result<DeleteError>> removeObjects(List<String> objects) { List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList()); Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build()); return results; } }
4. 測試
import com.wulei.common.util.JsonData; import com.wulei.user.util.MinioUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; @Api(tags = "文件管理模塊") @RestController @RequestMapping("/api/file/v1") @Slf4j public class MinioController { @Autowired private MinioUtil minioUtil; @ApiOperation(value = "查看存儲bucket是否存在") @GetMapping("/bucketExists") public JsonData bucketExists(String bucketName) { return JsonData.buildSuccess(minioUtil.bucketExists(bucketName)); } @ApiOperation(value = "建立存儲bucket") @GetMapping("/makeBucket") public JsonData makeBucket(String bucketName) { minioUtil.makeBucket(bucketName); return JsonData.buildSuccess(); } @ApiOperation(value = "刪除存儲bucket") @GetMapping("/removeBucket") public JsonData removeBucket(String bucketName) { minioUtil.removeBucket(bucketName); return JsonData.buildSuccess(); } @ApiOperation(value = "獲取所有bucket") @GetMapping("/getAllBuckets") public JsonData getAllBuckets() { return JsonData.buildSuccess(minioUtil.getAllBuckets()); } @ApiOperation(value = "文件上傳") @GetMapping("/upload") public JsonData upload(MultipartFile file) { minioUtil.upload(file); return JsonData.buildSuccess(); } @ApiOperation(value = "圖片預覽") @GetMapping("/preview") public JsonData preview(String fileName) { return JsonData.buildSuccess(minioUtil.preview(fileName)); } @ApiOperation(value = "文件下載") @GetMapping("/download") public JsonData download(String fileName, HttpServletResponse res) { minioUtil.download(fileName,res); return JsonData.buildSuccess(); } @ApiOperation(value = "文件刪除") @GetMapping("/remove") public JsonData remove(String fileName) { minioUtil.remove(fileName); return JsonData.buildSuccess(); } }
。