初探websocket

在看了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;
	}
	
}

到這裏個人一些心得感悟就寫完了,謝謝您的觀看,但願對您有所啓發。

相關文章
相關標籤/搜索