网站建设百强企业,wordpress 微信主题下载,什么网站做优化最好?,怎么看网站制作Java工程师实现minio存储大型视频文件网页实现分批加载视频播放 一、需求说明
老板给我出个题目#xff0c;让我把的电影文件上传到minio文件系统#xff0c;再通过WEB端分配加载视频播放#xff0c;类似于我们普通的电影网站。小编把Java代码共享出来。是真正的能拿过来直…Java工程师实现minio存储大型视频文件网页实现分批加载视频播放 一、需求说明
老板给我出个题目让我把的电影文件上传到minio文件系统再通过WEB端分配加载视频播放类似于我们普通的电影网站。小编把Java代码共享出来。是真正的能拿过来直接用的。小编我亲自测过。
1.1minio版本
dependencygroupIdio.minio/groupIdartifactIdminio/artifactIdversion7.1.4/version/dependency1.2maven依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.sun/groupIdartifactIdspringboot-sun/artifactIdversion1.0-SNAPSHOT/version!--springboot工程需要继承的父工程--parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.1.8.RELEASE/version/parentdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId/dependency!--web开发的起步依赖--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion2.1.0/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId!--scoperuntime/scope--/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdio.minio/groupIdartifactIdminio/artifactIdversion7.1.4/version/dependencydependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactIdversion3.12.0/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.28/versionscopeprovided/scope/dependencydependencygroupIdjoda-time/groupIdartifactIdjoda-time/artifactIdversion2.10.12/version
/dependency/dependencies/project1.3分段视频播放Controller
package com.sun.controller;import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.StatObjectArgs;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;import com.sun.minio.util.MinIoUtil;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;RestController
public class VideoController2 {GetMapping(/testDisplay2/{fileName})public ResponseEntitybyte[] 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 start0l;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);return new ResponseEntity(videoBytes, headers, HttpStatus.PARTIAL_CONTENT);} else {headers.setContentLength(videoBytes.length);return new ResponseEntity(videoBytes, headers, HttpStatus.OK);}}} catch (Exception e) {e.printStackTrace();return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);}}
}1.4 html5 播放
html
titletest/title
meta http-equivContent-Type contenttext/html; charsetutf-8
headstyle typetext/css.upload {margin-top: 100px;margin-left: 100px;text-align: center;}/style/head
body
h1 styletext-align: center;margin-top: 20pxtest/h1
div!-- img src/minio_demo/testClick/testDisplay?url/data/temp/img/a6efce1b9d16fdfabf36882ab08f8c5495ee7b9f.jpg --
/divdiv!-- video src/minio_demo/testClick/testDisplay?md5a172e15a869fd7224618840c0815dcb1 controls width640 height360您的浏览器不支持视频标签。
/video--video src/minio_demo/testDisplay2/test controls width640 height360您的浏览器不支持视频标签。
/video/div
/body
/html1.5上传Controller package com.sun.controller;import io.minio.errors.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;import com.sun.minio.util.MinIoContentType;
import com.sun.minio.util.MinIoUtil;
import com.sun.minio.util.MinioBucketEnum;
import com.sun.service.MinioServiceImpl;import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;RestController
RequestMapping(testClick)
public class MinioDemoController {Autowiredprivate 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)ResponseBodypublic 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));filePathpmd5/p;if(multipartFile.getOriginalFilename().contains(.mp4)) {filePath video src\/minio_demo/testClick/testDisplay?md5md5\ controls width\640\ height\360\\n 您的浏览器不支持视频标签。\n /video;}// 构建包含两个a标签的HTML代码字符串StringBuilder htmlBuilder new StringBuilder();htmlBuilder.append(a href\/minio_demo/testClick/deleteFile?md5).append(md5).append(\删除文件/a);htmlBuilder.append(nbsp;nbsp;nbsp;nbsp;); // 增加一些空格间隔两个标签htmlBuilder.append(a href\/minio_demo/testClick/testDownload?md5).append(md5).append(\下载文件/a);// 得到最终的HTML字符串String htmlString htmlBuilder.toString();filePathfilePathhtmlString;// filePathpmd5/p;}return filePath;}RequestMapping(/testMv1)public ModelAndView testMv1(HttpServletRequest request){ModelAndView modelAndView new ModelAndView();modelAndView.setViewName(/minio/demo);return modelAndView;}RequestMapping(/testMv2)public ModelAndView testMv2(HttpServletRequest request){ModelAndView modelAndView new ModelAndView();modelAndView.setViewName(/minio/demo2);return modelAndView;}RequestMapping(/testMv3)public ModelAndView testMv3(){ModelAndView mv new ModelAndView();mv.setViewName(/minio/demo3);return mv;}
}
1.6 上传HTML5
!DOCTYPE html
html langzh-CN
headtitle文件上传页面/titlemeta http-equivContent-Type contenttext/html; charsetutf-8style typetext/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: #f4f4f4;}/* 标题样式 */h1 {color: #333;margin-bottom: 30px;}/* 上传表单容器样式 */.upload {background-color: #fff;padding: 30px;border-radius: 10px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);width: 400px;}/* 表单段落样式 */.upload p {margin-bottom: 20px;}/* 文件选择输入框样式 */.upload input[typefile] {width: 100%;padding: 10px;border: 1px solid #ccc;border-radius: 5px;}/* 文本输入框样式 */.upload input[typetext] {width: 100%;padding: 10px;border: 1px solid #ccc;border-radius: 5px;}/* 提交按钮样式 */.upload input[typesubmit] {background-color: #007BFF;color: #fff;padding: 10px 20px;border: none;border-radius: 5px;cursor: pointer;transition: background-color 0.3s ease;}.upload input[typesubmit]:hover {background-color: #0056b3;}/style
/head
bodyh1文件上传至MinIO/h1div classuploadform action/minio_demo/testClick/testUpload methodpost enctypemultipart/form-datap选择文件: input typefile namemultipartFile //pp桶名称: input typetext namepucketName valuemovie //pp文件目录: input typetext nameurl hidden //ppinput typesubmit value上传并检测 //p/form/div
/body
/html1.7 MinIoUtil工具类
package com.sun.minio.util;import io.minio.*;
import io.minio.errors.*;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.web.multipart.MultipartFile;import com.sun.doman.MinioRecord;
import com.sun.service.MinioServiceImpl;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.*;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.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 {return minioClient.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 MapString,String getAccess(){MapString,String map new HashMap();map.put(username,username);map.put(password,password);return map;}/**** 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)||inputStreamnull){return null;}try{BufferedInputStream bis new BufferedInputStream(inputStream);String md5Val MD5Util.md5HashCode32(bis);MinioRecord byMd5Val minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Valnull){if(objectExist(minioBucketEnum.getBucketName(),name)){//minio存在同名文件,需要改一下文件名name getOtherName(name,md5Val);}boolean flag false;int count 3;for(int i 0;icount;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 (icount-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);}return md5Val;}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)||inputStreamnull){return null;}try{BufferedInputStream bis new BufferedInputStream(inputStream);String md5Val MD5Util.md5HashCode32(bis);MinioRecord byMd5Val minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Valnull){if(objectExist(minioBucketEnum.getBucketName(),name)){//minio存在同名文件,需要改一下文件名name getOtherName(name,md5Val);}boolean flag false;int count 3;for(int i 0;icount;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 (icount-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);}return md5Val;}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()||minioBucketEnumnull){return null;}return upload(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();return md5Str;}/**** 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)||responsenull){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 ((lenthbufferedInputStream.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(.)){return preFixmd5Val;}String suffix name.substring(name.lastIndexOf(.));return preFixmd5Valsuffix;}catch (Exception e){//最起码把md5的值返回作为文件名return md5Val;}}/*** 文件下载,可以下载到本地某个地址* 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(byMd5Valnull){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(byOldPathnull){return ;}md5ValOrOldPath byOldPath.getMd5Val();}return md5ValOrOldPath;}/*** 文件下载* param os 目标输出流* throws Exception*/private static boolean loadOBbjectByMD5(MinioBucketEnum minioBucketEnum, OutputStream os, String md5Val)throws Exception{if(StringUtils.isBlank(md5Val)||osnull){return false;}MinioRecord byMd5Val minioService.getByMd5Val(minioBucketEnum.getBucketName(),md5Val);if(byMd5Valnull){return false;}try(BufferedInputStream bufferedInputStream new BufferedInputStream(getObjectInputStream(minioBucketEnum.getBucketName(),byMd5Val.getMinioFilePath()));BufferedOutputStream bufferedOutputStream new BufferedOutputStream(os);){int lenth;byte[] bytes new byte[1024];while ((lenthbufferedInputStream.read(bytes,0,bytes.length))!-1){bufferedOutputStream.write(bytes,0,lenth);}bufferedOutputStream.flush();return true;}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())){return true;}return false;}catch (Exception e){return false;}}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;icount;i){try{InputStream object minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());return object;}catch (Exception e2){if(icount-1){throw e2;}TimeUnit.MILLISECONDS.sleep(200);}}return null;}/*** 获取对象流* 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());}return object;}/*** 根据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(byMd5Valnull){return;}if(byMd5Val.getRemainNum()!nullbyMd5Val.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(remainNumnull){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(byMd5Valnull){return false;}else{return true;}}/*** 返回minio数据库表的记录* return*/public static MinioRecord getMinioRecordByMd5Value(MinioBucketEnum minioBucketEnum, String minioMd5Value){return minioService.getByMd5Val(minioBucketEnum.getBucketName(),minioMd5Value);}}
package com.sun.minio.util;import org.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)){return minIoContentType;}}return STREAM;}public static MinIoContentType getContentTypeByFileName(String fileName){if(StringUtils.isBlank(fileName)){return STREAM;}String substring fileName.substring(fileName.lastIndexOf(.), fileName.length());if(StringUtils.isBlank(substring)){return STREAM;}substring substring.toLowerCase();if(pdf.equals(substring)){return PDF;}if(png.equals(substring)||jpg.equals(substring)||jpng.equals(substring)||gif.equals(substring)){return IMAGE;}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)){return VEDIO;}if(txt.equals(substring)){return TEXT;}return STREAM;}
}
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(){return bucketName;}
}
package com.sun.minio.util;import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.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));return md5HashCode32(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-256MessageDigest md MessageDigest.getInstance(MD5);//分多次将一个文件读入对于大型文件而言比较推荐这种方式占用内存比较少。byte[] buffer new byte[1024];int length -1;while ((length fis.read(buffer, 0, 1024)) ! -1) {md.update(buffer, 0, length);}fis.reset();//转换并返回包含16个元素字节数组,返回数值范围为-128到127byte[] 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。*/hexValue.append(0);}//这里借助了Integer类的方法实现16进制的转换hexValue.append(Integer.toHexString(val));}return hexValue.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。*/hexValue.append(0);}//这里借助了Integer类的方法实现16进制的转换hexValue.append(Integer.toHexString(val));}return hexValue.toString();} catch (Exception e) {e.printStackTrace();return ;}}
}
package com.sun.minio.util;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.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);return false;} finally {if (closeInputStream) {inputStream.close();}out.flush();out.close();}return true;}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);}
}