小编把Java代码共享出来
发布时间:2025-06-24 18:57:58 作者:北方职教升学中心 阅读量:880
需求说明
老板给我出个题目,让我把的电影文件上传到minio文件系统,再通过WEB端分配加载视频播放,类似于我们普通的电影网站。
1.1minio版本
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>7.1.4</version></dependency>
1.2maven依赖
<?xml version="1.0"encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.sun</groupId><artifactId>springboot-sun</artifactId><version>1.0-SNAPSHOT</version><!--springboot工程需要继承的父工程--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.8.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!--web开发的起步依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><!--<scope>runtime</scope>--></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>7.1.4</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><scope>provided</scope></dependency><dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId><version>2.10.12</version></dependency></dependencies></project>
1.3分段视频播放Controller
package com.sun.controller;importio.minio.GetObjectArgs;importio.minio.MinioClient;importio.minio.ObjectStat;importio.minio.StatObjectArgs;importio.minio.errors.*;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.HttpHeaders;importorg.springframework.http.HttpStatus;importorg.springframework.http.MediaType;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestHeader;importorg.springframework.web.bind.annotation.RestController;importcom.sun.minio.util.MinIoUtil;importjava.io.ByteArrayOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.security.InvalidKeyException;importjava.security.NoSuchAlgorithmException;@RestControllerpublic class VideoController2 {@GetMapping("/testDisplay2/{fileName}")public ResponseEntity<byte[]>getVideo(@PathVariable String fileName, @RequestHeader(value ="Range", required =false)String range){try {String bucketName ="movie";String objectName =fileName + ".mp4";MinioClient minioClient=MinIoUtil.minioClient;// 根据Range请求头来设置分批加载的范围 GetObjectArgs.Builder getObjectArgsBuilder =GetObjectArgs.builder().bucket(bucketName).object(objectName);long start=0l;if(range!=null &&range.startsWith("bytes=")){String[]values =range.split("=")[1].split("-");start =Long.parseLong(values[0]);long end =values.length >1? Long.parseLong(values[1]):-1;if(end!=-1){long length =end - start + 1;getObjectArgsBuilder.offset(start).length(length);}else{getObjectArgsBuilder.offset(start);}}// 获取视频流 try (InputStream inputStream =minioClient.getObject(getObjectArgsBuilder.build())){ByteArrayOutputStream outputStream =new ByteArrayOutputStream();byte[]buffer =new byte[1024* 1024];// 1MB缓冲区 int length;while((length =inputStream.read(buffer))!=-1){outputStream.write(buffer, 0, length);}byte[]videoBytes =outputStream.toByteArray();HttpHeaders headers =new HttpHeaders();headers.setContentType(MediaType.parseMediaType("video/mp4"));// 如果是分段请求,设置相应的响应头 if(range!=null){ObjectStat objectStat =minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());long fileSize =objectStat.length();headers.set("Content-Range", "bytes "+ start + "-"+ (start + videoBytes.length - 1)+ "/"+ fileSize);returnnew ResponseEntity<>(videoBytes, headers, HttpStatus.PARTIAL_CONTENT);}else{headers.setContentLength(videoBytes.length);returnnew ResponseEntity<>(videoBytes, headers, HttpStatus.OK);}}}catch (Exception e){e.printStackTrace();returnnew ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);}}}
1.4 html5 播放
<html><title>test</title><meta http-equiv="Content-Type"content="text/html; charset=utf-8"><head><style type="text/css">.upload {margin-top: 100px;margin-left: 100px;text-align: center;}</style></head><body><h1 style="text-align: center;margin-top: 20px">test</h1><div><!-- <img src="/minio_demo/testClick/testDisplay?url=/data/temp/img/a6efce1b9d16fdfabf36882ab08f8c5495ee7b9f.jpg">--></div><div><!-- <video src="/minio_demo/testClick/testDisplay?md5=a172e15a869fd7224618840c0815dcb1"controls width="640"height="360">您的浏览器不支持视频标签。 */hexValue.append("0");} //这里借助了Integer类的方法实现16进制的转换 hexValue.append(Integer.toHexString(val));}returnhexValue.toString();}catch (Exception e){e.printStackTrace();return"";}}}
package com.sun.minio.util;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.util.StringUtils;importjavax.servlet.http.HttpServletResponse;importjava.io.InputStream;importjava.io.OutputStream;importjava.net.URLEncoder;public class DownloadUtils {private static final String JSON_APPLICATION ="application/json";private static final Logger log =LoggerFactory.getLogger(DownloadUtils.class.getName());public static boolean downloadFile(HttpServletResponse response, InputStream inputStream , String objectName, long fileLen, String contentType , boolean closeInputStream, long maxAge,String exportFileName)throws Exception {String fileName =StringUtils.isEmpty(exportFileName)?objectName.substring(objectName.lastIndexOf("/")+1):exportFileName;if(!StringUtils.isEmpty(contentType)){response.setContentType(contentType);}else{response.setContentType("application/octet-stream");}response.setCharacterEncoding("utf-8");response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));response.setHeader("X-Actual-Content-Length", String.valueOf(fileLen));cors(response, maxAge);OutputStream out =response.getOutputStream();byte[]buffer =new byte[1024];int len;try {while((len =inputStream.read(buffer))!=-1){out.write(buffer, 0, len);}}catch (Exception e){log.info("download file error.e="+ e);returnfalse;}finally {if(closeInputStream){inputStream.close();}out.flush();out.close();}returntrue;}public static void cors(HttpServletResponse response, long maxAge){response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD");if(maxAge >0){response.setHeader("Access-Control-Max-Age", String.valueOf(maxAge));response.setHeader("Cache-Control", "max-age="+ maxAge);}response.setHeader("Access-Control-Allow-Headers", "*");response.setHeader("Access-Control-Expose-Headers", "Cache-Control, Accept-Ranges, Content-Encoding, Content-Length, Content-Range, X-Actual-Content-Length, Content-Disposition");}}

((int)md5Bytes[i])&0xff;//解释参见最下方 if (val <16){ /***如果小于16,那么val值的16进制形式必然为一位, *因为十进制0,1...9,10,11,12,13,14,15对应的 16进制为 0,1...9,a,b,c,d,e,f;*此处高位补0。</video></div></body></html>1.5上传Controller
package com.sun.controller;importio.minio.errors.*;importorg.apache.commons.lang3.StringUtils;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.core.io.support.PropertiesLoaderUtils;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.ResponseBody;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.multipart.MultipartFile;importorg.springframework.web.servlet.ModelAndView;importcom.sun.minio.util.MinIoContentType;importcom.sun.minio.util.MinIoUtil;importcom.sun.minio.util.MinioBucketEnum;importcom.sun.service.MinioServiceImpl;importjavax.servlet.RequestDispatcher;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.InputStream;importjava.security.InvalidKeyException;importjava.security.NoSuchAlgorithmException;importjava.util.Properties;@RestController@RequestMapping("testClick")public class MinioDemoController {@Autowired private MinioServiceImpl minioServiceImpl;/** * 直接页面展示 * @param response */ @RequestMapping("/testDisplay")public void testDisplay(HttpServletResponse response,String md5)throws Exception {MinIoUtil.displayFile(minioServiceImpl,MinioBucketEnum.VIDEO_FILES,response,md5);}@RequestMapping("/testDownload")public void testDownLoad(HttpServletResponse response,String md5)throws Exception {MinIoUtil.downloadFile(minioServiceImpl,MinioBucketEnum.VIDEO_FILES,response,md5,"");}@RequestMapping("/testLoad")public void testLoadFile(HttpServletResponse response,String md5,String targetPath)throws Exception{MinIoUtil.loadObject(MinioBucketEnum.VIDEO_FILES,targetPath,md5);}@RequestMapping("/deleteFile")public String deleteFile(String md5)throws Exception{MinIoUtil.deleteObject(minioServiceImpl,MinioBucketEnum.VIDEO_FILES, md5);return"deleteFileSucceed";}@RequestMapping("/testUpload")@ResponseBody public String testUpload(HttpServletRequest request, @RequestParam("multipartFile")MultipartFile[]multipartfiles,String url,String pucketName)throws Exception{String filePath ="";for(MultipartFile multipartFile:multipartfiles){String contentType =multipartFile.getContentType();InputStream inputStream =multipartFile.getInputStream();if(!StringUtils.isBlank(url)&&!url.startsWith("/")){url ="/"+url;}if(!StringUtils.isBlank(url)&&!url.endsWith("/")){url +="/";}MinioBucketEnum minioBucketEnum =MinioBucketEnum.VIDEO_FILES;/* * if(pucketName.equals("monthlytext")){minioBucketEnum =* MinioBucketEnum.MONTHLY_TEXT;}if(pucketName.equals("email")){* minioBucketEnum =MinioBucketEnum.VIDEO_FILES;}* if(pucketName.equals("excel")){minioBucketEnum =MinioBucketEnum.EXCEL;}*/ String md5 =MinIoUtil.upload(minioServiceImpl,minioBucketEnum,url + multipartFile.getOriginalFilename(), inputStream, MinIoContentType.getContentType(contentType));filePath+="<p>"+md5+"</p>";if(multipartFile.getOriginalFilename().contains(".mp4")){filePath ="<video src="/minio_demo/testClick/testDisplay?md5="+md5+""controls width="640"height="360">n"+ " 您的浏览器不支持视频标签。 */hexValue.append("0");} //这里借助了Integer类的方法实现16进制的转换 hexValue.append(Integer.toHexString(val));}returnhexValue.toString();}catch (Exception e){e.printStackTrace();return"";}}/** *字符串经过md5加密成32位 */ public static String md5HashCode32Str(String plainText){try {MessageDigest md =MessageDigest.getInstance("MD5");md.update(plainText.getBytes());byte[]md5Bytes =md.digest();StringBuffer hexValue =new StringBuffer();for(int i =0;i <md5Bytes.length;i++){int val =((int)md5Bytes[i])&0xff;//解释参见最下方 if (val <16){ /***如果小于16,那么val值的16进制形式必然为一位, *因为十进制0,1...9,10,11,12,13,14,15对应的 16进制为 0,1...9,a,b,c,d,e,f;*此处高位补0。小编我亲自测过。\n"+ "</video>";}// 构建包含两个a标签的HTML代码字符串 StringBuilder htmlBuilder =new StringBuilder();htmlBuilder.append("<a href=\"/minio_demo/testClick/deleteFile?md5=").append(md5).append("\">删除文件</a>");htmlBuilder.append(" ");// 增加一些空格间隔两个标签 htmlBuilder.append("<a href=\"/minio_demo/testClick/testDownload?md5=").append(md5).append("\">下载文件</a>");// 得到最终的HTML字符串 String htmlString =htmlBuilder.toString();filePath=filePath+htmlString;// filePath+="<p>"+md5+"</p>";}returnfilePath;}@RequestMapping("/testMv1")public ModelAndView testMv1(HttpServletRequest request){ModelAndView modelAndView =new ModelAndView();modelAndView.setViewName("/minio/demo");returnmodelAndView;}@RequestMapping("/testMv2")public ModelAndView testMv2(HttpServletRequest request){ModelAndView modelAndView =new ModelAndView();modelAndView.setViewName("/minio/demo2");returnmodelAndView;}@RequestMapping("/testMv3")public ModelAndView testMv3(){ModelAndView mv=new ModelAndView();mv.setViewName("/minio/demo3");returnmv;}}
1.6 上传HTML5
<!DOCTYPE html><html lang="zh-CN"><head><title>文件上传页面</title><meta http-equiv="Content-Type"content="text/html; charset=utf-8"><style type="text/css">/* 整体页面样式 */ body {font-family: Arial, sans-serif;margin: 0;padding: 0;display: flex;flex-direction: column;justify-content: center;align-items: center;min-height: 100vh;background-color: }/* 标题样式 */ h1 {color: margin-bottom: 30px;}/* 上传表单容器样式 */ .upload {background-color: padding: 30px;border-radius: 10px;box-shadow: 0010px rgba(0, 0, 0, 0.1);width: 400px;}/* 表单段落样式 */ .upload p {margin-bottom: 20px;}/* 文件选择输入框样式 */ .upload input[type="file"]{width: 100%;padding: 10px;border: 1px solid border-radius: 5px;}/* 文本输入框样式 */ .upload input[type="text"]{width: 100%;padding: 10px;border: 1px solid border-radius: 5px;}/* 提交按钮样式 */ .upload input[type="submit"]{background-color: color: padding: 10px 20px;border: none;border-radius: 5px;cursor: pointer;transition: background-color 0.3s ease;}.upload input[type="submit"]:hover {background-color: }</style></head><body><h1>文件上传至MinIO</h1><div class="upload"><form action="/minio_demo/testClick/testUpload"method="post"enctype="multipart/form-data"><p>选择文件: <input type="file"name="multipartFile"/></p><p>桶名称: <input type="text"name="pucketName"value="movie"/></p><p>文件目录: <input type="text"name="url"hidden /></p><p><input type="submit"value="上传并检测"/></p></form></div></body></html>

1.7 MinIoUtil工具类
package com.sun.minio.util;importio.minio.*;importio.minio.errors.*;importorg.apache.commons.lang3.StringUtils;importorg.joda.time.DateTime;importorg.slf4j.LoggerFactory;importorg.springframework.beans.BeansException;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.core.io.support.PropertiesLoaderUtils;importorg.springframework.web.multipart.MultipartFile;importcom.sun.doman.MinioRecord;importcom.sun.service.MinioServiceImpl;importjavax.servlet.ServletOutputStream;importjavax.servlet.http.HttpServletResponse;importjavax.validation.constraints.NotNull;importjava.io.*;importjava.net.URLEncoder;importjava.security.InvalidKeyException;importjava.security.NoSuchAlgorithmException;importjava.util.HashMap;importjava.util.Map;importjava.util.Properties;importjava.util.concurrent.TimeUnit;/** * minio工具类 *//** * minio工具类 */public class MinIoUtil {private static MinioServiceImpl minioService =null;private static final org.slf4j.Logger Logger =LoggerFactory.getLogger(MinIoUtil.class);public static MinioClient minioClient =null;private static String enpoint;private static String username;private static String password;static {try{Properties properties =PropertiesLoaderUtils.loadAllProperties("application.properties");enpoint =properties.getProperty("minioEnpoint");Logger.info("获取minio[enpoint]:"+enpoint);username =properties.getProperty("minioUserName");Logger.info("获取minio[minioUserName]:"+username);password =properties.getProperty("minioPassword");Logger.info("获取minio[minioPassword]"+password);minioClient =MinioClient.builder().endpoint(enpoint).credentials(username,password).build();for(MinioBucketEnum minioBucketEnum: MinioBucketEnum.values()){if(!bucketExist(minioBucketEnum.getBucketName())){createBucket(minioBucketEnum.getBucketName());}}}catch (Exception e){Logger.error("获取minio连接失败",e);e.printStackTrace();}}//检查桶是否存在 public static boolean bucketExist(String buckeyName)throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {returnminioClient.bucketExists(BucketExistsArgs.builder().bucket(buckeyName).build());}//创建桶 public static void createBucket(String bucketName)throws IOException, InvalidKeyException, InvalidResponseException, RegionConflictException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}/** * * @return */ public Map<String,String>getAccess(){Map<String,String>map =new HashMap<>();map.put("username",username);map.put("password",password);returnmap;}/** * * @param name 文件名,可以是单纯的文件名test.pdf,也可以是类似aaa/bbb/ccc/test.pdf,如果没有重复文件名,则会为在minio中的文件路径 * @param inputStream 文件流 * @param contentType * @return */ public static String upload(MinioServiceImpl minioService ,MinioBucketEnum minioBucketEnum, String name, InputStream inputStream, MinIoContentType contentType)throws Exception{if(StringUtils.isBlank(name)||inputStream==null){returnnull;}try{BufferedInputStream bis =new BufferedInputStream(inputStream);String md5Val =MD5Util.md5HashCode32(bis);MinioRecord byMd5Val =minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Val==null){if(objectExist(minioBucketEnum.getBucketName(),name)){//minio存在同名文件,需要改一下文件名 name =getOtherName(name,md5Val);}boolean flag =false;int count =3;for(int i =0;i<count;i++){//失败尝试3次.最后一次还失败抛异常 if(flag){break;}try{minioClient.putObject(PutObjectArgs.builder().bucket(minioBucketEnum.getBucketName()).object(name).contentType(contentType ==null ? MinIoContentType.STREAM.contentType :contentType.contentType).stream(bis, bis.available(), partSize).build());flag =true;}catch (Exception e){if(i==count-1){throw e;}TimeUnit.MILLISECONDS.sleep(200);}}minioService.insertOne(MinioRecord.builder().bucketName(minioBucketEnum.getBucketName()).md5Val(md5Val).minioFilePath(name).remainNum(1).createTime(DateTime.now().toString("yyyy-MM-dd HH:mm:ss")).updateTime(DateTime.now().toString("yyyy-MM-dd HH:mm:ss")).build());}else{byMd5Val.setRemainNum((byMd5Val.getRemainNum()==null?0:byMd5Val.getRemainNum())+1);minioService.updateRemainNum(byMd5Val);}returnmd5Val;}catch (Exception e){Logger.error("上传文件失败,name:"+name,e);throw e;}finally {try{inputStream.close();}catch (Exception e){}}}public static String upload(MinioBucketEnum minioBucketEnum, String name, InputStream inputStream, MinIoContentType contentType)throws Exception{if(StringUtils.isBlank(name)||inputStream==null){returnnull;}try{BufferedInputStream bis =new BufferedInputStream(inputStream);String md5Val =MD5Util.md5HashCode32(bis);MinioRecord byMd5Val =minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Val==null){if(objectExist(minioBucketEnum.getBucketName(),name)){//minio存在同名文件,需要改一下文件名 name =getOtherName(name,md5Val);}boolean flag =false;int count =3;for(int i =0;i<count;i++){//失败尝试3次.最后一次还失败抛异常 if(flag){break;}try{minioClient.putObject(PutObjectArgs.builder().bucket(minioBucketEnum.getBucketName()).object(name).contentType(contentType ==null ? MinIoContentType.STREAM.contentType :contentType.contentType).stream(bis, bis.available(), partSize).build());flag =true;}catch (Exception e){if(i==count-1){throw e;}TimeUnit.MILLISECONDS.sleep(200);}}minioService.insertOne(MinioRecord.builder().bucketName(minioBucketEnum.getBucketName()).md5Val(md5Val).minioFilePath(name).remainNum(1).createTime(DateTime.now().toString("yyyy-MM-dd HH:mm:ss")).updateTime(DateTime.now().toString("yyyy-MM-dd HH:mm:ss")).build());}else{byMd5Val.setRemainNum((byMd5Val.getRemainNum()==null?0:byMd5Val.getRemainNum())+1);minioService.updateRemainNum(byMd5Val);}returnmd5Val;}catch (Exception e){Logger.error("上传文件失败,name:"+name,e);throw e;}finally {try{inputStream.close();}catch (Exception e){}}}/** * * @param name 文件名,可以是单纯的文件名test.pdf,也可以是类似aaa/bbb/ccc/test.pdf,如果没有重复文件名,则会为在minio中的文件路径 * @param filePath 需要上传的文件路径 * @param contentType * @return */ public static String upload(MinioBucketEnum minioBucketEnum, String name, String filePath, MinIoContentType contentType)throws Exception {File file=new File(filePath);if(!file.exists()||minioBucketEnum==null){returnnull;}returnupload(minioBucketEnum,name, new FileInputStream(file), contentType);}/** * 基于MultipartFile文件上传 * @param minioBucketEnum 桶信息 * @param file文件 * @param contentType 内容类型 * @return 返回结果 * @throws Exception 异常 */ public static String upload(@NotNull MinioBucketEnum minioBucketEnum, @NotNull MultipartFile file, MinIoContentType contentType)throws Exception {String filename =file.getOriginalFilename();byte[]bytes =file.getBytes();ByteArrayInputStream bais =new ByteArrayInputStream(bytes);String md5Str =upload(minioBucketEnum, filename, bais, contentType);bais.close();returnmd5Str;}/** * * @param response * @param md5ValOrOldPath 新文件上传则是md5值,旧文件则依然使用旧文件的路径 * @param exportFileName 最终给到前端的文件名 */ public static void downloadFile(MinioServiceImpl minioService ,MinioBucketEnum minioBucketEnum, HttpServletResponse response, String md5ValOrOldPath,String exportFileName){downloadFileByMd5(minioService,minioBucketEnum,response,checkOutMd5Val(md5ValOrOldPath),exportFileName);}/** * 根据文件md5值获取 * @param md5Val * @return */ private static void downloadFileByMd5(MinioServiceImpl minioService ,MinioBucketEnum minioBucketEnum, HttpServletResponse response, String md5Val,String exportFileName){if(StringUtils.isBlank(md5Val)||response==null){return;}try {MinioRecord byMd5Val =minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Val!=null){ObjectStat objectStat =minioClient.statObject(StatObjectArgs.builder().bucket(minioBucketEnum.getBucketName()).object(byMd5Val.getMinioFilePath()).build());DownloadUtils.downloadFile(response, minioClient.getObject(GetObjectArgs.builder().bucket(minioBucketEnum.getBucketName()).object(byMd5Val.getMinioFilePath()).build()), objectStat.name(), objectStat.length(), objectStat.contentType(), true, -1,exportFileName);}}catch (Exception e){Logger.error("下载文件失败",e);e.printStackTrace();}}/** * * @param response * @param md5ValOrOldPath 新文件上传则是md5值,旧文件则依然使用旧文件的路径,最终都是通过文件md5找文件 * @throws Exception */ public static void displayFile(MinioServiceImpl minioService ,MinioBucketEnum minioBucketEnum, HttpServletResponse response, String md5ValOrOldPath)throws Exception {displayFileByMd5(minioService ,minioBucketEnum,response,checkOutMd5Val(md5ValOrOldPath));}/** * 根据MD5值展示文件 * @param response * @param md5Val */ private static void displayFileByMd5(MinioServiceImpl minioService ,MinioBucketEnum minioBucketEnum, HttpServletResponse response, String md5Val)throws Exception {MinioRecord byMd5Val =minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);ObjectStat objectStat =minioClient.statObject(StatObjectArgs.builder().bucket(minioBucketEnum.getBucketName()).object(byMd5Val.getMinioFilePath()).build());String objectName =objectStat.name();String fileName =objectName.substring(objectName.lastIndexOf("/")+1);response.setCharacterEncoding("utf-8");response.setHeader("Content-Type",objectStat.contentType());response.addHeader("Content-Disposition","inline;filename="+ URLEncoder.encode(fileName, "UTF-8"));response.addHeader("Content-Length",""+ objectStat.length());try(ServletOutputStream outputStream =response.getOutputStream();BufferedInputStream bufferedInputStream =new BufferedInputStream(getObjectInputStream(minioBucketEnum.getBucketName(),objectName));BufferedOutputStream bufferedOutputStream =new BufferedOutputStream(outputStream);){int lenth;byte[]bytes =new byte[1024];while((lenth=bufferedInputStream.read(bytes,0,bytes.length))!=-1){bufferedOutputStream.write(bytes,0,lenth);}bufferedOutputStream.flush();}catch (Exception e){Logger.error("下载失败objectname:"+objectName,e);}}/** * * @param name * @param md5Val * @return */ private static String getOtherName(String name,String md5Val){try{String preFix =name.substring(0,name.lastIndexOf("/")+1);if(!name.contains(".")){returnpreFix+md5Val;}String suffix =name.substring(name.lastIndexOf("."));returnpreFix+md5Val+suffix;}catch (Exception e){//最起码把md5的值返回作为文件名 returnmd5Val;}}/** * 文件下载,可以下载到本地某个地址 * @param targetFilaPath 目标文件 * @param md5ValOrOldPath 要下载到的目标文件地址,文件如果已经存在就无法下载 * @throws Exception */ public static void loadObject(MinioBucketEnum minioBucketEnum, String targetFilaPath, String md5ValOrOldPath)throws Exception{loadOBbjectByMD5(minioBucketEnum,targetFilaPath,checkOutMd5Val(md5ValOrOldPath));}/** * 文件下载,可以下载到本地某个地址 * @param targetFilePath 要下载到的目标文件地址,文件如果已经存在就无法下载 * @throws Exception */ private static void loadOBbjectByMD5(MinioBucketEnum minioBucketEnum, String targetFilePath, String md5Val)throws Exception {if(StringUtils.isBlank(targetFilePath)){return;}MinioRecord byMd5Val =minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Val==null){return;}File file=new File(targetFilePath);if(file.exists()){return;}file.createNewFile();loadOBbjectByMD5(minioBucketEnum,new FileOutputStream(file),md5Val);}/** * * @param os * @param md5ValOrOldPath 新文件上传则是md5值,旧文件则依然使用旧文件的路径,最终都是通过文件md5找文件 * @throws Exception */ public static void loadObject(MinioBucketEnum minioBucketEnum, OutputStream os, String md5ValOrOldPath)throws Exception{//先判断是不是32位的md5值 loadOBbjectByMD5(minioBucketEnum,os,checkOutMd5Val(md5ValOrOldPath));}/** * 看下传入参数是否是md5值,为md5值则直接返回..如果是旧文件系统保留的文件路径,需要看下迁移的文件中是否有过该文件,有则返回该文件的实际md5值 * 虽然可能会查两次数据库,不过问题不大,这表数据并不大 * @param md5ValOrOldPath * @return */ private static String checkOutMd5Val(String md5ValOrOldPath){//先判断是不是32位的md5值 if(StringUtils.isBlank(md5ValOrOldPath)){return"";}if(md5ValOrOldPath.length()!=32||md5ValOrOldPath.contains(".")||md5ValOrOldPath.contains("/")||md5ValOrOldPath.contains("\\")){String code =MD5Util.md5HashCode32Str(md5ValOrOldPath);MinioRecord byOldPath =minioService.getByOldPathMD5(code);if(byOldPath==null){return"";}md5ValOrOldPath =byOldPath.getMd5Val();}returnmd5ValOrOldPath;}/** * 文件下载 * @param os 目标输出流 * @throws Exception */ private static boolean loadOBbjectByMD5(MinioBucketEnum minioBucketEnum, OutputStream os, String md5Val)throws Exception{if(StringUtils.isBlank(md5Val)||os==null){returnfalse;}MinioRecord byMd5Val =minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Val==null){returnfalse;}try(BufferedInputStream bufferedInputStream =new BufferedInputStream(getObjectInputStream(minioBucketEnum.getBucketName(),byMd5Val.getMinioFilePath()));BufferedOutputStream bufferedOutputStream =new BufferedOutputStream(os);){int lenth;byte[]bytes =new byte[1024];while((lenth=bufferedInputStream.read(bytes,0,bytes.length))!=-1){bufferedOutputStream.write(bytes,0,lenth);}bufferedOutputStream.flush();returntrue;}catch (Exception e){Logger.error("下载失败objname:"+byMd5Val.getMinioFilePath(),e);throw e;}}/** * true存在 * @param bucketName * @param name * @return */ private static boolean objectExist(String bucketName,String name)throws Exception{try{ObjectStat objectStat =minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(name).build());if(!StringUtils.isBlank(objectStat.name())){returntrue;}returnfalse;}catch (Exception e){returnfalse;}}private static final long partSize =1024*1024*5l;/** * 覆盖并上传文件 * @param bucketName * @param name * @param inputStream * @throws Exception */ /** * 获取对象流 * @param bucketName * @param objectName * @return */ private static InputStream getObjectInputStream(String bucketName,String objectName)throws Exception{int count =3;for(int i =0;i<count;i++){try{InputStream object =minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());returnobject;}catch (Exception e2){if(i==count-1){throw e2;}TimeUnit.MILLISECONDS.sleep(200);}}returnnull;}/** * 获取对象流 * @param bucketName * @param objectName * @return */ public static InputStream getObjectInputStreamByMd5Val(String bucketName,String objectName)throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {MinioRecord byMd5Val =minioService.getByMd5Val(bucketName, objectName);InputStream object =null;try {object =minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(byMd5Val.getMinioFilePath()).build());}catch (Exception e){e.printStackTrace();object =minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(byMd5Val.getMinioFilePath()).build());}returnobject;}/** * 根据md5值删除 * 新文件上传则是md5值,旧文件则依然使用旧文件的路径,最终都是通过文件md5找文件 * @return */ public static void deleteObject(MinioServiceImpl minioService,MinioBucketEnum minioBucketEnum, String md5ValOrOldPath)throws Exception{String md5Val =checkOutMd5Val(md5ValOrOldPath);MinioRecord byMd5Val =minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Val==null){return;}if(byMd5Val.getRemainNum()!=null&&byMd5Val.getRemainNum()<=1){if(objectExist(minioBucketEnum.getBucketName(),byMd5Val.getMinioFilePath())){minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioBucketEnum.getBucketName()).object(byMd5Val.getMinioFilePath()).build());minioService.deleteRecord(minioBucketEnum.getBucketName(),md5Val);}}else{Integer remainNum =byMd5Val.getRemainNum();if(remainNum==null){byMd5Val.setRemainNum(1);}else{byMd5Val.setRemainNum(remainNum-1);}minioService.updateRemainNum(byMd5Val);}}/** * 仅供判断该文件是否存在. * @param minioMd5Value * @return */ public static boolean isExist(MinioBucketEnum minioBucketEnum, String minioMd5Value){MinioRecord byMd5Val =minioService.getByMd5Val(minioBucketEnum.getBucketName(),minioMd5Value);if(byMd5Val==null){returnfalse;}else{returntrue;}}/** * 返回minio数据库表的记录 * @return */ public static MinioRecord getMinioRecordByMd5Value(MinioBucketEnum minioBucketEnum, String minioMd5Value){returnminioService.getByMd5Val(minioBucketEnum.getBucketName(),minioMd5Value);}}
package com.sun.minio.util;importorg.apache.commons.lang3.StringUtils;public enum MinIoContentType {PDF("application/pdf"), STREAM("application/octet-stream"), IMAGE("image/jpeg"), VEDIO("video/mp4"), TEXT("text/html");public String contentType;private MinIoContentType(String contentType){this.contentType =contentType;}public static MinIoContentType getContentType(String contentType){for(MinIoContentType minIoContentType :MinIoContentType.values()){if(minIoContentType.contentType.equals(contentType)){returnminIoContentType;}}returnSTREAM;}public static MinIoContentType getContentTypeByFileName(String fileName){if(StringUtils.isBlank(fileName)){returnSTREAM;}String substring =fileName.substring(fileName.lastIndexOf("."), fileName.length());if(StringUtils.isBlank(substring)){returnSTREAM;}substring =substring.toLowerCase();if("pdf".equals(substring)){returnPDF;}if("png".equals(substring)||"jpg".equals(substring)||"jpng".equals(substring)||"gif".equals(substring)){returnIMAGE;}if("mp4".equals(substring)||"avi".equals(substring)||"mkv".equals(substring)||"mov".equals(substring)||"rmvb".equals(substring)||"FLV".equals(substring)||"rmvb".equals(substring)||"rm".equals(substring)){returnVEDIO;}if("txt".equals(substring)){returnTEXT;}returnSTREAM;}}
package com.sun.minio.util;public enum MinioBucketEnum {//EMAIL("email"), //EXCEL("excel"), //TYPICAL("typical"), //FIRE_CONTROL("firecontrol"), //MONTHLY_TEXT("monthlytext");VIDEO_FILES("movie");private String bucketName;private MinioBucketEnum(String bucketName){this.bucketName =bucketName;}public String getBucketName(){returnbucketName;}}
package com.sun.minio.util;importjava.io.BufferedInputStream;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.InputStream;importjava.security.MessageDigest;/** * 网上copy的代码,获取文件的32位MD5值 */public class MD5Util {/** * 保证文件的MD5值为32位 * @param filePath 文件路径 * @return * @throws FileNotFoundException */ public static String md5HashCode32(String filePath)throws Exception{BufferedInputStream bfis =new BufferedInputStream(new FileInputStream(filePath));returnmd5HashCode32(bfis);}/** * java计算文件32位md5值 * @param fis 输入流 * @return */ public static String md5HashCode32(InputStream fis){try {fis.mark(Integer.MAX_VALUE);//拿到一个MD5转换器,如果想使用SHA-1或SHA-256,则传入SHA-1,SHA-256 MessageDigest md =MessageDigest.getInstance("MD5");//分多次将一个文件读入,对于大型文件而言,比较推荐这种方式,占用内存比较少。</video>--><video src="/minio_demo/testDisplay2/test"controls width="640"height="360">您的浏览器不支持视频标签。Java工程师实现minio存储大型视频文件网页实现分批加载视频播放

一、是真正的能拿过来直接用的。小编把Java代码共享出来。