在看了websocket的简介之后觉得websocket功能很强大,很实用,闲暇之余进行了入门探索,这里记录了我在初探时的一些心得体会,有备无患。
1、前台在进行连接的建立的时候可以采用html5中内置的api来建立连接
var webSocket=new WebSocket("ws://ip地址:8080/项目名/路由","protocol");
第一个参数是必须的,第二个参数是可选的,用与指定可接受的子协议
该WebSocket对象有四个方法:
onerror,onopen,onmessage,onclose
onerror--通信错误时触发
onopen--建立连接时出发
onmessage--接收到服务端返回数据时触发
onclose--关闭连接时触发
2、服务器端是用java来编写,以注解形式进行开发的(如果以接口形式进行开发比较复杂,需要进行xml的配置)
用到的注解有:
@ServerEndpoint,@OnError,@OnOpen,@OnMessage,@OnClose
@ServerEndpoint--用来提供路由
其他四个分别对应WebSocket对象的四个方法
3、以上工作都做完并不能正常建立连接,因为还需要tomcat7以上的版本支持,javaee-api 7.0及以上支持。
4、到这里就能够正常建立连接。
5、以下我要说的是怎么群发消息
其实群发消息的时候的思路是:遍历所有在线的人的session,挨个推送消息
this.session.getBasicRemote().sendText(mess);
6、怎么在项目中使用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();
到这里我们已经为什么要修改这些地方以及修改后的效果,这里就不再赘述,直接上一个小项目来帮助理解(1、这个小项目没有使用数据库来做登陆功能。2、这个登陆功能是为了模拟多个用户的情况):
项目构建与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;
}
}
到这里我的一些心得感悟就写完了,谢谢您的观看,希望对您有所启发。