1. 先从菜单栏下的视频转码list页面开始。

    <!DOCTYPE html>
    <html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
    <head><th:block th:include="include :: header('视频转码列表')" />
    </head>
    <body class="gray-bg"><div class="container-div"><div class="row"><div class="col-sm-12 search-collapse"><form id="formId"><div class="select-list"><ul><li><p>标题:</p><input type="text" name="videoTitle"/></li><li><p>上传者:</p><input type="text" name="videoWriter"/></li><li><p>文化程度:</p><select name="videoGrade" th:with="type=${@dict.getType('zyk_video_grade')}"><option value="">所有</option><option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option></select></li><li><p>视频地址:</p><input type="text" name="videoUrl"/></li><li class="select-time"><p>上传时间:</p><input type="text" class="time-input" id="startTime" placeholder="开始时间" name="params[beginVideoTime]"/><span>-</span><input type="text" class="time-input" id="endTime" placeholder="结束时间" name="params[endVideoTime]"/></li><li><p>视频封面地址:</p><input type="text" name="videoPicurl"/></li><li><a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;搜索</a><a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;重置</a></li></ul></div></form></div><div class="btn-group-sm" id="toolbar" role="group"><a class="btn btn-success" onclick="add()" shiro:hasPermission="zyk:video:add"><i class="fa fa-plus"></i> 添加</a><a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="zyk:video:edit"><i class="fa fa-edit"></i> 修改</a><a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="zyk:video:remove"><i class="fa fa-remove"></i> 删除</a><a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="zyk:video:export"><i class="fa fa-download"></i> 导出</a></div><div class="col-sm-12 select-table table-striped"><table id="bootstrap-table"></table></div></div></div><th:block th:include="include :: footer" /><script th:inline="javascript">var editFlag = [[${@permission.hasPermi('zyk:video:edit')}]];var removeFlag = [[${@permission.hasPermi('zyk:video:remove')}]];var videoGradeDatas = [[${@dict.getType('zyk_video_grade')}]];var prefix = ctx + "zyk/video";$(function() {var options = {url: prefix + "/list",createUrl: prefix + "/add",updateUrl: prefix + "/edit/{id}",removeUrl: prefix + "/remove",exportUrl: prefix + "/export",modalName: "视频转码",columns: [{checkbox: true},{field : 'videoId', title : '主键id',visible: false},{field : 'videoTitle', title : '标题'},{field : 'videoWriter', title : '上传者'},{field : 'videoGrade', title : '文化程度',formatter: function(value, row, index) {return $.table.selectDictLabel(videoGradeDatas, value);}},{field : 'videoUrl', title : '视频地址',width :200,height:150,formatter: function(value, row, index) {if(value==''||value ==null||value =="other_default.jpg"){return '<img src="/img/other_default.jpg" width="50" height="50">';}else{return  '<video  src="http://192.168.2.195:8091/profile/'+value+'" width="100" height="50"  controls/>';}}},{field : 'videoTimecount',title : '视频时长'},{field : 'videoTime', title : '上传时间'},{field : 'videoPicurl', title : '视频封面地址',formatter: function(value, row, index) {if(value==''||value ==null||value =="other_default.jpg"){return '<img src="/img/other_default.jpg" width="50" height="50">';}else{return '<img src="/profile/' + value + '" width="50" height="50">';}}},{title: '操作',align: 'center',formatter: function(value, row, index) {var actions = [];actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.videoId + '\')"><i class="fa fa-edit"></i>编辑</a> ');actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.videoId + '\')"><i class="fa fa-remove"></i>删除</a>');return actions.join('');}}]};$.table.init(options);});/*** 预览资源*/function add() {var index = layer.open({type: 2,title: '视频上传转码:',area: ['1200px', '650px'], //宽高fix: false, //不固定maxmin: true,content: '/zyk/video/add1'});this.layerIndex = index;};</script>
    </body>
    </html>

    以上是首页列表的页面代码,你可以分析一下并借鉴对你的项目有用的代码!

  2. 现在开始重点说一下添加视频并后台转码
    <!DOCTYPE html>
    <html lang="zh" xmlns:th="http://www.thymeleaf.org" >
    <head><th:block th:include="include :: header('文件上传')" /><th:block th:include="include :: bootstrap-fileinput-css" />
    </head>
    <body class="gray-bg">
    <div class="wrapper wrapper-content animated fadeInRight"><div class="row"><div class="col-sm-12"><div class="ibox float-e-margins"><div class="ibox-title"><h5>新增资源视频转码</h5></div><div class="ibox-content"><div class="container-fluid"><form id="form" action="/zyk/video/upload" method="post" enctype="multipart/form-data"><div class="row form-group"><label class="col-md-4">上传视频:</label><div class="col-sm-12"><input id="input-id" name="file" multiple type="file" data-show-caption="true"></div></div></form><button type="button" class="btn btn-danger" icon="fa-eraser" onclick="ds()"><i class="fa fa-close"></i>取消</button></div><hr></div></div></div></div>
    </div>
    <th:block th:include="include :: footer" />
    <th:block th:include="include :: bootstrap-fileinput-js" />
    <script>/*** 关闭此对话框*/function ds() {var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引parent.layer.close(index); //再执行关闭window.location.href="/zyk/video";}
    </script>
    <script type="text/javascript">$(function () {initFileInput("input-id");})function initFileInput(ctrlName) {var control = $('#' + ctrlName);control.fileinput({language: 'zh', //设置语言uploadUrl: "/zyk/video/upload", //上传的地址allowedFileExtensions: ['jpg', 'gif', 'png','mp4'],//接收的文件后缀//uploadExtraData:{"id": 1, "fileName":'123.mp3'},uploadAsync: true, //默认异步上传showUpload: true, //是否显示上传按钮showRemove : true, //显示移除按钮showPreview : true, //是否显示预览showCaption: false,//是否显示标题browseClass: "btn btn-primary", //按钮样式dropZoneEnabled: true,//是否显示拖拽区域//minImageWidth: 50, //图片的最小宽度//minImageHeight: 50,//图片的最小高度//maxImageWidth: 1000,//图片的最大宽度//maxImageHeight: 1000,//图片的最大高度//maxFileSize: 0,//单位为kb,如果为0表示不限制文件大小//minFileCount: 0,//maxFileCount: 10, //表示允许同时上传的最大文件个数enctype: 'multipart/form-data',validateInitialCount:true,previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!",}).on('filepreupload', function(event, data, previewId, index) {//上传中var form = data.form,files = data.files,extra = data.extra,response = data.response,reader = data.reader;console.log('文件正在上传');}).on("fileuploaded", function (event, data, previewId, index) {//一个文件上传成功console.log('文件上传成功!'+data);}).on('fileerror', function(event, data, msg) {//一个文件上传失败console.log('文件上传失败!'+data);})}function initFileInput1(ctrlName) {var control = $('#' + ctrlName);control.fileinput({language: 'zh', //设置语言uploadUrl: "/zyk/video/upload", //上传的地址allowedFileExtensions: ['jpg', 'gif', 'png','mp4'],//接收的文件后缀//uploadExtraData:{"id": 1, "fileName":'123.mp3'},uploadAsync: true, //默认异步上传showUpload: true, //是否显示上传按钮showRemove : true, //显示移除按钮showPreview : true, //是否显示预览showCaption: false,//是否显示标题browseClass: "btn btn-primary", //按钮样式dropZoneEnabled: true,//是否显示拖拽区域//minImageWidth: 50, //图片的最小宽度//minImageHeight: 50,//图片的最小高度//maxImageWidth: 1000,//图片的最大宽度//maxImageHeight: 1000,//图片的最大高度//maxFileSize: 0,//单位为kb,如果为0表示不限制文件大小//minFileCount: 0,//maxFileCount: 10, //表示允许同时上传的最大文件个数enctype: 'multipart/form-data',validateInitialCount:true,previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!",}).on('filepreupload', function(event, data, previewId, index) {//上传中var form = data.form,files = data.files,extra = data.extra,response = data.response,reader = data.reader;console.log('文件正在上传');}).on("fileuploaded", function (event, data, previewId, index) {//一个文件上传成功console.log('文件上传成功!'+data);}).on('fileerror', function(event, data, msg) {//一个文件上传失败console.log('文件上传失败!'+data);})}function initFileInput2(ctrlName) {var control = $('#' + ctrlName);control.fileinput({language: 'zh', //设置语言uploadUrl: "/zyk/video/upload", //上传的地址allowedFileExtensions: ['jpg', 'gif', 'png','mp4'],//接收的文件后缀//uploadExtraData:{"id": 1, "fileName":'123.mp3'},uploadAsync: true, //默认异步上传showUpload: true, //是否显示上传按钮showRemove : true, //显示移除按钮showPreview : true, //是否显示预览showCaption: false,//是否显示标题browseClass: "btn btn-primary", //按钮样式dropZoneEnabled: true,//是否显示拖拽区域//minImageWidth: 50, //图片的最小宽度//minImageHeight: 50,//图片的最小高度//maxImageWidth: 1000,//图片的最大宽度//maxImageHeight: 1000,//图片的最大高度//maxFileSize: 0,//单位为kb,如果为0表示不限制文件大小//minFileCount: 0,//maxFileCount: 10, //表示允许同时上传的最大文件个数enctype: 'multipart/form-data',validateInitialCount:true,previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!",}).on('filepreupload', function(event, data, previewId, index) {//上传中var form = data.form,files = data.files,extra = data.extra,response = data.response,reader = data.reader;console.log('文件正在上传');}).on("fileuploaded", function (event, data, previewId, index) {//一个文件上传成功console.log('文件上传成功!'+data);}).on('fileerror', function(event, data, msg) {//一个文件上传失败console.log('文件上传失败!'+data);})}
    </script>
    </body>
    </html>
    

    上面是添加视频页面,这里面有webuploader的百度上传图片或者视频插件,需要引入与它有关的js,不知道可以百度一下就知道了,这个用法在上面的注释中是不是已经很详细了。

  3. 看到上面的add页面中有上传的路径,那就说明在页面上添加完视频后就要提交的,那下面就是controller中接口的实现。

    package com.ruoyi.system.controller;import java.io.*;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;import com.alibaba.fastjson.JSONObject;
    import com.ruoyi.system.tool.ConverVideoTest;
    import com.ruoyi.system.tool.FfmpegTest;
    import org.apache.shiro.authz.annotation.RequiresPermissions;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.annotation.*;
    import com.ruoyi.common.annotation.Log;
    import com.ruoyi.common.enums.BusinessType;
    import com.ruoyi.system.domain.ZykVideo;
    import com.ruoyi.system.service.IZykVideoService;
    import com.ruoyi.common.core.controller.BaseController;
    import com.ruoyi.common.core.domain.AjaxResult;
    import com.ruoyi.common.utils.poi.ExcelUtil;
    import com.ruoyi.common.core.page.TableDataInfo;
    import org.springframework.web.multipart.MultipartFile;
    import org.springframework.web.multipart.commons.CommonsMultipartFile;
    import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;/*** 视频转码Controller* * @author yuliujun* @date 2019-10-30*/
    @Controller
    @RequestMapping("/zyk/video")
    public class ZykVideoController extends BaseController
    {private String prefix = "zyk/video";@Autowiredprivate IZykVideoService zykVideoService;Map<String,String> map = new HashMap<>();/*** @Description:(视频资源的单独上传的接收)* @param:@param request* @param:@param response* @param:@param session* @param:@return* @version:V1.0*/@RequestMapping(value = "/upload",method =RequestMethod.POST)@ResponseBody       //@RequestPart("file") MultipartFile file,public JSONObject uploadflie_Video(@RequestParam(name = "file",required = false) MultipartFile file, HttpServletResponse req, HttpServletRequest request) {System.out.println("进入addVideo视频上传控制层");String NewVideopath =null;String filename2 =null;if (file.getSize() != 0) {//上传的多格式的视频文件-作为临时路径保存,转码以后删除-路径不能写//String path = "E://javaEdit//temp/";File TempFile = new File(path);if (TempFile.exists()) {if (TempFile.isDirectory()) {System.out.println("该文件夹存在!!!!!!!!!!!!!!!!");}else {System.out.println("同名的文件存在,不能创建文件夹。");}}else {System.out.println("文件夹不存在,创建该文件夹。");TempFile.mkdir();}// 获取上传时候的文件名String filename = file.getOriginalFilename();// 获取文件后缀名String filename_extension = filename.substring(filename.lastIndexOf(".") + 1);System.out.println("视频的后缀名:"+filename_extension);//时间戳做新的文件名,避免中文乱码-重新生成filenamelong filename1 = new  Date().getTime();filename = Long.toString(filename1)+"."+filename_extension;//去掉后缀的文件名filename2 = filename.substring(0, filename.lastIndexOf("."));System.out.println("视频名为:"+filename2);//源视频地址+重命名后的视频名+视频后缀String yuanPATH =(path+filename);System.out.println("视频的完整文件名1:"+filename);System.out.println("源视频路径为:"+yuanPATH);//上传到本地磁盘/服务器try {System.out.println("写入本地磁盘/服务器");InputStream is = file.getInputStream();OutputStream os = new FileOutputStream(new File(path, filename));int len = 0;byte[] buffer = new byte[2048];while ((len = is.read(buffer)) != -1) {os.write(buffer, 0, len);}os.close();os.flush();is.close();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("========上传完成,开始调用转码工具类=======");//调用转码机制flv mp4 f4v m3u8 webm ogg放行直接播放,//asx,asf,mpg,wmv,3gp,mov,avi,wmv9,rm,rmvb等进行其他转码为mp4if (filename_extension.equals("avi") || filename_extension.equals("rm")|| filename_extension.equals("rmvb") || filename_extension.equals("wmv")|| filename_extension.equals("3gp")  || filename_extension.equals("mov")||filename_extension.equals("flv")   || filename_extension.equals("ogg")||filename_extension.equals("mp4")) {ConverVideoTest c = new ConverVideoTest();c.run(yuanPATH);   //调用转码System.out.println("=================转码过程彻底结束=====================");}//获取转码后的mp4文件名String Mp4path = "D://ruoyi/uploadPath//";filename2 = filename2+".mp4";NewVideopath =Mp4path +filename2;System.out.println("新视频的url:"+NewVideopath);FfmpegTest ffmpegTest = new FfmpegTest();map = ffmpegTest.getVideoTime(NewVideopath);System.out.println("视频时间长度======================:"+map.get("time"));//删除临时文件File file2 = new File(path);if (!file2.exists()) {System.out.println("没有该文件");}if (!file2.isDirectory()) {System.out.println("没有该文件夹");}String[] tempList = file2.list();File temp = null;for (int i = 0; i < tempList.length; i++) {if (path.endsWith(File.separator)) {temp = new File(path + tempList[i]);} else {temp = new File(path + File.separator + tempList[i]);}if (temp.isFile() || temp.isDirectory()) {temp.delete();        //删除文件夹里面的文件}}System.out.println("所有的临时视频文件删除成功");//已转码后的视频存放地址NewVideopath}JSONObject json = new JSONObject();ZykVideo zykVideo = new ZykVideo();zykVideo.setVideoPicurl(filename2.substring(0, filename2.lastIndexOf("."))+".jpg");zykVideo.setVideoTimecount(map.get("time"));zykVideo.setVideoTitle(file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf(".")));zykVideo.setVideoUrl(filename2);zykVideoService.insertZykVideo(zykVideo);json.put("code",200);return json;}@RequiresPermissions("zyk:video:view")@GetMapping()public String video(){return prefix + "/video";}/*** 查询视频转码列表*/@RequiresPermissions("zyk:video:list")@PostMapping("/list")@ResponseBodypublic TableDataInfo list(ZykVideo zykVideo){startPage();List<ZykVideo> list = zykVideoService.selectZykVideoList(zykVideo);return getDataTable(list);}/*** 导出视频转码列表*/@RequiresPermissions("zyk:video:export")@PostMapping("/export")@ResponseBodypublic AjaxResult export(ZykVideo zykVideo){List<ZykVideo> list = zykVideoService.selectZykVideoList(zykVideo);ExcelUtil<ZykVideo> util = new ExcelUtil<ZykVideo>(ZykVideo.class);return util.exportExcel(list, "video");}/*** 新增视频转码*/@GetMapping("/add1")public String add1() {System.out.println("请求进入接口中==========================");return prefix + "/addvideo";}/*** 新增保存视频转码*/@RequiresPermissions("zyk:video:add")@Log(title = "视频转码", businessType = BusinessType.INSERT)@PostMapping("/add")@ResponseBodypublic AjaxResult addSave(ZykVideo zykVideo){return toAjax(zykVideoService.insertZykVideo(zykVideo));}/*** 修改视频转码*/@GetMapping("/edit/{videoId}")public String edit(@PathVariable("videoId") Long videoId, ModelMap mmap){ZykVideo zykVideo = zykVideoService.selectZykVideoById(videoId);mmap.put("zykVideo", zykVideo);return prefix + "/edit";}/*** 修改保存视频转码*/@RequiresPermissions("zyk:video:edit")@Log(title = "视频转码", businessType = BusinessType.UPDATE)@PostMapping("/edit")@ResponseBodypublic AjaxResult editSave(ZykVideo zykVideo){return toAjax(zykVideoService.updateZykVideo(zykVideo));}/*** 删除视频转码*/@RequiresPermissions("zyk:video:remove")@Log(title = "视频转码", businessType = BusinessType.DELETE)@PostMapping( "/remove")@ResponseBodypublic AjaxResult remove(String ids) {System.out.println("删除功能接收的ids"+ids);String[] arr = ids.split(",");for (int i = 0; i < arr.length ; i++) {System.out.println("遍历的每个id:=================="+arr[i]);ZykVideo zykVideo =  zykVideoService.selectZykVideoById((long)Integer.parseInt(arr[i]));File file = new File("D://ruoyi/uploadPath//"+zykVideo.getVideoUrl());file.delete();File file1 = new File("D://ruoyi/uploadPath//"+zykVideo.getVideoPicurl());file1.delete();}return toAjax(zykVideoService.deleteZykVideoByIds(ids));}
    }
    

    不要急,上面的代码中第一个接口中upload中需要转码工具类和需要用到ffmpeg转码工具和mencoder转码工具,其实就是两个exe执行文件,关于ffmpeg怎么实现转码,你要去看一下它的用法,主要是参数设置,执行得到的转码结果,我会写一篇ffmpeg的参数用法,你也可以观看一下!下面我就贴出需要在接口用到的转码工具类和转码文件的存放位置工具类。

  4. 首先是转码文件的存放位置工具类。

    package com.ruoyi.system.tool;public class Contants {/*** @Description:(3.工具类主类)设置转码工具的各个路径* @param:@param args* @return:void* @author:于留俊* @date:2019-11-2* @version:V1.0*/public static final String ffmpegpath = "E://javaEdit//ffmpeg//bin//ffmpeg.exe";        // ffmpeg工具安装位置public static final String mencoderpath = "E://javaEdit//mencoder//mencoder.exe";    // mencoder工具安装的位置public static final String videofolder = "E://javaEdit//temp1/";  // 需要被转换格式的视频目录public static final String videoRealPath = "E://javaEdit//temp2/";   // 需要被截图的视频目录public static final String targetfolder = "D://ruoyi/uploadPath//"; // 转码后视频保存的目录public static final String imageRealPath = "D://ruoyi/uploadPath//"; // 截图的存放目录}

    其次是转码工具类:

    package com.ruoyi.system.tool;import java.io.*;
    import java.util.ArrayList;
    import java.util.List;/**** @Title: ConverVideoUtils.java* @Package:com.resource.mytools* @Description:(2.转码和截图功能)* @see:接收Contants实体的路径* @author:于留俊* @date:2019-11-02* @version:V1.0*/public class ConverVideoUtils {private String sourceVideoPath;                          //源视频路径private String filerealname;                         //文件名不包括后缀名private String filename;                                 //包括后缀名private String videofolder = Contants.videofolder;       // 别的格式视频的目录private String targetfolder = Contants.targetfolder;    // flv视频的目录private String ffmpegpath = Contants.ffmpegpath;      // ffmpeg.exe的目录private String mencoderpath = Contants.mencoderpath;   // mencoder的目录private String imageRealPath = Contants.imageRealPath;   // 截图的存放目录public ConverVideoUtils() {}//重构构造方法,传入源视频public ConverVideoUtils(String path) {sourceVideoPath = path;}//set和get方法传递pathpublic String getPATH() {return sourceVideoPath;}public void setPATH(String path) {sourceVideoPath = path;}/*** 转换视频格式* @param String targetExtension 目标视频后缀名 .xxx* @param boolean isDelSourseFile 转换完成后是否删除源文件* @return*/public boolean beginConver(String targetExtension, boolean isDelSourseFile) {File fi = new File(sourceVideoPath);filename = fi.getName();             //获取文件名+后缀名filerealname = filename.substring(0, filename.lastIndexOf(".")); //获取不带后缀的文件名-后面加.toLowerCase()小写System.out.println("----接收到文件("+sourceVideoPath+")需要转换-------");//检测本地是否存在/*if (checkfile(sourceVideoPath)) {System.out.println(sourceVideoPath + "========该文件存在哟 ");return false;}*/System.out.println("----开始转文件(" + sourceVideoPath + ")-------------------------- ");//执行转码机制if (process(targetExtension,isDelSourseFile)) {System.out.println("视频转码结束,开始截图================= ");//视频转码完成,调用截图功能--zoutaoif (processImg(sourceVideoPath)) {System.out.println("截图成功! ");} else {System.out.println("截图失败! ");}//删除原视频+临时视频/*if (isDelSourseFile) {deleteFile(sourceVideoPath);}*//*File file1 = new File(sourceVideoPath);if (file1.exists()){System.out.println("删除原文件-可用:"+sourceVideoPath);file1.delete();}*/String temppath=videofolder + filerealname + ".avi";File file2 = new File(temppath);if (file2.exists()){System.out.println("删除临时文件:"+temppath);file2.delete();}sourceVideoPath = null;return true;} else {sourceVideoPath = null;return false;}}/*** 检查文件是否存在-多处都有判断* @param path* @return*//*private boolean checkfile(String path) {path = sourceVideoPath;File file = new File(path);try {if (file.exists()) {System.out.println("视频文件不存在============="+path);return true;} else {System.out.println("视频文件存在"+path);return false;}} catch (Exception e) {// TODO: handle exceptionSystem.out.println("拒绝对文件进行读访问");}return false;}*//*** 视频截图功能* @param sourceVideoPath 需要被截图的视频路径(包含文件名和后缀名)* @return*/public boolean processImg(String sourceVideoPath) {//先确保保存截图的文件夹存在File TempFile = new File(imageRealPath);if (TempFile.exists()) {if (TempFile.isDirectory()) {System.out.println("该文件夹存在!!!!!!!!");}else {System.out.println("同名的文件存在,不能创建文件夹。");}}else {System.out.println("文件夹不存在,创建该文件夹。");TempFile.mkdir();}File fi = new File(sourceVideoPath);filename = fi.getName();           //获取视频文件的名称。filerealname = filename.substring(0, filename.lastIndexOf("."));    //获取视频名+不加后缀名 后面加.toLowerCase()转为小写List<String> commend = new ArrayList<String>();//第一帧: 00:00:01//截图命令:time ffmpeg -ss 00:00:01 -i test1.flv -f image2 -y test1.jpgcommend.add(ffmpegpath);          //指定ffmpeg工具的路径commend.add("-ss");commend.add("00:00:01");          //1是代表第1秒的时候截图commend.add("-i");commend.add(sourceVideoPath);       //截图的视频路径commend.add("-f");commend.add("image2");commend.add("-y");commend.add(imageRealPath + filerealname + ".jpg");      //生成截图xxx.jpg//打印截图命令--zoutaoStringBuffer test = new StringBuffer();for (int i = 0; i < commend.size(); i++) {test.append(commend.get(i) + " ");}System.out.println("截图命令:"+test);//转码后完成截图功能-还是得用线程来解决--zoutaotry {/*ProcessBuilder builder = new ProcessBuilder();builder.command(commend);Process p =builder.start();*///调用线程处理命令ProcessBuilder builder = new ProcessBuilder();builder.command(commend);Process p = builder.start();//获取进程的标准输入流final InputStream is1 = p.getInputStream();//获取进程的错误流final InputStream is2 = p.getErrorStream();//启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流new Thread() {public void run() {BufferedReader br = new BufferedReader(new InputStreamReader(is1));try {String lineB = null;while ((lineB = br.readLine()) != null) {if (lineB != null){System.out.println(lineB);    //必须取走线程信息避免堵塞}}} catch (IOException e) {e.printStackTrace();}//关闭流finally{try {is1.close();} catch (IOException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));try {String lineC = null;while ((lineC = br2.readLine()) != null) {if (lineC != null)   {//System.out.println(lineC);   //必须取走线程信息避免堵塞}}} catch (IOException e) {e.printStackTrace();}//关闭流finally{try {is2.close();} catch (IOException e) {e.printStackTrace();}}}}.start();// 等Mencoder进程转换结束,再调用ffmepg进程非常重要!!!p.waitFor();System.out.println("截图进程结束");return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 实际转换视频格式的方法* @param targetExtension 目标视频后缀名* @param isDelSourseFile 转换完成后是否删除源文件* @return*/private boolean process(String targetExtension, boolean isDelSourseFile) {//先判断视频的类型-返回状态码int type = checkContentType();boolean status = false;//根据状态码处理if (type == 0) {System.out.println("ffmpeg可以转换,统一转为mp4文件");status = processVideoFormat(sourceVideoPath,targetExtension,isDelSourseFile);//可以指定转换为什么格式的视频} else if (type == 1) {//如果type为1,将其他文件先转换为avi,然后在用ffmpeg转换为指定格式System.out.println("ffmpeg不可以转换,先调用mencoder转码avi");String avifilepath = processAVI(type);if (avifilepath == null){// 转码失败--avi文件没有得到System.out.println("mencoder转码失败,未生成AVI文件");return false;}else {System.out.println("生成AVI文件成功,ffmpeg开始转码:");status = processVideoFormat(avifilepath,targetExtension,isDelSourseFile);}}return status;   //执行完成返回布尔类型true}/*** 检查文件类型* @return*/private int checkContentType() {//取得视频后缀-String type = sourceVideoPath.substring(sourceVideoPath.lastIndexOf(".") + 1, sourceVideoPath.length()).toLowerCase();System.out.println("源视频类型为:"+type);// 如果是ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)if (type.equals("avi")) {return 0;} else if (type.equals("mpg")) {return 0;} else if (type.equals("wmv")) {return 0;} else if (type.equals("3gp")) {return 0;} else if (type.equals("mov")) {return 0;} else if (type.equals("mp4")) {return 0;} else if (type.equals("asf")) {return 0;} else if (type.equals("asx")) {return 0;} else if (type.equals("flv")) {return 0;}else if (type.equals("mkv")) {return 0;}// 如果是ffmpeg无法解析的文件格式(wmv9,rm,rmvb等),// 就先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.else if (type.equals("wmv9")) {return 1;} else if (type.equals("rm")) {return 1;} else if (type.equals("rmvb")) {return 1;}System.out.println("上传视频格式异常");return 9;}/***  对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等),*  可以先用(mencoder)转换为avi(ffmpeg能解析的)格式.再用ffmpeg解析为指定格式* @param type* @return*/private String processAVI(int type) {System.out.println("调用了mencoder.exe工具");List<String> commend = new ArrayList<String>();commend.add(mencoderpath);                //指定mencoder.exe工具的位置commend.add(sourceVideoPath);             //指定源视频的位置commend.add("-oac");commend.add("mp3lame");         //lavc 原mp3lamecommend.add("-lameopts");commend.add("preset=64");commend.add("-ovc");commend.add("xvid");       //mpg4(xvid),AVC(h.264/x264),只有h264才是公认的MP4标准编码,如果ck播放不了,就来调整这里commend.add("-xvidencopts");  //xvidencopts或x264encoptscommend.add("bitrate=600");     //600或440commend.add("-of");commend.add("avi");commend.add("-o");commend.add(videofolder + filerealname + ".avi");   //存放路径+名称,生成.avi视频//打印出转换命令-zoutaoStringBuffer test = new StringBuffer();for (int i = 0; i < commend.size(); i++) {test.append(commend.get(i) + " ");}System.out.println("mencoder输入的命令:"+test);// cmd命令:mencoder 1.rmvb -oac mp3lame -lameopts preset=64 -ovc xvid// -xvidencopts bitrate=600 -of avi -o rmvb.avitry {//调用线程命令启动转码ProcessBuilder builder = new ProcessBuilder();builder.command(commend);Process p = builder.start();   //多线程处理加快速度-解决数据丢失//doWaitFor(p);//获取进程的标准输入流final InputStream is1 = p.getInputStream();//获取进程的错误流final InputStream is2 = p.getErrorStream();//启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流new Thread() {public void run() {BufferedReader br = new BufferedReader(new InputStreamReader(is1));try {String lineB = null;while ((lineB = br.readLine()) != null) {if (lineB != null){System.out.println();System.out.println(lineB);    //打印mencoder转换过程代码-可注释}}} catch (IOException e) {e.printStackTrace();}//关闭流/* finally{try {is1.close();} catch (IOException e) {e.printStackTrace();}}  */}}.start();new Thread() {public void run() {BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));try {String lineC = null;while ((lineC = br2.readLine()) != null) {if (lineC != null)   {System.out.println(lineC);    //打印mencoder转换过程代码}}} catch (IOException e) {e.printStackTrace();}//关闭/* finally{try {is2.close();} catch (IOException e) {e.printStackTrace();}} */}}.start();// 等Mencoder进程转换结束,再调用ffmepg进程非常重要!!!p.waitFor();System.out.println("Mencoder进程结束");return videofolder + filerealname + ".avi";      //返回转为AVI以后的视频地址} catch (Exception e) {e.printStackTrace();return null;}}/*** 转换为指定格式--zoutao* ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)* @param oldfilepath* @param targetExtension 目标格式后缀名 .xxx* @param isDelSourseFile 转换完成后是否删除源文件* @return*/private boolean processVideoFormat(String oldfilepath, String targetExtension, boolean isDelSourceFile) {System.out.println("调用了ffmpeg.exe工具");//先确保保存转码后的视频的文件夹存在File TempFile = new File(targetfolder);if (TempFile.exists()) {if (TempFile.isDirectory()) {System.out.println("该文件夹存在。");}else {System.out.println("同名的文件存在,不能创建文件夹。");}}else {System.out.println("文件夹不存在,创建该文件夹。");TempFile.mkdir();}List<String> commend = new ArrayList<String>();commend.add(ffmpegpath);       //ffmpeg.exe工具地址commend.add("-i");commend.add(oldfilepath);            //源视频路径commend.add("-vcodec");commend.add("h263");  //commend.add("-ab");       //新增4条commend.add("128");      //高品质:128 低品质:64commend.add("-acodec");commend.add("mp3");      //音频编码器:原libmp3lamecommend.add("-ac");commend.add("2");       //原1commend.add("-ar");commend.add("22050");   //音频采样率22.05kHzcommend.add("-r");commend.add("29.97");  //高品质:29.97 低品质:15commend.add("-c:v");commend.add("libx264");    //视频编码器:视频是h.264编码格式commend.add("-strict");commend.add("-2");commend.add(targetfolder + filerealname + targetExtension);  // //转码后的路径+名称,是指定后缀的视频//打印命令--zoutaoStringBuffer test = new StringBuffer();for (int i = 0; i < commend.size(); i++) {test.append(commend.get(i) + " ");}System.out.println("ffmpeg输入的命令:"+test);try {//多线程处理加快速度-解决rmvb数据丢失builder名称要相同ProcessBuilder builder = new ProcessBuilder();builder.command(commend);Process p = builder.start();   //多线程处理加快速度-解决数据丢失final InputStream is1 = p.getInputStream();final InputStream is2 = p.getErrorStream();new Thread() {public void run() {BufferedReader br = new BufferedReader(new InputStreamReader(is1));try {String lineB = null;while ((lineB = br.readLine()) != null) {if (lineB != null)System.out.println();System.out.println(lineB);    //打印mencoder转换过程代码}} catch (IOException e) {e.printStackTrace();}}}.start();new Thread() {public void run() {BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));try {String lineC = null;while ((lineC = br2.readLine()) != null) {if (lineC != null)System.out.println(lineC);    //打印mencoder转换过程代码}} catch (IOException e) {e.printStackTrace();}}}.start();p.waitFor();        //进程等待机制,必须要有,否则不生成mp4!!!System.out.println("生成mp4视频为:"+videofolder + filerealname + ".mp4");return true;}catch (Exception e) {e.printStackTrace();return false;}}
    }
    

    当你的代码写到这里,你把项目启动测试一下,看一下控制台报的信息,每个人的信息大致一样,少一些文件夹等简单信息,那你手动新建一个就好了。同时如果你是springboot项目要做好配置关于保存文件夹的路径,在项目中配置安全路径开放,不然你保存到数据的视频路径在页面中404,我贴出来我的配置!

  5. 首先是yml文件中配置:

    # 项目相关配置
    ruoyi:# 名称name: RuoYi# 版本version: 4.0.0# 版权年份copyrightYear: 2019# 实例演示开关demoEnabled: true# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)profile: D:/ruoyi/uploadPath ## 获取ip地址开关addressEnabled: true

    你可以看到prifile就是视频在页面中保存文件夹路径映射,在页面中展示视频要这样:http://**.**.**.**:8080/profile/****.mp4这样才是播放视频,接下来是映射配置在config中,先在全局参数设置中定义路径名称,从yml配置中可以方便取出,

    package com.ruoyi.common.config;import java.io.FileNotFoundException;
    import java.util.HashMap;
    import java.util.Map;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import com.ruoyi.common.utils.StringUtils;
    import com.ruoyi.common.utils.YamlUtil;/*** 全局配置类* * @author 于留俊*/
    public class Global
    {private static final Logger log = LoggerFactory.getLogger(Global.class);private static String NAME = "application.yml";/*** 当前对象实例*/private static Global global;/*** 保存全局属性值*/private static Map<String, String> map = new HashMap<String, String>();private Global(){}/*** 静态工厂方法*/public static synchronized Global getInstance(){if (global == null){global = new Global();}return global;}/*** 获取配置*/public static String getConfig(String key){String value = map.get(key);if (value == null){Map<?, ?> yamlMap = null;try{yamlMap = YamlUtil.loadYaml(NAME);value = String.valueOf(YamlUtil.getProperty(yamlMap, key));map.put(key, value != null ? value : StringUtils.EMPTY);}catch (FileNotFoundException e){log.error("获取全局配置异常 {}", key);}}return value;}/*** 获取项目名称*/public static String getName(){return StringUtils.nvl(getConfig("ruoyi.name"), "RuoYi");}/*** 获取项目版本*/public static String getVersion(){return StringUtils.nvl(getConfig("ruoyi.version"), "4.0.0");}/*** 获取版权年份*/public static String getCopyrightYear(){return StringUtils.nvl(getConfig("ruoyi.copyrightYear"), "2019");}/*** 实例演示开关*/public static String isDemoEnabled(){return StringUtils.nvl(getConfig("ruoyi.demoEnabled"), "true");}/*** 获取ip地址开关*/public static Boolean isAddressEnabled(){return Boolean.valueOf(getConfig("ruoyi.addressEnabled"));}/*** 获取文件上传路径*/public static String getProfile(){return getConfig("ruoyi.profile");}/*** 获取头像上传路径*/public static String getAvatarPath(){return getProfile() + "/avatar";}/*** 获取下载路径*/public static String getDownloadPath(){return getProfile() + "/download/";}/*** 获取上传路径*/public static String getUploadPath(){return getProfile() + "/upload";}
    }
    

    这个通用配置,用过的朋友,肯定知道这是配置文件,接口文档等的配置。

    package com.ruoyi.framework.config;import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import com.ruoyi.common.config.Global;
    import com.ruoyi.common.constant.Constants;
    import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;/*** 通用配置* * @author 于留俊*/
    @Configuration
    public class ResourcesConfig implements WebMvcConfigurer {/*** 首页地址*/@Value("${shiro.user.indexUrl}")private String indexUrl;@Autowiredprivate RepeatSubmitInterceptor repeatSubmitInterceptor;/*** 默认首页的设置,当输入域名是可以自动跳转到默认指定的网页*/@Overridepublic void addViewControllers(ViewControllerRegistry registry){registry.addViewController("/").setViewName("forward:" + indexUrl);}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry){/** 本地文件上传路径 */registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + Global.getProfile() + "/");/** swagger配置 */registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}/*** 自定义拦截规则*/@Overridepublic void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");}
    }

    这里的mvc映射文件,都是通用设置,你要是是在不会,就去百度一下,各个设置的作用,其中的

    Constants是个工具类,配置全局参数的,贴出来
    package com.ruoyi.common.constant;/*** 通用常量信息* * @author 于留俊*/
    public class Constants
    {/*** UTF-8 字符集*/public static final String UTF8 = "UTF-8";/*** 通用成功标识*/public static final String SUCCESS = "0";/*** 通用失败标识*/public static final String FAIL = "1";/*** 登录成功*/public static final String LOGIN_SUCCESS = "Success";/*** 注销*/public static final String LOGOUT = "Logout";/*** 登录失败*/public static final String LOGIN_FAIL = "Error";/*** 自动去除表前缀*/public static final String AUTO_REOMVE_PRE = "true";/*** 当前记录起始索引*/public static final String PAGE_NUM = "pageNum";/*** 每页显示记录数*/public static final String PAGE_SIZE = "pageSize";/*** 排序列*/public static final String ORDER_BY_COLUMN = "orderByColumn";/*** 排序的方向 "desc" 或者 "asc".*/public static final String IS_ASC = "isAsc";/*** 资源映射路径 前缀*/public static final String RESOURCE_PREFIX = "/profile";
    }
    
    还有这里需要在ShiroConfig中配置一下profile不需要验证,我把配置文件贴出,你可以加入项目试一下,好用!
    package com.ruoyi.framework.config;import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.LinkedHashMap;
    import java.util.Map;
    import javax.servlet.Filter;
    import org.apache.commons.io.IOUtils;
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.codec.Base64;
    import org.apache.shiro.config.ConfigurationException;
    import org.apache.shiro.io.ResourceUtils;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.CookieRememberMeManager;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.apache.shiro.web.servlet.SimpleCookie;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import com.ruoyi.common.utils.StringUtils;
    import com.ruoyi.common.utils.spring.SpringUtils;
    import com.ruoyi.framework.shiro.realm.UserRealm;
    import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
    import com.ruoyi.framework.shiro.session.OnlineSessionFactory;
    import com.ruoyi.framework.shiro.web.filter.LogoutFilter;
    import com.ruoyi.framework.shiro.web.filter.captcha.CaptchaValidateFilter;
    import com.ruoyi.framework.shiro.web.filter.kickout.KickoutSessionFilter;
    import com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter;
    import com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter;
    import com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager;
    import com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler;
    import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;/*** 权限配置加载* * @author ruoyi*/
    @Configuration
    public class ShiroConfig
    {public static final String PREMISSION_STRING = "perms[\"{0}\"]";// Session超时时间,单位为毫秒(默认30分钟)@Value("${shiro.session.expireTime}")private int expireTime;// 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟@Value("${shiro.session.validationInterval}")private int validationInterval;// 同一个用户最大会话数@Value("${shiro.session.maxSession}")private int maxSession;// 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户@Value("${shiro.session.kickoutAfter}")private boolean kickoutAfter;// 验证码开关@Value("${shiro.user.captchaEnabled}")private boolean captchaEnabled;// 验证码类型@Value("${shiro.user.captchaType}")private String captchaType;// 设置Cookie的域名@Value("${shiro.cookie.domain}")private String domain;// 设置cookie的有效访问路径@Value("${shiro.cookie.path}")private String path;// 设置HttpOnly属性@Value("${shiro.cookie.httpOnly}")private boolean httpOnly;// 设置Cookie的过期时间,秒为单位@Value("${shiro.cookie.maxAge}")private int maxAge;// 登录地址@Value("${shiro.user.loginUrl}")private String loginUrl;// 权限认证失败地址@Value("${shiro.user.unauthorizedUrl}")private String unauthorizedUrl;/*** 缓存管理器 使用Ehcache实现*/@Beanpublic EhCacheManager getEhCacheManager(){net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi");EhCacheManager em = new EhCacheManager();if (StringUtils.isNull(cacheManager)){em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));return em;}else{em.setCacheManager(cacheManager);return em;}}/*** 返回配置文件流 避免ehcache配置文件一直被占用,无法完全销毁项目重新部署*/protected InputStream getCacheManagerConfigFileInputStream(){String configFile = "classpath:ehcache/ehcache-shiro.xml";InputStream inputStream = null;try{inputStream = ResourceUtils.getInputStreamForPath(configFile);byte[] b = IOUtils.toByteArray(inputStream);InputStream in = new ByteArrayInputStream(b);return in;}catch (IOException e){throw new ConfigurationException("Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e);}finally{IOUtils.closeQuietly(inputStream);}}/*** 自定义Realm*/@Beanpublic UserRealm userRealm(EhCacheManager cacheManager){UserRealm userRealm = new UserRealm();userRealm.setCacheManager(cacheManager);return userRealm;}/*** 自定义sessionDAO会话*/@Beanpublic OnlineSessionDAO sessionDAO(){OnlineSessionDAO sessionDAO = new OnlineSessionDAO();return sessionDAO;}/*** 自定义sessionFactory会话*/@Beanpublic OnlineSessionFactory sessionFactory(){OnlineSessionFactory sessionFactory = new OnlineSessionFactory();return sessionFactory;}/*** 会话管理器*/@Beanpublic OnlineWebSessionManager sessionManager(){OnlineWebSessionManager manager = new OnlineWebSessionManager();// 加入缓存管理器manager.setCacheManager(getEhCacheManager());// 删除过期的sessionmanager.setDeleteInvalidSessions(true);// 设置全局session超时时间manager.setGlobalSessionTimeout(expireTime * 60 * 1000);// 去掉 JSESSIONIDmanager.setSessionIdUrlRewritingEnabled(false);// 定义要使用的无效的Session定时调度器manager.setSessionValidationScheduler(SpringUtils.getBean(SpringSessionValidationScheduler.class));// 是否定时检查sessionmanager.setSessionValidationSchedulerEnabled(true);// 自定义SessionDaomanager.setSessionDAO(sessionDAO());// 自定义sessionFactorymanager.setSessionFactory(sessionFactory());return manager;}/*** 安全管理器*/@Beanpublic SecurityManager securityManager(UserRealm userRealm, SpringSessionValidationScheduler springSessionValidationScheduler){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 设置realm.securityManager.setRealm(userRealm);// 记住我securityManager.setRememberMeManager(rememberMeManager());// 注入缓存管理器;securityManager.setCacheManager(getEhCacheManager());// session管理器securityManager.setSessionManager(sessionManager());return securityManager;}/*** 退出过滤器*/public LogoutFilter logoutFilter(){LogoutFilter logoutFilter = new LogoutFilter();logoutFilter.setCacheManager(getEhCacheManager());logoutFilter.setLoginUrl(loginUrl);return logoutFilter;}/*** Shiro过滤器配置*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// Shiro的核心安全接口,这个属性是必须的shiroFilterFactoryBean.setSecurityManager(securityManager);// 身份认证失败,则跳转到登录页面的配置shiroFilterFactoryBean.setLoginUrl(loginUrl);// 权限认证失败,则跳转到指定页面shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);// Shiro连接约束配置,即过滤链的定义LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 对静态资源设置匿名访问filterChainDefinitionMap.put("/favicon.ico**", "anon");filterChainDefinitionMap.put("/ruoyi.png**", "anon");filterChainDefinitionMap.put("/profile/**", "anon");filterChainDefinitionMap.put("/css/**", "anon");filterChainDefinitionMap.put("/docs/**", "anon");filterChainDefinitionMap.put("/fonts/**", "anon");filterChainDefinitionMap.put("/img/**", "anon");filterChainDefinitionMap.put("/ajax/**", "anon");filterChainDefinitionMap.put("/js/**", "anon");filterChainDefinitionMap.put("/ruoyi/**", "anon");filterChainDefinitionMap.put("/druid/**", "anon");filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");// 退出 logout地址,shiro去清除sessionfilterChainDefinitionMap.put("/logout", "logout");// 不需要拦截的访问filterChainDefinitionMap.put("/login", "anon,captchaValidate");// 系统权限列表// filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());Map<String, Filter> filters = new LinkedHashMap<String, Filter>();filters.put("onlineSession", onlineSessionFilter());filters.put("syncOnlineSession", syncOnlineSessionFilter());filters.put("captchaValidate", captchaValidateFilter());filters.put("kickout", kickoutSessionFilter());// 注销成功,则跳转到指定页面filters.put("logout", logoutFilter());shiroFilterFactoryBean.setFilters(filters);// 所有请求需要认证filterChainDefinitionMap.put("/**", "user,kickout,onlineSession,syncOnlineSession");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}/*** 自定义在线用户处理过滤器*/@Beanpublic OnlineSessionFilter onlineSessionFilter(){OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter();onlineSessionFilter.setLoginUrl(loginUrl);return onlineSessionFilter;}/*** 自定义在线用户同步过滤器*/@Beanpublic SyncOnlineSessionFilter syncOnlineSessionFilter(){SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter();return syncOnlineSessionFilter;}/*** 自定义验证码过滤器*/@Beanpublic CaptchaValidateFilter captchaValidateFilter(){CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter();captchaValidateFilter.setCaptchaEnabled(captchaEnabled);captchaValidateFilter.setCaptchaType(captchaType);return captchaValidateFilter;}/*** cookie 属性设置*/public SimpleCookie rememberMeCookie(){SimpleCookie cookie = new SimpleCookie("rememberMe");cookie.setDomain(domain);cookie.setPath(path);cookie.setHttpOnly(httpOnly);cookie.setMaxAge(maxAge * 24 * 60 * 60);return cookie;}/*** 记住我*/public CookieRememberMeManager rememberMeManager(){CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(rememberMeCookie());cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ=="));return cookieRememberMeManager;}/*** 同一个用户多设备登录限制*/public KickoutSessionFilter kickoutSessionFilter(){KickoutSessionFilter kickoutSessionFilter = new KickoutSessionFilter();kickoutSessionFilter.setCacheManager(getEhCacheManager());kickoutSessionFilter.setSessionManager(sessionManager());// 同一个用户最大的会话数,默认-1无限制;比如2的意思是同一个用户允许最多同时两个人登录kickoutSessionFilter.setMaxSession(maxSession);// 是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;踢出顺序kickoutSessionFilter.setKickoutAfter(kickoutAfter);// 被踢出后重定向到的地址;kickoutSessionFilter.setKickoutUrl("/login?kickout=1");return kickoutSessionFilter;}/*** thymeleaf模板引擎和shiro框架的整合*/@Beanpublic ShiroDialect shiroDialect(){return new ShiroDialect();}/*** 开启Shiro注解通知器*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager){AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}
    }
    
    看到上面的Shiro过滤器配置,这个注释了吗?加入
    filterChainDefinitionMap.put("/profile/**", "anon");这个句代码,就是在调用页面路径的时候放行权限,不然的话你会404!
  6. 我的项目是springboot项目,里面配置这复杂的权限设置和各个项目分模块的maven管理和子父关系的项目依赖,今个先把视频转码的关键技术和上传文件夹的路径配置的方法贴出来,朋友们可以在自己的项目中,测试是否可用,如果有bug,可以留言贴出你的代码,大家一起谈论和解决!

javag关于视频转码技术点分析!相关推荐

  1. 音视频转码技术指南:国内主流云转码服务提供商对比测评

    摘要: 随着大量视频产生,怎样才能够高效精准地对视频进行云端转码和处理,来适配多终端展示需求和应对复杂的网络情况,是我们视频行业开发人员工作的重中之重.作为从业者,我们会经常接触各大云转码服务商,对音 ...

  2. java用ffmpeg转码_java运用FFMPEG视频转码技术.doc

    java运用FFMPEG视频转码技术 基于windows系统安装FFMPEG转码技术 软件特点: 被转视频基本不失真(支持超清.高清.标清): 转码速度比较现成转码软件快非常多(不管文件有多大,此软件 ...

  3. 视频转码能力哪家强?腾讯云、阿里云、七牛云多维度对比

    随着大量视频产生,怎样才能够高效精准地对视频进行云端转码和处理,来适配多终端展示需求和应对复杂的网络情况,是我们视频行业开发人员工作的重中之重.作为从业者,我们会经常接触各大云转码服务商,对音视频转码 ...

  4. 音视频转码FFmpeg

    前言 音视频转码主要指这样的概念: 容器格式的转换,比如MP4转换为MOV 容器中音视频数据编码方式转换,比如H264编码转换成MPEG4编码,MP3换为AAC 音视频码率的转换,比如4M的视频码率降 ...

  5. NVIDIA FFmpeg 转码技术分析

    NVIDIA FFmpeg 转码技术分析 所有从 Kepler 一代开始的 NVIDIA GPUs 都支持完全加速的硬件视频编码,而从费米一代开始的所有 GPUs 都支持完全加速的硬件视频解码.截至 ...

  6. 抖音SEO优化源码,企业号搜索排名系统,技术理论分析搭建。

    前言:抖音SEO优化源码,企业号搜索排名系统,技术理论分析搭建. 抖音seo源码如何搭建?抖音seo排名优化系统软件部分源码分析,代码打包中... 场景:在 python 中,你可以使用 list[1 ...

  7. 移动视频监控业务技术分析

    摘 要 移动视频监控业务结合视频监控业务和移动网络二者的优点,能为用户带来全新的业务体验, 将为运营商开辟新的移动增值业务市场.本文分析移动视频监控业务的技术原理,详细介绍了一种基于 移动流媒体平台实 ...

  8. H265/HEVC视频分层码流分析语义元素解释

    H265/HEVC视频分层码流分析语义元素解释 H265分层结构 H265码流结构 Ffmpge 抽取H264,H265码流的命令 视频参数集VPS 序列参数集SPS(Sequence Paramet ...

  9. 视频管理软件技术分析报告(二)--商业VMS产品分析(Milestone)

    1.公司简介   Milestone(麦视通)公司1998年成立于丹麦,是开放式网络型监控系统(全球领导品牌)的领导厂家.   Milestone是全球第一家开发出网络型开放式平台监控系统的公司.Mi ...

  10. 抖音seo优化源码搭建/搜索排名系统,技术理论分析搭建中。

    抖音seo系统源码SaaS+源码私有化部署搭建,抖音seo源码,抖音seo系统源码,抖音seo系统搭建部署,抖音已经成为了当今最为流行的短视频平台之一,拥有着庞大的用户群体和海量的视频资源.对于一些商 ...

最新文章

  1. c语言visit函数指针,C++中的函数指针总结
  2. 使用CFree调用Win32 LoadLibrary 简单示例
  3. 京瓷打印机几个常见密码
  4. vue实现查询多条记录_sql:多表查询
  5. 解决burpsuite无法对DVWA环境(本地环境)进行抓包
  6. for遍历list scala_面试官问:List 如何一边遍历,一边删除?
  7. jquery file upload 后台收到的文件名中文乱码, filename中文乱码
  8. php ismethod,结合php类三种属性说明is_callable和method_exists简单区别
  9. 使用JSLint提高JS代码质量
  10. 系统架构设计师 - 单体架构、SOA架构、微服务架构
  11. 这座中国小城,靠“造假”称霸一个全球市场
  12. mysql 检查配置_MYSQL 配置检查脚本
  13. CSP-J (初中级别比赛)初赛总结
  14. 计算机找网络共享盘快捷键,电脑共享快捷键不见了怎么办
  15. 博士申请 | 西湖大学智能无人系统实验室招收空中机器人方向全奖博士生
  16. 倡导低碳低成本出行,神州租车用实力说话
  17. 1273-宣传墙(状压dp )
  18. 大数据分析如何使用pandas进行时间序列分析
  19. 笔记:RTSP在线视频流资源地址
  20. 经典运放电路分析—虚短虚断

热门文章

  1. GRUB4DOS入门
  2. java kinect_使用java来做Kinect开发
  3. Arduino作为编程器读写BIOS、bootloader、uboot或者breed
  4. Reader之FileReader、BufferedReader
  5. 大数据时代网络安全问题分析
  6. (后台)Openbravo如何实现业务事件监听处理
  7. QT编译程序出现[ui_Widget.h] Error 1
  8. 三、GTK-按钮(微调按钮、复选按钮、单选按钮)、快捷键、热键
  9. 【网络实验】10G网络下的真实带宽——CPU负载与网卡TSO、GSO
  10. HTML 按钮交互,20 个交互非常棒的按钮代码_html/css_WEB-ITnose