java视频上传,播放预览,解决苹果手机视频无法预览的问题

news/2024/11/28 10:48:57/

需求:上传视频后,点击链接可以在PC和手机端播放预览,包括苹果手机

1.相关工具类

1.1文件上传工具类

package resources.util;import common.util.FileOperateUtil;
import common.util.HttpClientUtil;
import net.sf.json.JSONObject;
import org.apache.commons.httpclient.util.DateUtil;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;/*** @description:* @projectName:alumni* @see:resources.util* @author:* @createTime:2021/11/25 13:41* @version:1.0*/
public class FileUploadTool {TransfMediaTool transfMediaTool = new TransfMediaTool();// 文件最大500Mprivate static long upload_maxsize = 800 * 1024 * 1024;// 文件允许格式private static String[] allowFiles = {".rar", ".doc", ".docx", ".zip",".pdf", ".txt", ".swf", ".xlsx", ".gif", ".png", ".jpg", ".jpeg",".bmp", ".xls", ".mp4", ".flv", ".ppt", ".avi", ".mpg", ".wmv",".3gp", ".mov", ".asf", ".asx", ".vob", ".wmv9", ".rm", ".rmvb"};// 允许转码的视频格式(ffmpeg)private static String[] allowFLV = {".avi", ".mpg", ".wmv", ".3gp",".mov", ".asf", ".asx", ".vob"};// 允许的视频转码格式(mencoder)private static String[] allowAVI = {".wmv9", ".rm", ".rmvb"};public JSONObject createFile(MultipartFile multipartFile, HttpServletRequest request, String staticRes, String from, String userId, String orgCode) {boolean bflag = false;String fileName = multipartFile.getOriginalFilename().toString();fileName = FileOperateUtil.produceFileName(fileName);//生成新的文件名// 判断文件不为空if (multipartFile.getSize() != 0 && !multipartFile.isEmpty()) {bflag = true;// 判断文件大小if (multipartFile.getSize() <= upload_maxsize) {bflag = true;// 文件类型判断if (this.checkFileType(fileName)) {bflag = true;} else {bflag = false;System.out.println("文件类型不允许");}} else {bflag = false;System.out.println("文件大小超范围");}} else {bflag = false;System.out.println("文件为空");}if (bflag) {String logoPathDir = staticRes + "/video/" + orgCode + "/" + from + "/" + userId + "/" + DateUtil.formatDate(new Date(), "yyyy-MM-dd" );//String logoRealPathDir = request.getSession().getServletContext().getRealPath(logoPathDir);File logoSaveFile = new File(logoPathDir);if (!logoSaveFile.exists()) {logoSaveFile.mkdirs();}String name = fileName.substring(0, fileName.lastIndexOf("."));System.out.println("文件名称:" + name);// 新的文件名String newFileName = this.getName(fileName);// 文件扩展名String fileEnd = this.getFileExt(fileName);String fileNamedirs = logoPathDir + File.separator + newFileName + fileEnd;System.out.println("保存的路径:" + fileNamedirs);File filedirs = new File(fileNamedirs);//依据路径创建的文件// 转入文件try {FileOperateUtil.inputCopy(multipartFile.getInputStream(), filedirs);// multipartFile.transferTo(filedirs);} catch (IllegalStateException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}// 相对路径String fileDir = logoPathDir + newFileName + fileEnd;//String fileDir = logoPathDir + newFileName;StringBuilder builder = new StringBuilder(fileDir);String finalFileDir = builder.substring(1);// size存储为StringString size = this.getSize(filedirs);// 源文件保存路径String aviPath = logoSaveFile.getAbsolutePath();JSONObject result = new JSONObject();result.put("fileName", newFileName+fileEnd);//新文件名result.put("size", size);//大小result.put("contentType", HttpClientUtil.getMimeType(filedirs.getName()));//文件标识String localUrl = request.getContextPath() + "/down/video/" + orgCode + "/" + from + "/" + userId + "/" + DateUtil.formatDate(new Date(), "yyyy-MM-dd") + "/" + fileName;result.put("localUrl", localUrl);//路径return result;} else {return null;}} else {return null;}}/*** 文件类型判断** @param fileName* @return*/private boolean checkFileType(String fileName) {Iterator<String> type = Arrays.asList(allowFiles).iterator();while (type.hasNext()) {String ext = type.next();if (fileName.toLowerCase().endsWith(ext)) {return true;}}return false;}/*** 视频类型判断(flv)** @param* @return*/private boolean checkMediaType(String fileEnd) {Iterator<String> type = Arrays.asList(allowFLV).iterator();while (type.hasNext()) {String ext = type.next();if (fileEnd.equals(ext)) {return true;}}return false;}/*** 视频类型判断(AVI)** @param* @return*/private boolean checkAVIType(String fileEnd) {Iterator<String> type = Arrays.asList(allowAVI).iterator();while (type.hasNext()) {String ext = type.next();if (fileEnd.equals(ext)) {return true;}}return false;}/*** 获取文件扩展名** @return string*/private String getFileExt(String fileName) {return fileName.substring(fileName.lastIndexOf("."));}/*** 依据原始文件名生成新文件名** @return*/private String getName(String fileName) {Iterator<String> type = Arrays.asList(allowFiles).iterator();while (type.hasNext()) {String ext = type.next();if (fileName.contains(ext)) {String newFileName = fileName.substring(0, fileName.lastIndexOf(ext));return newFileName;}}return "";}/*** 文件大小,返回kb.mb** @return*/private String getSize(File file) {String size = "";long fileLength = file.length();DecimalFormat df = new DecimalFormat("#.00");if (fileLength < 1024) {size = df.format((double) fileLength) + "BT";} else if (fileLength < 1048576) {size = df.format((double) fileLength / 1024) + "KB";} else if (fileLength < 1073741824) {size = df.format((double) fileLength / 1048576) + "MB";} else {size = df.format((double) fileLength / 1073741824) + "GB";}return size;}
}

