当前位置:   article > 正文

JAVA集成WebSocket,实现服务器与客户端握手_java实现webwocke客户端和服务端交互并实现心跳和重连

java实现webwocke客户端和服务端交互并实现心跳和重连

                                      WebSocket实现服务器与客户端握手

自学的WebSocket途中遇到很多坑,希望需要使用的朋友可以少走弯路,

使用的环境:tomcat7.0,mysql,springMvc,spring,Mybatis

主要使用2个jar包 这2个jar包在tomcat7的 lib文件夹里面有

catalina.jar        websocket-api.jar

其他jar包截图如下

本章实例中,实现了客户端之间的通信和服务器响应数据给客户端

1.客户端之间的通信,打开2个浏览器模仿QQ聊天功能

2.服务器与客户端之间的通信

 当数据库信息发生改变时候,服务器把最新的数据响应给客户端

这是数据没改变的时候的

当数据库发生改变时候,服务器把最新的数据推送给客户端

没改变的时候,服务器不会推送数据

主要类3个

GetHttpSession用与在MyWebSocket类中获取HttpSession对象

  1. package ljm.web;
  2. import javax.servlet.http.HttpSession;
  3. import javax.websocket.HandshakeResponse;
  4. import javax.websocket.server.HandshakeRequest;
  5. import javax.websocket.server.ServerEndpointConfig;
  6. public class GetHttpSession extends ServerEndpointConfig.Configurator
  7. {
  8. @Override
  9. public void modifyHandshake(ServerEndpointConfig config,
  10. HandshakeRequest request,HandshakeResponse response){
  11. HttpSession httpSession = (HttpSession)request.getHttpSession();
  12. config.getUserProperties().put(HttpSession.class.getName(),httpSession);
  13. }
  14. }

 

MyWebSocket用实现服务器与客户端的通信

 

  1. package ljm.web;
  2. import java.io.IOException;
  3. import java.util.concurrent.CopyOnWriteArraySet;
  4. import javax.servlet.http.HttpSession;
  5. import javax.websocket.EndpointConfig;
  6. import javax.websocket.OnClose;
  7. import javax.websocket.OnError;
  8. import javax.websocket.OnMessage;
  9. import javax.websocket.OnOpen;
  10. import javax.websocket.Session;
  11. import javax.websocket.server.ServerEndpoint;
  12. import org.springframework.web.context.ContextLoader;
  13. import ljm.service.UserService;
  14. @ServerEndpoint(value="/chat",configurator=GetHttpSession.class)
  15. public class MyWebSocket {
  16. private UserService userService = (UserService) ContextLoader.getCurrentWebApplicationContext().getBean("userService");
  17. //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
  18. private static int onlineCount = 0;
  19. //更新数据的线程
  20. RefreshThread thread =null;
  21. //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
  22. private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
  23. //与某个客户端的连接会话,需要通过它来给客户端发送数据
  24. private Session session;
  25. /**
  26. * 连接建立成功调用的方法
  27. * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
  28. * @throws Exception
  29. */
  30. @OnOpen
  31. public void onOpen(Session session,EndpointConfig config) throws Exception{
  32. Integer age=userService.findUserAge(1);
  33. System.out.println(age);
  34. this.session = session;
  35. webSocketSet.add(this);
  36. HttpSession se= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
  37. se.setAttribute("userId", 1);
  38. thread=new RefreshThread(session,se);
  39. thread.start();
  40. addOnlineCount(); //在线数加1
  41. System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
  42. }
  43. /**
  44. * 连接关闭调用的方法
  45. */
  46. @OnClose
  47. public void onClose(){
  48. thread.stopThread();
  49. webSocketSet.remove(this); //从set中删除
  50. subOnlineCount(); //在线数减1
  51. System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
  52. }
  53. /**
  54. * 收到客户端消息后调用的方法
  55. * @param message 客户端发送过来的消息
  56. * @param session 可选的参数
  57. */
  58. @OnMessage
  59. public void onMessage(String message, Session session) {
  60. System.out.println("来自客户端的消息:" + message);
  61. //群发消息
  62. for(MyWebSocket item: webSocketSet){
  63. try {
  64. item.sendMessage(message);
  65. } catch (IOException e) {
  66. e.printStackTrace();
  67. continue;
  68. }
  69. }
  70. }
  71. /**
  72. * 发生错误时调用
  73. * @param session
  74. * @param error
  75. */
  76. @OnError
  77. public void onError(Session session, Throwable error){
  78. System.out.println("发生错误");
  79. error.printStackTrace();
  80. }
  81. /**
  82. * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
  83. * @param message
  84. * @throws IOException
  85. */
  86. public void sendMessage(String message) throws IOException{
  87. //同步
  88. this.session.getBasicRemote().sendText(message);
  89. //异步this.session.getAsyncRemote().sendText(message);
  90. }
  91. public static synchronized int getOnlineCount() {
  92. return onlineCount;
  93. }
  94. public static synchronized void addOnlineCount() {
  95. MyWebSocket.onlineCount++;
  96. }
  97. public static synchronized void subOnlineCount() {
  98. MyWebSocket.onlineCount--;
  99. }
  100. }

