当前位置:   article > 正文

springboot(三)websocket实现服务端,客户端的视频传输_javaspringboot websocket video

javaspringboot websocket video

1.服务端

1.1pom.xml引入库

  1. <!--引入websocket依赖-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-websocket</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.java-websocket</groupId>
  8. <artifactId>Java-WebSocket</artifactId>
  9. <version>1.3.5</version>
  10. </dependency>

1.2新建配置类, 开启WebSocket支持:

发现问题

经过了测试,发现几个问题,
一.连接断开,而且不报任何错
解决方式:是因为缓冲区过小,而传输的视频过大,websocket的默认缓冲区应该是8k,我们传输的视频有10几兆了,所以我们应该去改动缓冲区,查询资料,这里的缓冲区是独立的,有几个websocket连接就有几个缓冲区。

  1. package com.example.demo.config;
  2. import org.springframework.boot.web.servlet.ServletContextInitializer;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.web.socket.server.standard.ServerEndpointExporter;
  6. import org.springframework.web.util.WebAppRootListener;
  7. import javax.servlet.ServletContext;
  8. import javax.servlet.ServletException;
  9. /**
  10. * 开启WebSocket支持
  11. **/
  12. @Configuration
  13. public class WebSocketConfig implements ServletContextInitializer {
  14. @Bean
  15. public ServerEndpointExporter serverEndpointExporter() {
  16. return new ServerEndpointExporter();
  17. }
  18. //设置websocket发送内容长度
  19. @Override
  20. public void onStartup(ServletContext servletContext) throws ServletException {
  21. servletContext.addListener(WebAppRootListener.class);
  22. //这里设置了30兆的缓冲区
  23. //Tomcat每次请求过来时在创建session时都会把这个webSocketContainer作为参数传进去所以对所有的session都生效了
  24. servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize","30000000");
  25. servletContext.setInitParameter("org.apache.tomcat.websocket.binaryBufferSize","30000000");
  26. }
  27. }

