本地视频服务

项目结构 

 服务端

package com.apach.video.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;


@Controller
@RequestMapping("/video")
public class VideoController {

    private String path = "F:\\文件1\\file\\file\\";

    public List<Map<String, String>> videoList() throws UnsupportedEncodingException {
        File file = new File(path);
        if (!file.exists()) {
            return new ArrayList();
        }
        List<Map<String, String>> listMap = new ArrayList<>();
        String[] list = file.list();
        Arrays.sort(list);
        for (int i = 0; i < list.length; i++) {
            Map<String, String> map = new HashMap<>();
            map.put("name", list[i]);
            map.put("name1", URLEncoder.encode(list[i], "utf-8"));
            listMap.add(map);
        }
        return listMap;
    }

    @GetMapping("/index")
    public String index(Model model) throws UnsupportedEncodingException {
        List<Map<String, String>> list = videoList();
        model.addAttribute("list", list);
        return "video";
    }

    @GetMapping("/t3")
    public String t3(Model model, String name) throws UnsupportedEncodingException {
        model.addAttribute("name", name);
        model.addAttribute("name1",URLDecoder.decode(name, "utf-8"));
        return "detail";
    }

    @GetMapping("/save")
    public String save(String name, String name1) {
        File file = new File(path + name1);
        System.out.println("file.exists() = " + file.exists());
        boolean b;
        for (int i = 0; !(b=file.renameTo(new File(path + name)))&&i<1; i++) {
        }
        System.out.println("save " + b + "\n");
        return "redirect:index";
    }

    @GetMapping("/edit")
    public String edit(String name, Model model) {
        model.addAttribute("name", name);
        return "edit";
    }

