因为项目中用到了 minIO 文件服务器,自己的话也是第一次接触,算是特别基础的东西,自己记录一下,以便以后随取随用
1、spring boot 整合 minIO
1-1 引入依赖
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>3.0.10</version>
</dependency>
1-2 工具类
工具类是方便 操作 minIO
MinIOUtil
import io.minio.MinioClient; import io.minio.errors.InvalidEndpointException; import io.minio.errors.InvalidPortException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.multipart.MultipartFile; import java.time.LocalDate; import java.util.Random; /** * 对象存储工具类 * @author */ public class MinIOUtil { private static final Logger log = LoggerFactory.getLogger(MinIOUtil.class); /** * Mino服务器的AccessKey */ private final transient static String ACCESS_KEY = "minio 用户名"; /**Mino服务器的SecretKey * */ private final transient static String SECRET_KEY = "密码"; /** * 桶名称 */ private final transient static String BUCKET_NAME ="桶名称"; /** * minio 服务器地址 */ private final transient static String OOS_URL ="minio 地址"; /** * minio服务端口,默认是9000 */ private final transient static int OSS_PORT = 8057; private transient static boolean BUCKET_EXISTS = false; //单例模式-内部类实现 private static class MinioClientHolder { private static MinioClient minioClient; static { try { minioClient = new MinioClient(OOS_URL, OSS_PORT, ACCESS_KEY, SECRET_KEY); } catch (InvalidEndpointException e) { e.printStackTrace(); } catch (InvalidPortException e) { e.printStackTrace(); } } } /** * 获取minio客户端实例 * * @return */ public static MinioClient getMinioClient() { return MinioClientHolder.minioClient; } /** * 获取文件名 * * @param muFile 文件 * @param isRetain 是否保留源文件名 * @return 返回文件名,以当前年月日作为前缀路径 */ private static String getFilePathName(MultipartFile muFile, boolean isRetain) { String fileName = muFile.getOriginalFilename(); String name = fileName; String prefix = ""; if (fileName.indexOf('.') != -1) { name = fileName.substring(0, fileName.indexOf('.')); prefix = fileName.substring(fileName.lastIndexOf(".")); } LocalDate date = LocalDate.now(); StringBuilder filePathName = new StringBuilder("/upload/"); filePathName.append(date.getYear()); filePathName.append("/"); filePathName.append(date.getMonthValue()); filePathName.append("/"); filePathName.append(date.getDayOfMonth()); filePathName.append("/"); //添加随机后缀 Random r = new Random(); int pix = r.ints(1, (100 + 1)).findFirst().getAsInt(); filePathName.append(System.currentTimeMillis()); filePathName.append("" + pix); //文件名超过32字符则截取 if (isRetain) { filePathName.append("_"); if (name.length() >= 32) { name = name.substring(0, 32); } filePathName.append(name); } filePathName.append(prefix); return filePathName.toString(); } }
2、 具体实现
具体在接口里实现
@PostMapping("/uploadFile") @ApiOperation(value = "上传文件(通用:支持图片、音频、视频、文档)") public BaseResponse MinIOUploadFile(@ApiParam(name = "file", value = "文件", required = true) @RequestParam("file") MultipartFile file) { if (file.isEmpty() || file.getSize() == 0) { return setResultError("文件为空"); } // 测试判断文件类型 String type = VerifyFileType.gitFileTypeBySuffix(file); logger.info("type={}",type); try { MinioClient minioClient = MinIOUtil.getMinioClient(); //是否存在名为“actives”的bucket if (!minioClient.bucketExists("actives")) { minioClient.makeBucket("actives"); } String fileName = file.getOriginalFilename(); String newName=null; if ("image".equals(type)){ //图片 newName ="img/"+ UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf(".")); }else if ("audio".equals(type)){ newName ="audio/"+ UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf(".")); }else if ("video".equals(type)){ newName ="video/"+ UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf(".")); }else if ("doc".equals(type)){ newName ="doc/"+ UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf(".")); }else { return setResultError("该文件类型不能上传!"); } //新的名称,pic会是bucket下的文件夹 //获取file的inputStream InputStream inputStream = file.getInputStream(); //上传 minioClient.putObject("actives", newName, inputStream, "application/octet-stream"); inputStream.close(); //文件访问路径 String url = minioClient.getObjectUrl("actives", newName); return setResultSuccess(url); } catch (Exception e) { logger.error(String.valueOf(e)); } return setResultError("上传失败"); }
之前因为业务只有 图片上传,所以就只写了图片上传的,后来需求增加一个 MP3上传预览的,索性就开发了一个 通用的,支持图片、音频、视频、文档
其中加了一个文件类型判断 ,区分文件类型分别以建立不同的文件夹存储
VerifyFileType.java
/** * 根据文件后缀进行分类 * @param file * @return */ public static String gitFileTypeBySuffix(MultipartFile file){ String fileName = file.getOriginalFilename(); String suffix = fileName.substring(fileName.lastIndexOf(".") + 1); // 文件类型分类 String[] imgTypes = new String[] { "jpg", "png", "gif"}; String[] audioTypes = new String[] { "wav", "mp3"}; String[] videoTypes = new String[] { "avi", "mp4","rmvb","wmv","flv"}; String[] docTypes = new String[] { "pdf", "docx","doc"}; if (isValid(suffix, imgTypes)){ return "image"; }else if (isValid(suffix, audioTypes)){ return "audio"; }else if (isValid(suffix,videoTypes)){ return "video"; }else if (isValid(suffix,docTypes)){ return "doc"; }else { return null; } } public static boolean isValid(String contentType, String... allowTypes) { if (null == contentType || "".equals(contentType)) { return false; } for (String type : allowTypes) { if (contentType.equals(type)) { return true; } } return false; }
网上还有一个 根据 fileCode 区分的,比较安全,有兴趣可以去看看,也蛮有意思的
上传完之后,返回的url 需在 html 标签中预览
<!DOCTYPE HTML> <html> <body> 音频 <audio src="http://ip/actives/mp3/0769d7ff6ae543ba94c2e0107a877f8f.mp3" controls="controls"> Your browser does not support the audio element. </audio> <br/> 图片 <img src="http://ip/actives/img/253f5f6638cc4b419277ccb1538304b9.jpg" alt="图片" height="200" width="200" /> <br/> 视频 <video src="http://ip/actives/video/8593052c6e784a1c8bdd593eb8db4ce5.mp4" controls="controls"> </video> </body> </html>
如果你 预览不行的话 看看minio 文件夹的权限有没有开
这样设置一下就ok 啦,
看看效果