1.3新建一个websocket处理类,这里我创建一个类为WebSocketServer

  1. package dzftxt.web.controller;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import dzftxt.data.dataobject.Videos;
  5. import dzftxt.data.form.VideoForm;
  6. import dzftxt.service.SaveFileI;
  7. import dzftxt.service.VideoService;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10. import org.springframework.beans.BeanUtils;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.stereotype.Component;
  13. import javax.websocket.OnClose;
  14. import javax.websocket.OnMessage;
  15. import javax.websocket.OnOpen;
  16. import javax.websocket.Session;
  17. import javax.websocket.server.PathParam;
  18. import javax.websocket.server.ServerEndpoint;
  19. import java.io.IOException;
  20. import java.util.HashMap;
  21. import java.util.Map;
  22. import java.util.concurrent.CopyOnWriteArraySet;
  23. /**
  24. * @author :Siyuan Gao
  25. * @date :Created in 2020/9/12 10:24
  26. * @description:用于接受处理客户端向服务端传递的信息
  27. * @modified By:
  28. * @version: $
  29. */
  30. @Component
  31. @ServerEndpoint("/upload/{sid}")
  32. public class WebSocketUploadServer {
  33. private static final Logger LOG = LoggerFactory.getLogger(WebSocketUploadServer.class);
  34. //用来记录当前在线连接数,
  35. private static int onlineCount = 0;
  36. //线程安全的set,用来存放每个客户端对应的websocket对象
  37. private static CopyOnWriteArraySet<WebSocketUploadServer> webSocketSet = new CopyOnWriteArraySet<>();
  38. //与某个客户端的连接会话,需要通过它来给客户端发送数据
  39. private Session session;
  40. private static SaveFileI saveFileI;
  41. @Autowired
  42. public void setSaveFileI(SaveFileI saveFileI){
  43. WebSocketUploadServer.saveFileI=saveFileI;
  44. }
  45. //用hashmap存储文件对象和文件路径
  46. private HashMap docUrl;
  47. //结束标志
  48. private String endupload = "over";
  49. private static VideoService videoService;
  50. @Autowired
  51. public void setVideoService(VideoService videoService){
  52. WebSocketUploadServer.videoService=videoService;
  53. }
  54. //连接成功时,服务端会自动调用这个方法
  55. @OnOpen
  56. public void onOpen(Session session, @PathParam("sid") String sid){
  57. //这一句是注入session,否则this无法发送消息
  58. this.session=session;
  59. webSocketSet.add(this);
  60. addOnlineCount();
  61. LOG.info(sid + "------连接成功---当前在线人数为"+onlineCount);
  62. }
  63. /**
  64. * 连接关闭时调用的方法
  65. */
  66. @OnClose
  67. public void onClose(@PathParam("sid") String sid) {
  68. //在线人数减1
  69. subOnlineCount();
  70. //set中删除
  71. webSocketSet.remove(this);
  72. LOG.info(sid + "已关闭连接" + "----剩余在线人数为:" + onlineCount);
  73. }
  74. /*
  75. 下面这个onmessage只负责处理客户端传来的字符串类型的文件,主要用于和前端的配合,
  76. */
  77. /*@OnMessage
  78. public void onMessage(String message, @PathParam("sid") String sid) {
  79. //把前端传来的json转为对象‘
  80. JSONObject jsonObject = JSON.parseObject(message);
  81. //消息类型 比如类型有文件名称filename,传的文件的第几份filecount,是否结束over
  82. String type = jsonObject.getString("type");
  83. //得到消息内容
  84. String data = jsonObject.getString("data");
  85. //一开始文件名传进来,服务端接受后生成有具体地址的文件对象,并向客户端传递ok进行下一步的传输
  86. if ("fileName".equals(type)) {
  87. LOG.info("传输的文件名为:" + data);
  88. try {
  89. Map<String, Object> map = saveFileI.docPath(data);
  90. docUrl = (HashMap) map;
  91. this.sendMessage("ok");
  92. } catch (IOException e) {
  93. e.printStackTrace();
  94. }
  95. }
  96. //如果是发来的文件的第几份,那么打印出是第几份
  97. else if("fileCount".equals(type)){
  98. LOG.info("传输第"+data+"份");
  99. }
  100. //如果传递的是结束,则给客户端返回一个文件存储地址
  101. else if (endupload.equals(type)){
  102. LOG.info("===============>传输成功");
  103. String path = (String) docUrl.get("nginxPath");
  104. try {
  105. this.sendMessage(path);
  106. } catch (IOException e) {
  107. e.printStackTrace();
  108. }
  109. }
  110. }*/
  111. /*
  112. 下面这个onmessage只负责处理客户端传来的byte[]的文件,主要用于和前端的配合,进行分段传输
  113. */
  114. /*@OnMessage
  115. public void onMessage(byte[] message,Session session){
  116. //
  117. try{
  118. //把传来的字节流数组写入到上面创建的文件对象里去
  119. saveFileI.saveFileFromBytes(message,docUrl);
  120. // saveFileI.saveFileFromBytes(message);
  121. //只有客户端接受到ok才会传输下一段文件
  122. this.sendMessage("服务端已成功接受视频");
  123. }catch (IOException e){
  124. e.printStackTrace();
  125. }
  126. }*/
  127. /*
  128. * 下面的onmessage用于接受经过json转换的map
  129. * */
  130. @OnMessage
  131. public void onMessage(String message, @PathParam("sid") String sid) {
  132. //把前端传来的json转为对象‘
  133. JSONObject jsonObject = JSON.parseObject(message);
  134. //消息类型 比如类型有文件名称filename,传的文件的第几份filecount,是否结束over
  135. String fileName= jsonObject.getString("fileName");
  136. VideoForm videos=JSON.toJavaObject(jsonObject,VideoForm.class);
  137. //得到消息内容
  138. if (videos.getContent()==null) System.out.println("传输的内容为空!");
  139. Map<String, Object> map = saveFileI.docPath(fileName);
  140. //
  141. try {
  142. saveFileI.saveFileFromBytes(videos.getContent(),map);
  143. this.sendMessage("服务端已成功接受视频:"+videos.toString());
  144. //保存视频信息到数据库
  145. Videos videos1=new Videos();
  146. BeanUtils.copyProperties(videos,videos1);
  147. videos1.setPath((String) map.get("path"));
  148. videoService.saveVideo(videos1);
  149. this.sendMessage("服务端已成功保存该视频");
  150. LOG.info(sid + "------视频传输成功---");
  151. }catch (IOException e){
  152. e.printStackTrace();
  153. }
  154. }
  155. //这个方法用于接受处理客户端传来的字节流数组类型的文件
  156. @OnMessage
  157. public void onMessage(byte[] message,Session session){
  158. //
  159. try{
  160. //把传来的字节流数组写入到上面创建的文件对象里去
  161. // saveFileI.saveFileFromBytes(message,docUrl);
  162. saveFileI.saveFileFromBytes(message);
  163. //只有客户端接受到ok才会传输下一段文件
  164. this.sendMessage("服务端已成功接受视频");
  165. }catch (IOException e){
  166. e.printStackTrace();
  167. }
  168. }
  169. //服务端向客户端发送消息
  170. public void sendMessage(String message) throws IOException{
  171. this.session.getBasicRemote().sendText(message);
  172. }
  173. /**
  174. * 群发消息功能
  175. *
  176. * @param message 消息内容
  177. * @param sid 房间号
  178. */
  179. public static void sendInfo(String message, @PathParam("sid") String sid) {
  180. LOG.info("推送消息到所有客户端" + sid + ",推送内容:" + message);
  181. for (WebSocketUploadServer item : webSocketSet) {
  182. try {
  183. //这里可以设定只推送给这个sid的,为null则全部推送
  184. item.sendMessage(message);
  185. } catch (IOException e) {
  186. LOG.error("消息发送失败" + e.getMessage(), e);
  187. return;
  188. }
  189. }
  190. }
  191. /**
  192. * 原子性的++操作
  193. */
  194. public static synchronized void addOnlineCount() {
  195. WebSocketUploadServer.onlineCount++;
  196. }
  197. /**
  198. * 原子性的--操作
  199. */
  200. public static synchronized void subOnlineCount() {
  201. WebSocketUploadServer.onlineCount--;
  202. }
  203. }

 savefilei.java

  1. package dzftxt.service;
  2. import java.util.Map;
  3. public interface SaveFileI {
  4. /**
  5. * 生成文件路径
  6. * @param fileName 接收文件名
  7. * @return 返回一个map,里面包换文件路径,文件,相对路径
  8. */
  9. Map<String,Object> docPath(String fileName);
  10. /**
  11. * 将字节流写入文件
  12. * @param b 字节流数组,是前端传来的。把这个字节流数组添加到map中的file中去(先通过file生成文件流对象outputstream)
  13. * @param map 文件路径
  14. * @return 返回是否成功
  15. */
  16. boolean saveFileFromBytes(byte[] b, Map<String, Object> map);
  17. boolean saveFileFromBytes(byte[] b);
  18. }

