初探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;
	}
	
}

到这里个人一些心得感悟就写完了,谢谢您的观看,但愿对您有所启发。