在看了websocket的簡介以後以爲websocket功能很強大,很實用,閒暇之餘進行了入門探索,這裏記錄了我在初探時的一些心得體會,有備無患。javascript
一、前臺在進行鏈接的創建的時候能夠採用html5中內置的api來創建鏈接css
var webSocket=new WebSocket("ws://ip地址:8080/項目名/路由","protocol");html
第一個參數是必須的,第二個參數是可選的,用與指定可接受的子協議html5
該WebSocket對象有四個方法:java
onerror,onopen,onmessage,onclosejquery
onerror--通訊錯誤時觸發web
onopen--創建鏈接時出發數據庫
onmessage--接收到服務端返回數據時觸發apache
onclose--關閉鏈接時觸發bootstrap
二、服務器端是用java來編寫,以註解形式進行開發的(若是以接口形式進行開發比較複雜,須要進行xml的配置)
用到的註解有:
@ServerEndpoint,@OnError,@OnOpen,@OnMessage,@OnClose
@ServerEndpoint--用來提供路由
其餘四個分別對應WebSocket對象的四個方法
三、以上工做都作完並不能正常創建鏈接,由於還須要tomcat7以上的版本支持,javaee-api 7.0及以上支持。
四、到這裏就可以正常創建鏈接。
五、如下我要說的是怎麼羣發消息
其實羣發消息的時候的思路是:遍歷全部在線的人的session,挨個推送消息
this.session.getBasicRemote().sendText(mess);
六、怎麼在項目中使用httpSession
這個點相對難一些,首先在不進行修改的狀況下能夠肯定WebSocket不可以直接使用httpSession,這裏用的是利用@ServerEndpoint註解中的的configurator來定義咱們須要的修改類
@ServerEndpoint(value="/connWebSocket",configurator=GetHttpSessionConfigurator.class)
自定義修改類GetHttpSessionConfigurator繼承Configurator,經過查看Configurator類咱們發現這樣一句話:
If the developer does not override this method, no further modification of the request and response are made by the implementation.
/** * Called by the container after it has formulated a handshake response resulting from * a well-formed handshake request. The container has already * checked that this configuration has a matching URI, determined the * validity of the origin using the checkOrigin method, and filled * out the negotiated subprotocols and extensions based on this configuration. * Custom configurations may override this method in order to inspect * the request parameters and modify the handshake response that the server has formulated. * and the URI checking also. * * <p>If the developer does not override this method, no further * modification of the request and response are made by the implementation. * * @param sec the configuration object involved in the handshake * @param request the opening handshake request. * @param response the proposed opening handshake response */ public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { // nothing. }
這句話對應的方法爲modifyHandshake,因此咱們對該方法進行修改,重寫了此方法:
package mywebsocket; import javax.servlet.http.HttpSession; import javax.websocket.HandshakeResponse; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpointConfig; import javax.websocket.server.ServerEndpointConfig.Configurator; public class GetHttpSessionConfigurator extends Configurator{ @Override public void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest req,HandshakeResponse res) { HttpSession httpSession = (HttpSession)req.getHttpSession(); sec.getUserProperties().put(HttpSession.class.getName(), httpSession); } }
接着查看HandshakeRequest類:
/** * Return a reference to the HttpSession that the web socket handshake that * started this conversation was part of, if the implementation * is part of a Java EE web container. * * @return the http session or {@code null} if either the websocket * implementation is not part of a Java EE web container, or there is * no HttpSession associated with the opening handshake request. */ Object getHttpSession();
到這裏咱們已經爲何要修改這些地方以及修改後的效果,這裏就再也不贅述,直接上一個小項目來幫助理解(一、這個小項目沒有使用數據庫來作登錄功能。二、這個登錄功能是爲了模擬多個用戶的狀況):
項目構建與maven工程中
項目結構:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lzy</groupId> <artifactId>mywebsocket</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>mywebsocket Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax/javaee-api --> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>mywebsocket</finalName> </build> </project>
web.xml
只進行了歡迎頁面的配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>mywebsocket</display-name> <welcome-file-list> <welcome-file>static/html/index.html</welcome-file> <welcome-file>static/html/default.html</welcome-file> </welcome-file-list> </web-app>
index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>test WebSocket</title> <!-- Bootstrap --> <link href="static/css/bootstrap.css" rel="stylesheet"> </head> <body> <form id="form1" action="http://192.168.0.199:8080/mywebsocket/logining" method="post"> 用戶名:<input type="text" name="username" class="form-control"> 密碼:<input type="password" name="password" class="form-control"> <input type="submit" id="btn" class="btn btn-success" value="login"> </form> <hr> <script src="static/js/jquery-3.2.1.js"></script> <script src="static/js/bootstrap.js"></script> <script src="static/js/login.js"></script> </body> </html>
chat.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang="zh-CN"> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>chat</title> <!-- Bootstrap --> <link href="../../static/css/bootstrap.css" rel="stylesheet"> </head> <body> <div id="jilu"> </div> <form action="" id="form1"> <textarea rows="4" cols="30" class="form-control" id="myWord" name="myWord"></textarea> </form> <input type="button" onclick="send()" value="send"> <input type="button" onclick="closeConn()" value="close connection"> <script src="../../static/js/jquery-3.2.1.js"></script> <script src="../../static/js/bootstrap.js"></script> <script src="../../static/js/testWebsocket.js"></script> </body> </html>
testWebsocket.js
if("WebSocket" in window){ console.log("this browser supports websocket..."); var webSocket=new WebSocket("ws://192.168.0.199:8080/mywebsocket/connWebSocket"); }else{ console.log("this browser does not supports websocket..."); } webSocket.onerror=function(){ console.log("連接錯誤..."); } webSocket.onopen=function(){ console.log("連接成功..."); } webSocket.onmessage=function(event){ $("#jilu").append($("<p></p>").text(event.data)); } webSocket.onclose=function(){ console.log("連接關閉..."); } window.onbeforeunload=function(){ console.log("窗口即將關閉,準備關閉連接..."); webSocket.close(); } var send=function(){ webSocket.send(decodeURIComponent($("#form1").serialize(),true)); $("#myWord").val(""); } var closeConn=function(){ webSocket.close(); }
Logining.java
package mywebsocket; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/logining") public class Logining extends HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html;charset=utf-8"); req.setCharacterEncoding("utf-8"); String username=req.getParameter("username"); String password=req.getParameter("password"); if("aaa".equals(username)) { if("1234".equals(password)) { req.getSession().setAttribute("username", username); req.getSession().setAttribute("name","張三"); req.getSession().setAttribute("sId",req.getSession().getId()); res.sendRedirect("static/html/chat.jsp"); System.out.println(req.getSession().getId()); }else { System.out.println("密碼不對..."); PrintWriter out = res.getWriter(); out.println("<div>密碼不對</div>"); } }else if("bbb".equals(username)) { if("1234".equals(password)) { req.getSession().setAttribute("username", username); req.getSession().setAttribute("name","李四"); req.getSession().setAttribute("sId",req.getSession().getId()); res.sendRedirect("static/html/chat.jsp"); System.out.println(req.getSession().getId()); }else { System.out.println("密碼不對..."); PrintWriter out = res.getWriter(); out.println("<div>密碼不對</div>"); } }else if("ccc".equals(username)) { if("1234".equals(password)) { req.getSession().setAttribute("username", username); req.getSession().setAttribute("name","李四"); req.getSession().setAttribute("sId",req.getSession().getId()); res.sendRedirect("static/html/chat.jsp"); System.out.println(req.getSession().getId()); }else { System.out.println("密碼不對..."); PrintWriter out = res.getWriter(); out.println("<div>密碼不對</div>"); } }else { System.out.println("用戶名不對..."); PrintWriter out = res.getWriter(); out.println("<div>用戶名不對</div>"); } } }
GetHttpSessionConfigurator.java
package mywebsocket; import javax.servlet.http.HttpSession; import javax.websocket.HandshakeResponse; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpointConfig; import javax.websocket.server.ServerEndpointConfig.Configurator; public class GetHttpSessionConfigurator extends Configurator{ @Override public void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest req,HandshakeResponse res) { HttpSession httpSession = (HttpSession)req.getHttpSession(); sec.getUserProperties().put(HttpSession.class.getName(), httpSession); } }
MyWebSocket.java
package mywebsocket; import java.io.IOException; import java.util.ArrayList; import java.util.List; 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; @ServerEndpoint(value="/connWebSocket",configurator=GetHttpSessionConfigurator.class) public class MyWebSocket { private Session session; private static List<MyWebSocket> mwsL=new ArrayList<MyWebSocket>(); private List<HttpSession> httpSL=new ArrayList<>(); private static long userCount=0; @OnOpen public void open(Session session,EndpointConfig config) { System.out.println("open..."); HttpSession httpSession = (HttpSession)config.getUserProperties().get(HttpSession.class.getName()); boolean flag = httpSL.add(httpSession); System.out.println(flag); this.session=session; System.out.println(session.getId()); System.out.println(this); mwsL.add(this); addUserCount(); System.out.println(httpSession.getAttribute("name")+"加入,當前在線人數:"+MyWebSocket.getUserCount()); } @OnClose public void close(Session session) { System.out.println("連接關閉..."); subUserCount(); System.out.println(httpSL.get(0).getAttribute("name")+"退出,當前在線人數:"+MyWebSocket.getUserCount()); mwsL.remove(this); } @OnError public void error(Throwable error) { System.out.println("連接出錯..."); error.printStackTrace(); } @OnMessage public void message(String mess){ String message=httpSL.get(0).getAttribute("name")+" say:"+mess.substring(mess.indexOf("=")+1); System.out.println("cowal size:"+mwsL.size()); System.out.println("httpSL size:"+httpSL.size()); for(MyWebSocket items:mwsL) { System.out.println(items.httpSL.get(0).getAttribute("name")); if(mwsL.size()==2) { try { items.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } } } public void sendMessage(String mess) throws IOException { this.session.getBasicRemote().sendText(mess); } private static synchronized void addUserCount() { MyWebSocket.userCount++; } private static synchronized void subUserCount() { MyWebSocket.userCount--; } private static synchronized long getUserCount() { return MyWebSocket.userCount; } }
到這裏個人一些心得感悟就寫完了,謝謝您的觀看,但願對您有所啓發。