香港网站域名查询/站长工具 忘忧草
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对象
package ljm.web;
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;public class GetHttpSession extends ServerEndpointConfig.Configurator
{@Overridepublic void modifyHandshake(ServerEndpointConfig config,HandshakeRequest request,HandshakeResponse response){HttpSession httpSession = (HttpSession)request.getHttpSession();config.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}
MyWebSocket用实现服务器与客户端的通信
package ljm.web;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;import org.springframework.web.context.ContextLoader;import ljm.service.UserService;@ServerEndpoint(value="/chat",configurator=GetHttpSession.class)
public class MyWebSocket {private UserService userService = (UserService) ContextLoader.getCurrentWebApplicationContext().getBean("userService"); //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//更新数据的线程RefreshThread thread =null;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;/*** 连接建立成功调用的方法* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据* @throws Exception */@OnOpenpublic void onOpen(Session session,EndpointConfig config) throws Exception{ Integer age=userService.findUserAge(1);System.out.println(age);this.session = session;webSocketSet.add(this);HttpSession se= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());se.setAttribute("userId", 1);thread=new RefreshThread(session,se);thread.start();addOnlineCount(); //在线数加1System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(){thread.stopThread();webSocketSet.remove(this); //从set中删除subOnlineCount(); //在线数减1 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** 收到客户端消息后调用的方法* @param message 客户端发送过来的消息* @param session 可选的参数*/@OnMessagepublic void onMessage(String message, Session session) {System.out.println("来自客户端的消息:" + message);//群发消息for(MyWebSocket item: webSocketSet){ try {item.sendMessage(message);} catch (IOException e) {e.printStackTrace();continue;}}}/*** 发生错误时调用* @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error){System.out.println("发生错误");error.printStackTrace();}/*** 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。* @param message* @throws IOException*/public void sendMessage(String message) throws IOException{//同步this.session.getBasicRemote().sendText(message);//异步this.session.getAsyncRemote().sendText(message);}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {MyWebSocket.onlineCount++;}public static synchronized void subOnlineCount() {MyWebSocket.onlineCount--;}}
RefreshThread线程用于查询数据库有没有新的通知信息
package ljm.web;
import javax.servlet.http.HttpSession;
import javax.websocket.Session;import org.springframework.web.context.ContextLoader;import ljm.service.UserService;
public class RefreshThread extends Thread {private Session session;private Integer currentAge;private HttpSession se;UserService userService;private volatile boolean stop = false;//关闭线程public void stopThread() {this.stop = true;} public RefreshThread(Session session,HttpSession se) throws Exception {userService = (UserService) ContextLoader.getCurrentWebApplicationContext().getBean("userService"); this.session = session;this.se=se;currentAge =userService.findUserAge((Integer) se.getAttribute("userId")) ;//此时是0条最新消息}@Overridepublic void run() {Integer age=null;while (true) {try {Integer id=(Integer) se.getAttribute("userId");age=userService.findUserAge(id);if(age!=currentAge){session.getBasicRemote().sendText(age+"");currentAge=age;}//一秒刷新一次Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}}}
}
其次就是配置要通讯的JSP页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><base href="<%=basePath%>"><title>My JSP 'index.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"></head><body>Welcome<br/><input id="text" type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button><div id="message"></div></body><script type="text/javascript">var websocket = null;//判断当前浏览器是否支持WebSocketif('WebSocket' in window){websocket = new WebSocket("ws://localhost:8080/webSocketDemo/chat");}else{alert('Not support websocket');}//连接发生错误的回调方法websocket.onerror = function(){setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(event){setMessageInnerHTML("open");};//接收到消息的回调方法websocket.onmessage = function(event){setMessageInnerHTML(event.data);};//连接关闭的回调方法websocket.onclose = function(){setMessageInnerHTML("close");};//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function(){websocket.close();};//将消息显示在网页上function setMessageInnerHTML(innerHTML){document.getElementById('message').innerHTML += innerHTML + '<br/>';}//关闭连接function closeWebSocket(){websocket.close();}//发送消息function send(){var message = document.getElementById('text').value;websocket.send(message);}</script>
</html>
注意事项