2.视频上传代码的实现

/*** description 视频上传* param [request, file, from, userId, orgCode]* return common.enums.ResultVO* author * createTime 2021/11/26 11:36**/@PostMapping("/video")public ResultVO uploadVideo(HttpServletRequest request, MultipartFile file, String from, String userId, String orgCode) {String message = "";JSONObject entity = null;// FileEntity entity = new FileEntity();FileUploadTool fileUploadTool = new FileUploadTool();ModelMap map = new ModelMap();try {entity = fileUploadTool.createFile(file, request, staticRes, from, userId, orgCode);if (entity != null) {
//                service.saveFile(entity);message = "上传成功";map.put("entity", entity);map.put("result", message);} else {message = "上传失败";map.put("result", message);}} catch (Exception e) {e.printStackTrace();}return new ResultVO(ResultCode.SUCCESS, entity);}

3.视频下载PC播放以及手机播放的实现

 /*** description 视频下载器* param [request, response]* return common.enums.ResultVO* author * createTime 2021/11/26 11:39**/@GetMapping("/video/**")public ResultVO downVideo(HttpServletRequest request, HttpServletResponse response) throws IOException {String fileUrl = request.getRequestURI();try {fileUrl = URLDecoder.decode(fileUrl, "UTF-8");} catch (UnsupportedEncodingException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}fileUrl = fileUrl.substring(fileUrl.indexOf("/video") + 6);String imgPath = staticRes + "/video" + fileUrl;String realPath = imgPath;File tmFile = new File(realPath);if ((!tmFile.exists()) || tmFile.length() < 1) {throw new RuntimeException("文件不存在!");}try {/*response.setContentType("video/mp4");InputStream ins = FileOperateUtil.inputStreamFromFile(tmFile);OutputStream ous = response.getOutputStream();FileOperateUtil.readToOutStream(ins, ous, null);*/String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);sendVideo(request, response, tmFile, fileName);} catch (IOException e) {e.printStackTrace();}return new ResultVO(ResultCode.SUCCESS, "下载成功");}//解决苹果 使用 video 标签不能正常播放视频问题//刚开始时代码返回的视频流是在一个请求里全部返回的,而苹果的浏览器会先发一次探测请求来获取文件大小,之后再发送多次请求来分段取数据流的数据,其实这里就是一个分段上传的思想(Accept-Ranges)。有两个很重要的点就是,//第一:需要根据请求内容的不同做出不同的响应,第一次探测请求需要返回200,后面的请求需要返回206和具体数据//第二:contentType必须设置为video/mp4。private void sendVideo(HttpServletRequest request, HttpServletResponse response, File file, String fileName) throws FileNotFoundException, IOException {RandomAccessFile randomFile = new RandomAccessFile(file, "r");//只读模式long contentLength = randomFile.length();String range = request.getHeader("Range");int start = 0, end = 0;if (range != null && range.startsWith("bytes=")) {String[] values = range.split("=")[1].split("-");start = Integer.parseInt(values[0]);if (values.length > 1) {end = Integer.parseInt(values[1]);}}int requestSize = 0;if (end != 0 && end > start) {requestSize = end - start + 1;} else {requestSize = Integer.MAX_VALUE;}byte[] buffer = new byte[4096];response.setContentType("video/mp4");response.setHeader("Accept-Ranges", "bytes");response.setHeader("ETag", fileName);response.setHeader("Last-Modified", new Date().toString());//第一次请求只返回content length来让客户端请求多次实际数据if (range == null) {response.setHeader("Content-length", contentLength + "");} else {//以后的多次以断点续传的方式来返回视频数据response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206long requestStart = 0, requestEnd = 0;String[] ranges = range.split("=");if (ranges.length > 1) {String[] rangeDatas = ranges[1].split("-");requestStart = Integer.parseInt(rangeDatas[0]);if (rangeDatas.length > 1) {requestEnd = Integer.parseInt(rangeDatas[1]);}}long length = 0;if (requestEnd > 0) {length = requestEnd - requestStart + 1;response.setHeader("Content-length", "" + length);response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);} else {length = contentLength - requestStart;response.setHeader("Content-length", "" + length);response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength);}}ServletOutputStream out = response.getOutputStream();int needSize = requestSize;randomFile.seek(start);while (needSize > 0) {int len = randomFile.read(buffer);if (needSize < buffer.length) {out.write(buffer, 0, needSize);} else {out.write(buffer, 0, len);if (len < buffer.length) {break;}}needSize -= buffer.length;}randomFile.close();out.close();}