saveFileImpl.java

  1. package dzftxt.service;
  2. import org.springframework.stereotype.Service;
  3. import javax.websocket.server.ServerEndpoint;
  4. import java.io.File;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.text.SimpleDateFormat;
  8. import java.util.Date;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. /**
  12. * @author :Siyuan Gao
  13. * @date :Created in 2020/9/12 10:17
  14. * @description:
  15. * @modified By:
  16. * @version: $
  17. */
  18. @Service
  19. public class SaveFileImpl implements SaveFileI{
  20. public Map<String, Object> docPath(String fileName) {
  21. HashMap<String, Object> map = new HashMap<>();
  22. //根据时间生成文件夹路径
  23. Date date = new Date();
  24. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");
  25. String docUrl = simpleDateFormat.format(date);
  26. //文件保存地址
  27. String path = "/data/images/" + docUrl;
  28. //创建文件
  29. File dest = new File(path+"/" + fileName);
  30. //如果文件已经存在就先删除掉
  31. if (dest.getParentFile().exists()) {
  32. dest.delete();
  33. }
  34. map.put("dest", dest);
  35. map.put("path", path+"/" + fileName);
  36. map.put("nginxPath","/"+docUrl+"/"+fileName);
  37. return map;
  38. }
  39. public boolean saveFileFromBytes(byte[] b, Map<String, Object> map) {
  40. //创建文件流对象
  41. FileOutputStream fstream = null;
  42. //从map中获取file对象
  43. File file = (File) map.get("dest");
  44. //判断路径是否存在,不存在就创建
  45. if (!file.getParentFile().exists()) {
  46. file.getParentFile().mkdirs();
  47. }
  48. try {
  49. fstream = new FileOutputStream(file, true);
  50. fstream.write(b);
  51. } catch (Exception e) {
  52. e.printStackTrace();
  53. return false;
  54. } finally {
  55. if (fstream != null) {
  56. try {
  57. fstream.close();
  58. } catch (IOException e1) {
  59. e1.printStackTrace();
  60. }
  61. }
  62. }
  63. return true;
  64. }
  65. public boolean saveFileFromBytes(byte[] b) {
  66. //创建文件流对象
  67. FileOutputStream fstream = null;
  68. //从map中获取file对象
  69. File file = new File("E:\\Users\\Administrator.DESKTOP-K38H7QV\\Desktop\\videos\\test.mp4");
  70. //判断路径是否存在,不存在就创建
  71. if (!file.getParentFile().exists()) {
  72. file.getParentFile().mkdirs();
  73. }
  74. try {
  75. fstream = new FileOutputStream(file, true);
  76. fstream.write(b);
  77. } catch (Exception e) {
  78. e.printStackTrace();
  79. return false;
  80. } finally {
  81. if (fstream != null) {
  82. try {
  83. fstream.close();
  84. } catch (IOException e1) {
  85. e1.printStackTrace();
  86. }
  87. }
  88. }
  89. return true;
  90. }
  91. }

