项目结构
服务端
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>
          
<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>
          
<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>