http://www.ppmy.cn/news/516587.html

相关文章

如何从苹果手机中导出视频且保证画面不失真

最近买了iPhone 12&#xff0c;因为工作需要需要导出视频&#xff0c;但是手机连上电脑后&#xff0c;如何导出视频且保证清晰度是个问题&#xff0c;尝试了一下&#xff0c;特此记录&#xff0c;供大家参考&#xff01; 1、手机设置 设置——相册——“传输到MAC或PC”&…

使用wxParse解析富文本的总结以及解决苹果手机上视频无法播放的方法

先上官方文档&#xff1a;https://github.com/icindy/wxParse。先讲一下我的理解&#xff0c;最后说明下自己使用wxParse的业务场景以及遇到的问题。 1.先上个目录结构。 然后总结下wxParse下我处理过得文件。html2json.js中注释掉console.dir()---显示对象的属性跟方法&#…

如何禁止视频在手机移动端页面中全屏播放

最近公司的项目中出了需要在局部播放视频的需求&#xff0c;我们都知道HTML5中有一个专门的标签video用来嵌入视频。不过&#xff0c;这个video标签有很多的属性可能很多同学并不是很熟悉&#xff0c;下面我们来认识一下&#xff1a; 在网页里嵌入HTML5视频播放器的方法非常简单…

iPhone下mp4视频无法播放和部分手机只有声音没有画面

概述 mp4视频在部分手机上加载失败、无法播放或有声音没画面的原因是&#xff1a;视频编码或声道数有问题&#xff0c;解决方案&#xff1a;视频转码。 遇到的问题 mp4视频在 iPhone XR (IOS 14.1) 上无法播放&#xff0c;一直显示加载失败&#xff0c;但是在安卓手机上却可以…

html5ios播放视频在线播放,ios-iPhone上的HTML5视频自动播放

这是克服您在网站上进行视频自动播放的所有难题的小技巧&#xff1a; 1)检查视频是否正在播放。2)在诸如单击或触摸身体等事件时触发视频播放。 注意&#xff1a;除非用户与设备进行交互&#xff0c;否则某些浏览器不允许视频自动播放。 因此&#xff0c;用于检查视频是否正在播…

iOS 不能播放远程视频(Android 可以)的问题

问题描述&#xff1a; 1、同样的 url&#xff0c;Android 能放&#xff0c;iOS 不能放。后台给的 url 是这个样子(mp4文件格式)&#xff1a; http://192.168.80.102:28085/schcommonweb/weedfs/rdownload/28a54d21abc2、用 KVO 监听 AVPlayerItem 的 status 发现报错&#xf…

html禁止视频弹窗,基于video弹窗视频播放代码

使用方法: 1、head引入css文件 body{background-color: #222} .videolist { position:relative; float:left; width:500px; height:300px; margin-right:50px; margin-top:15px; margin-bottom:30px; } .videolist:hover{ cursor: pointer; } .videoed { display:none; width:…

【前端 ios】audio不能在苹果手机正常播放

在项目中用到了audio组件播放音频&#xff0c;在安卓上播放都是正常的&#xff0c;在 ios 的 safari 浏览器中却不能正常播放音频 原因&#xff1a; 由于 iOS Safari 限制不允许 audio autoplay, 必须用户主动交互(例如 click)后才能播放 audio。故需要用户通过手动触摸的方式(…