    @RequestMapping("/video1/{name}")
    public void download(HttpServletRequest request, HttpServletResponse response, @PathVariable("name") String name) {
        File file = new File(path + name.replaceAll("\\+"," "));
        OutputStream outputStream = null;
        RandomAccessFile targetFile = null;
        try {
            outputStream = response.getOutputStream();//获取响应的输出流
            //File file = new File(path+"\\"+name);
            targetFile = new RandomAccessFile(file, "r");
            //name = URLDecoder.decode(name, "utf-8");
            //清空缓存
            response.reset();
            if (file.exists()) {
                //创建随机读取文件对象
                long fileLength = targetFile.length();
                //获取从那个字节开始读取文件
                String rangeString = request.getHeader("Range");
                if (rangeString != null) {//如果rangeString不为空,证明是播放视频发来的请求
                    long range = Long.valueOf(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
                    //log.info("请求视频播放流,从字节:"+range+" 开始");
                    //设置内容类型
                    response.setHeader("Content-Type", "video/mp4");
                    //设置此次相应返回的数据长度
                    response.setHeader("Content-Length", String.valueOf(fileLength - range));
                    //设置此次相应返回的数据范围
                    response.setHeader("Content-Range", "bytes " + range + "-" + (fileLength - 1) + "/" + fileLength);
                    //返回码需要为206,而不是200
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                    //设定文件读取开始位置(以字节为单位)
                    targetFile.seek(range);
                } else {
                    //如果rangeString为空,证明是播放视频发来的请求
                    //log.info("请求视频文件下载");
                    //设置响应头,把文件名字设置好
                    response.setHeader("Content-Disposition", "attachment; filename=" +
                            new String(name.getBytes("utf-8"), "iso-8859-1"));
                    //设置文件长度
                    response.setHeader("Content-Length", String.valueOf(fileLength));
                    //解决编码问题
                    response.setHeader("Content-Type", "application/octet-stream");
                }
                byte[] cache = new byte[1024 * 300];
                int flag;
                while ((flag = targetFile.read(cache)) != -1) {
                    outputStream.write(cache, 0, flag);
                }
            } else {
                String message = "file:" + "fileName" + " not exists";
                //log.error(message);
                //解决编码问题
                response.setHeader("Content-Type", "application/json");
                outputStream.write(message.getBytes(StandardCharsets.UTF_8));
            }
        } catch (IOException e) {
        } catch (NumberFormatException e) {
        } finally {
            try {
                targetFile.close();
                outputStream.close();
            } catch (IOException e) {
            }
        }

    }

    private final static String utf8 = "utf-8";
    private Map<String, AtomicInteger> map = new ConcurrentHashMap<>();
    @RequestMapping("/up")
    public void upload(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setCharacterEncoding(utf8);
        MultipartFile file = ((StandardMultipartHttpServletRequest) request).getFile("file");
        int chunk = Integer.parseInt(request.getParameter("chunk"));
        int chunks = Integer.parseInt(request.getParameter("chunks"));
        String path = "F:\\temp";
        String fileName = file.getOriginalFilename();
        File saveFile=new File(path + "\\" +fileName+"-"+ chunk);
        file.transferTo(saveFile);
        AtomicInteger cou = map.get(fileName);
        if (cou==null) {
            cou = new AtomicInteger(1);
            map.put(fileName, cou);
        }else{
            cou.incrementAndGet();
        }
        if (cou.get()==chunks){
            mergeChunks(fileName,chunks);
            map.remove(fileName);

            File temp = new File(path);
            File[] files = temp.listFiles();
            for (File file1 : files) {
                if (file1.getName().lastIndexOf("-")!=-1&&file1.getName().substring(0,file1.getName().lastIndexOf("-")).equals(fileName)) {
                    boolean delete = file1.delete();
                }
            }
        }
        response.getWriter().write("up success");
    }

    public void mergeChunks(String fileName,int chunks) {
        byte[] buff = new byte[1024 * 1024*10];
        int len;
        try (FileOutputStream outputStream = new FileOutputStream(path +System.currentTimeMillis()+"-"+fileName)) {
            for (int i = 0; i <= chunks-1; i++) {
                FileInputStream inputStream = new FileInputStream("F:\\temp\\" +fileName+"-"+ i);
                while ((len = inputStream.read(buff)) != -1) {
                    outputStream.write(buff, 0, len);
                    outputStream.flush();
                }
                inputStream.close();
            }
        } catch (Exception e) {
        }
    }
}

前端

video.html 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" type="text/css" href="/webuploader-0.1.5/webuploader.css">
    <script type="text/javascript" src="/webuploader-0.1.5/jquery.min.js"></script>
    <script type="text/javascript" src="/webuploader-0.1.5/webuploader.min.js"></script>
</head>
<body>
<h1 style="display: inline;"><a th:href="@{index}">hello</a></h1>
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
<span id="uploadimg">
    <span id="imgPicker">选择文件</span>
    <span id="ctlBtn" hidden="true">
        <button class="webuploader-pick" id="button">开始上传</button>
        :<span id="percentage">0</span>
    </span>
</span>
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
<p id="time" style="display: inline;"></p>
<br><br>
<table border="1" cellspacing="0" width="1000">
    <tr th:each="name,status : ${list}">
        <td th:text="${status.count}">这里显示编号</td>
        <td>
            <a th:text="${name.name}" th:href="@{t3(name=${name.name1})}">这里显示老师的名字</a>
        </td>
        <td style="width:2cm;text-align:center">
            <a th:href="@{video1/}+${name.name1}">[[${status.count}]]下载</a>
        </td>
        <td style="width:2cm;text-align:center">
            <a th:href="@{edit(name=${name.name})}">[[${status.count}]]编辑</a>
        </td>
    </tr>
</table>

<script type="text/javascript">
    //var GUID = WebUploader.guid();//一个GUID
    var uploader = WebUploader.create({
        //auto: true, // 选完文件后,是否自动上传
        swf: 'webuploader-0.1.5/Uploader.swf', // swf文件路径
        server: '[[@{up}]]', // 文件接收服务端
        pick: '#imgPicker', // 选择文件的按钮。可选
        chunked: true,//开启分片上传
        threads: 10,//上传并发数
        resize: false,
        chunkSize: 1024*1024*10,  //每一片的大小
        //chunkRetry: 100,         // 如果遇到网络错误,重新上传次数
        // formData: {
        //     guid: GUID //自定义参数,待会儿解释
        // }
    });
    $("#ctlBtn").click(function () {
        document.getElementById("imgPicker").hidden = true
        document.getElementById("button").innerText = "上传中"
        uploader.upload();
    });