RefreshThread线程用于查询数据库有没有新的通知信息

  1. package ljm.web;
  2. import javax.servlet.http.HttpSession;
  3. import javax.websocket.Session;
  4. import org.springframework.web.context.ContextLoader;
  5. import ljm.service.UserService;
  6. public class RefreshThread extends Thread {
  7. private Session session;
  8. private Integer currentAge;
  9. private HttpSession se;
  10. UserService userService;
  11. private volatile boolean stop = false;
  12. //关闭线程
  13. public void stopThread() {
  14. this.stop = true;
  15. }
  16. public RefreshThread(Session session,HttpSession se) throws Exception {
  17. userService = (UserService) ContextLoader.getCurrentWebApplicationContext().getBean("userService");
  18. this.session = session;
  19. this.se=se;
  20. currentAge =userService.findUserAge((Integer) se.getAttribute("userId")) ;//此时是0条最新消息
  21. }
  22. @Override
  23. public void run() {
  24. Integer age=null;
  25. while (true) {
  26. try {
  27. Integer id=(Integer) se.getAttribute("userId");
  28. age=userService.findUserAge(id);
  29. if(age!=currentAge){
  30. session.getBasicRemote().sendText(age+"");
  31. currentAge=age;
  32. }
  33. //一秒刷新一次
  34. Thread.sleep(1000);
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. }
  38. }
  39. }
  40. }

其次就是配置要通讯的JSP页面

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%
  3. String path = request.getContextPath();
  4. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  5. %>
  6. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  7. <html>
  8. <head>
  9. <base href="<%=basePath%>">
  10. <title>My JSP 'index.jsp' starting page</title>
  11. <meta http-equiv="pragma" content="no-cache">
  12. <meta http-equiv="cache-control" content="no-cache">
  13. <meta http-equiv="expires" content="0">
  14. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  15. <meta http-equiv="description" content="This is my page">
  16. </head>
  17. <body>
  18. Welcome<br/>
  19. <input id="text" type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button>
  20. <div id="message">
  21. </div>
  22. </body>
  23. <script type="text/javascript">
  24. var websocket = null;
  25. //判断当前浏览器是否支持WebSocket
  26. if('WebSocket' in window){
  27. websocket = new WebSocket("ws://localhost:8080/webSocketDemo/chat");
  28. }
  29. else{
  30. alert('Not support websocket');
  31. }
  32. //连接发生错误的回调方法
  33. websocket.onerror = function(){
  34. setMessageInnerHTML("error");
  35. };
  36. //连接成功建立的回调方法
  37. websocket.onopen = function(event){
  38. setMessageInnerHTML("open");
  39. };
  40. //接收到消息的回调方法
  41. websocket.onmessage = function(event){
  42. setMessageInnerHTML(event.data);
  43. };
  44. //连接关闭的回调方法
  45. websocket.onclose = function(){
  46. setMessageInnerHTML("close");
  47. };
  48. //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
  49. window.onbeforeunload = function(){
  50. websocket.close();
  51. };
  52. //将消息显示在网页上
  53. function setMessageInnerHTML(innerHTML){
  54. document.getElementById('message').innerHTML += innerHTML + '<br/>';
  55. }
  56. //关闭连接
  57. function closeWebSocket(){
  58. websocket.close();
  59. }
  60. //发送消息
  61. function send(){
  62. var message = document.getElementById('text').value;
  63. websocket.send(message);
  64. }
  65. </script>
  66. </html>

注意事项

 

 

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

闽ICP备14008679号