2.客户端

WebSocketConfig.java

  1. package com.nju.config;
  2. import org.java_websocket.drafts.Draft_6455;
  3. import org.java_websocket.handshake.ServerHandshake;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.stereotype.Component;
  6. import org.java_websocket.client.WebSocketClient;
  7. import java.net.URI;
  8. /**
  9. * @author :Siyuan Gao
  10. * @date :Created in 2020/9/8 14:08
  11. * @description:websocket的bean
  12. * @modified By:
  13. * @version: $
  14. */
  15. @Component
  16. public class WebSocketConfig {
  17. @Bean
  18. public WebSocketClient webSocketClient(){
  19. try{
  20. WebSocketClient webSocketClient=new WebSocketClient(new URI("ws://localhost:8090/dzftxt/upload/25477fes1"),new Draft_6455()) {
  21. @Override
  22. public void onOpen(ServerHandshake serverHandshake) {
  23. System.out.println("客户端建立连接");
  24. }
  25. @Override
  26. public void onMessage(String s) {
  27. System.out.println("客户端收到消息----"+s);
  28. }
  29. @Override
  30. public void onClose(int i, String s, boolean b) {
  31. System.out.println("客户端关闭连接");
  32. }
  33. @Override
  34. public void onError(Exception e) {
  35. }
  36. };
  37. webSocketClient.connect();
  38. return webSocketClient;
  39. }catch (Exception e){
  40. e.printStackTrace();
  41. }
  42. return null;
  43. }
  44. }
  1. package com.nju.service;
  2. import org.java_websocket.client.WebSocketClient;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Component;
  5. /**
  6. * @author :Siyuan Gao
  7. * @date :Created in 2020/9/8 11:19
  8. * @description:用于websocket传输视频的接口
  9. * @modified By:
  10. * @version: $
  11. */
  12. @Component
  13. public class WebSocketService {
  14. @Autowired
  15. private WebSocketClient webSocketClient;
  16. public void sendMessageToServe(String s){
  17. webSocketClient.send(s);
  18. }
  19. public void sendByteMessage(byte[] bytes){
  20. webSocketClient.send(bytes);
  21. }
  22. }
  1. package com.nju.controller;
  2. import com.alibaba.fastjson.JSON;
  3. import com.nju.Utils.FileUtil;
  4. import com.nju.service.WebSocketService;
  5. import com.alibaba.fastjson.JSONObject;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.stereotype.Controller;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import javax.websocket.server.ServerEndpoint;
  10. import java.io.*;
  11. import java.text.SimpleDateFormat;
  12. import java.util.*;
  13. /**
  14. * @author :Siyuan Gao
  15. * @date :Created in 2020/9/9 10:39
  16. * @description:测试文件上传
  17. * @modified By:
  18. * @version: $
  19. */
  20. @Controller
  21. @ServerEndpoint("/clientWs")
  22. public class UploadFileController {
  23. private static WebSocketService webSocketService;
  24. @Autowired
  25. public void setWebSocketService(WebSocketService webSocketService){
  26. UploadFileController.webSocketService=webSocketService;
  27. }
  28. @RequestMapping("/upload")
  29. public String uploadFile(){
  30. return "fileUpload";
  31. }
  32. /*
  33. * 下面这个wsupload用于直接传输byte类型
  34. * */
  35. @RequestMapping("/wsUpload")
  36. public String wsUpload() throws FileNotFoundException {
  37. // File file=new File("E:\\Users\\Administrator.DESKTOP-K38H7QV\\Desktop\\test.mp4");
  38. File file=new File("D:\\BaiduYunDownload\\14test.mp4");
  39. String name=file.getName();
  40. byte[] bytes = FileUtil.fileToBinArray(file);
  41. //如果直接传入会不会出问题呢测试一下
  42. webSocketService.sendByteMessage(bytes);
  43. /* int start_size=0;
  44. int end_size=0;
  45. //当服务端处理完了
  46. while(end_size<bytes.length){
  47. byte[] temp= Arrays.copyOfRange(bytes,start_size,end_size);
  48. webSocketService.sendByteMessage(temp);
  49. }*/
  50. System.out.println("客户端发送了视频");
  51. return "success";
  52. }
  53. /*
  54. * 下面这个wsupload用于测试传输含有byte类型的map转化为string
  55. * */
  56. @RequestMapping("/wsUpload1")
  57. public String wsUpload1() throws FileNotFoundException {
  58. // File file=new File("E:\\Users\\Administrator.DESKTOP-K38H7QV\\Desktop\\test.mp4");
  59. File file=new File("D:\\BaiduYunDownload\\02vuetest.avi");
  60. byte[] bytes = FileUtil.fileToBinArray(file);
  61. HashMap<String,Object> map=new HashMap();
  62. map.put("fileName",file.getName());
  63. map.put("content",bytes);
  64. map.put("ah","案号test");
  65. map.put("dzftId","锁id");
  66. map.put("fydm","法院代码test");
  67. SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  68. map.put("createTime",(df.format(new Date())).toString());
  69. webSocketService.sendMessageToServe(JSON.toJSONString(map));
  70. /* int start_size=0;
  71. int end_size=0;
  72. //当服务端处理完了
  73. while(end_size<bytes.length){
  74. byte[] temp= Arrays.copyOfRange(bytes,start_size,end_size);
  75. webSocketService.sendByteMessage(temp);
  76. }*/
  77. System.out.println("客户端发送了视频");
  78. return "success";
  79. }
  80. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/196406
推荐阅读
相关标签
  

闽ICP备14008679号