    uploader.on( 'fileQueued', function( file ) {
        document.getElementById("ctlBtn").hidden = false;
    });
    var flag = true
    // 监控上传进度
    // percentage:代表上传文件的百分比
    uploader.on("uploadProgress", function(file, percentage) {
        document.getElementById("percentage").innerText = Math.round(percentage * 100) + '%'
        if (percentage==1&&flag){
            alert("upLoad success");
            window.location.href='[[@{index}]]';
            flag = false
        }
    });


    function time() {
        document.getElementById("time").innerText = new Date().toLocaleString();
    }

    setInterval("time()",500);

</script>
</body>
</html>

detail.html 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link type="text/css" rel="stylesheet" href="/ckplayer/ckplayer/css/ckplayer.css"/>
    <script type="text/javascript" src="/ckplayer/ckplayer/js/ckplayer.min.js" charset="UTF-8"></script>
</head>
<body>
<p>[[${name1}]]</p>
<div class="video" style="width: 100%; height: 500px;max-width: 800px;">播放容器</div>
<script>
    //调用开始
    var videoObject = {
        container: '.video', //视频容器
        poster: '/ckplayer/video/poster.png',//封面图片
        video: '/video/video1/' + '[[${name}]]'//视频地址
        //video: '[[@{video1(name=${name})}]]'//视频地址
    };
    var player = new ckplayer(videoObject)//调用播放器并赋值给变量player
    /*
     * ===============================================================================================
     * 以上代码已完成调用演示,下方的代码是演示监听动作和外部控制的部分
     * ===============================================================================================
     * ===============================================================================================
     */
    player.play(function () {
        document.getElementById('state').innerHTML = '监听到播放';
    });
    player.pause(function () {
        document.getElementById('state').innerHTML = '监听到暂停';
    });
    player.volume(function (vol) {
        document.getElementById('state').innerHTML = '监听到音量改变:' + vol;
    });
    player.muted(function (b) {
        document.getElementById('state2').innerHTML = '监听到静音状态:' + b;
    });
    player.full(function (b) {
        document.getElementById('state').innerHTML = '监听到全屏状态:' + b;
    });
    player.ended(function () {
        document.getElementById('state').innerHTML = '监听到播放结束';
    });
</script>
<a th:href="@{index}"><h1>hello</h1></a>
<p>控制示例:</p>
<p>
    <button type="button" onclick="player.play()">播放</button>
    <button type="button" onclick="player.pause()">暂停</button>
    <button type="button" onclick="player.seek(20)">跳转</button>
    <button type="button" onclick="player.volume(0.6)">修改音量</button>
    <button type="button" onclick="player.muted()">静音</button>
    <button type="button" onclick="player.exitMuted()">恢复音量</button>
    <button type="button" onclick="player.full()">全屏</button>
    <button type="button" onclick="player.webFull()">页面全屏</button>
    <button type="button" onclick="player.theatre()">剧场模式</button>
    <button type="button" onclick="player.exitTheatre()">退出剧场模式</button>
</p>
<p id="state"></p>
<p id="state2"></p>
</body>
</html>

 edit.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a th:href="@{index}"><h1>hello</h1></a>
<form th:action="@{save}">
    name: <input type="text" name="name" th:value="${name}" style="width:20cm"><br>
        <input type="hidden" name="name1" th:value="${name}">
    submit: <input type="submit" value="提交">
</form>
</body>
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值