/**
* 上傳視頻。http://localhost:8080/Video/upload
*/
@RequestMapping("/upload")
@ResponseBody
public R uploadPhoto(MultipartFile file) {
if (file == null) {
return R.error("請選擇視頻上傳");
}
String fileName = file.getOriginalFilename();//獲取初始文件名
int indexOf = fileName.lastIndexOf(".");
if(indexOf == -1){
return R.error("視頻格式不正確");
}
String suffix = fileName.substring(indexOf);//得到文件名后綴 .mp4
if(suffix==null||suffix.equals(".")){
return R.error("視頻格式不正確");
}
//.mp4
if(!(suffix.equals(".mp4"))){
return R.error("視頻格式不正確");
}
// 生成隨機文件名
String name = UUID.randomUUID().toString().replaceAll("-", "") + suffix;
//獲取當前項目下視頻保存的路徑
String uploadPath = null;
try {
// c:\\a2295929271\ .....
uploadPath = new File("").getCanonicalPath();
} catch (IOException e) {
throw new RuntimeException("獲取項目路徑失敗", e);
}
// 確定文件存放的路徑
String ans = uploadPath + File.separator + "file" + File.separator + "video" + File.separator + name;
File dest = new File(ans);
try {
// 存儲文件
file.transferTo(dest);
} catch (IOException e) {
throw new RuntimeException("上傳文件失敗,服務器發生異常!", e);
}
String result = domain + name;
return R.ok().put("url",result);
}
確實,視頻傳輸上去了,一百多M的視頻,沒什么問題。。。。不知道傳到服務器上有沒有問題,估計應該有。
然而把視頻讀取到瀏覽器上:
/**
* 獲取視頻。
* http://localhost:8080/Video/load/626905be16ce4f36b033693cd61662dc.mp4
* 得到項目路徑下 /file/video/48c3df11ca5f4c80bab198159e41a5de.png的圖片
*/
@RequestMapping("/load/{name}")
@ResponseBody
public void loadPhoto(HttpServletResponse response,@PathVariable("name") String name) {
String videoPath = null;
FileInputStream fis = null;
OutputStream os = null ;
try {
//得到項目中視頻保存的路徑
videoPath = new File("").getCanonicalPath() + File.separator + "file" + File.separator + "video";
} catch (IOException e) {
throw new RuntimeException("獲取項目路徑失敗", e);
}
videoPath += File.separator + name;
try {
fis = new FileInputStream(videoPath);
int size = fis.available(); // 得到文件大小
byte data[] = new byte[size];
fis.read(data); // 讀數據
fis.close();
response.setContentType("video/mp4"); // 設置返回的文件類型
os = response.getOutputStream();
os.write(data);
os.flush();
os.close();
os = null;fis = null;
} catch (FileNotFoundException e) {
throw new RuntimeException("........文件" +videoPath + "未找到......", e);
} catch (IOException e) {
throw new RuntimeException("..文件大小讀取異常..", e);
}
}
出現異常了,。。。百度說也就 是 文件過大了。
這樣,百度到了一個方法:分片循環輸出。
修改代碼:
/**
* 獲取視頻。
* http://localhost:8080/Video/load/626905be16ce4f36b033693cd61662dc.mp4
* 得到項目路徑下 /file/video/48c3df11ca5f4c80bab198159e41a5de.png的圖片
*/
@RequestMapping("/load/{name}")
@ResponseBody
public void loadPhoto(HttpServletResponse response,@PathVariable("name") String name) {
String videoPath = null;
FileInputStream fis = null;
OutputStream os = null ;
response.setContentType("video/mp4");
try {
//得到項目中視頻保存的路徑
videoPath = new File("").getCanonicalPath() + File.separator + "file" + File.separator + "video";
} catch (IOException e) {
throw new RuntimeException("獲取項目路徑失敗", e);
}
videoPath += File.separator + name;
try {
fis = new FileInputStream(videoPath);
int size = fis.available(); // 得到文件大小
os = response.getOutputStream();//得到輸出流
byte[] data = new byte[1024 * 1024 * 5];// 5MB
// 5M 大小循環寫出
fis.read(data); // 讀數據
int len = 0;
while ((len = fis.read(data)) != -1) {
System.out.println("111111111111111");
os.write(data,0,len);
}
os.flush();
os.close();
fis.close();
os = null;
fis = null;
} catch (FileNotFoundException e) {
throw new RuntimeException("........文件" +videoPath + "未找到......", e);
} catch (IOException e) {
throw new RuntimeException("文件操作出現異常,請聯系管理員", e);
}
}
仍然存在剛才的問題。。。。。。
待解決
過了兩天繼續寫博客,問題已解決。不能一次性傳遞全部視頻,要分段的傳遞
在每次的請求的頭中加入 Range:bytes=xx-yy xx yy就是字節開始和結束點。
重新寫了個接口:
/**
* 獲取視頻流
* @param response
* @param fileName 視頻存放信息索引
* @return
* @author xWang
* @Date 2020-05-20
*/
@RequestMapping("/getVideo/{fileName}")
public void getVideo(HttpServletRequest request, HttpServletResponse response,@PathVariable("fileName") String fileName) {
//獲取視頻路徑
String videoPath = null;
try {
//得到項目中視頻保存的路徑
videoPath = new File("").getCanonicalPath() + File.separator + "file" + File.separator + "video";
} catch (IOException e) {
throw new RuntimeException("獲取項目路徑失敗", e);
}
videoPath += File.separator + fileName;
//視頻資源存儲信息
response.reset();
//獲取從那個字節開始讀取文件
String rangeString = request.getHeader("Range");
try {
//獲取響應的輸出流
OutputStream outputStream = response.getOutputStream();
File file = new File(videoPath);
if(file.exists()){
RandomAccessFile targetFile = new RandomAccessFile(file, "r");
long fileLength = targetFile.length();
//播放
if(rangeString != null){
long range = Long.parseLong(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
//設置內容類型
response.setHeader("Content-Type", "video/mov");
//設置此次相應返回的數據長度
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 {//下載
//設置響應頭,把文件名字設置好
response.setHeader("Content-Disposition", "attachment; filename="+fileName );
//設置文件長度
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";
//解決編碼問題
response.setHeader("Content-Type","application/json");
outputStream.write(message.getBytes(StandardCharsets.UTF_8));
}
outputStream.flush();
outputStream.close();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
問題已解決。而且在安卓端訪問的時候,也可以很好的變成訪問在線播放的效果,給用戶很好的體驗。