在看了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; } }
到这里个人一些心得感悟就写完了,谢谢您的观看,但愿对您有所启发。