首先声明,本篇博文参考文章

https://blog.csdn.net/jack_eusong/article/details/79064081

主要在于理解和自己动手搭建环境,自己搭建的过程中会发生很多意想不到的错误。

1.环境

Eclipse Mars + jdk1.7 + tomcat8

2.使用的jar包,spring 的核心jar包就不写了,只写和websocket相关的。

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.0.2.RELEASE</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>4.0.2.RELEASE</version>
</dependency> <dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>

其实我感觉只用 javax.websocket-api 这一个包就够了,可能是我本地环境有问题,如果取消前面两个包Tomcat 无法启动,所以就只能留着了

搭建完的项目结构如下图

主要的代码注意一个类,通过@ServerEndpoint注解将类声明为服务端

package com.lzl.ws;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint; import org.apache.log4j.Logger;
import org.springframework.web.socket.server.standard.SpringConfigurator; @ServerEndpoint(value="/chat/{userId}",configurator = SpringConfigurator.class)
public class websocketchat{
public static Logger logger = Logger.getLogger(websocketchat.class); //在线人数
public static int onlineCount = 0; //记录每个用户下多个终端的连接
private static Map<String, Set<websocketchat>> userSocket = new HashMap<>(); //需要session来对用户发送数据, 获取连接特征userId
private Session session;
private String userId; @OnOpen
public void onOpen(@PathParam("userId") String userId,Session session) throws IOException{
this.session = session;
this.userId = userId;
onlineCount++;
//根据该用户当前是否已经在别的终端登录进行添加操作
if (userSocket.containsKey(this.userId)) {
logger.info("当前用户id:{"+this.userId+"}已有其他终端登录");
userSocket.get(this.userId).add(this); //增加该用户set中的连接实例
}else {
logger.info("当前用户id:{"+this.userId+"}第一个终端登录");
Set<websocketchat> addUserSet = new HashSet<>();
addUserSet.add(this);
userSocket.put(this.userId, addUserSet);
}
logger.info("用户{"+userId+"}登录的终端个数是为{"+userSocket.get(this.userId).size()+"}");
logger.info("当前在线用户数为:{"+userSocket.size()+"},所有终端个数为:{"+onlineCount+"}");
} @OnClose
public void onClose(){
//移除当前用户终端登录的websocket信息,如果该用户的所有终端都下线了,则删除该用户的记录
if (userSocket.get(this.userId).size() == 0) {
userSocket.remove(this.userId);
}else{
userSocket.get(this.userId).remove(this);
}
logger.info("用户{"+this.userId+"}登录的终端个数是为{"+userSocket.get(this.userId).size()+"}");
logger.info("当前在线用户数为:{"+userSocket.size()+"},所有终端个数为:{"+onlineCount+"}");
} /**
* @Title: onMessage
* @Description: 收到消息后的操作
* @param @param message 收到的消息
* @param @param session 该连接的session属性
*/
@OnMessage
public void onMessage(String message, Session session) {
logger.info("收到来自用户id为:{"+this.userId+"}的消息:{"+message+"}");
if(session ==null) logger.info("session null");
//测试向客户端发送消息发送
logger.info("开始将消息以广播形式发送至所有终端.......");
sendMessageToUser( this.userId+"说:"+message);
logger.info("广播结束.......");
} /**
* @Title: onError
* @Description: 连接发生错误时候的操作
* @param @param session 该连接的session
* @param @param error 发生的错误
*/
@OnError
public void onError(Session session, Throwable error){
logger.info("用户id为:{"+this.userId+"}的连接发送错误");
error.printStackTrace();
} /**
* @Title: sendMessageToUser
* @Description: 发送消息给用户下的所有终端
* @param @param userId 用户id
* @param @param message 发送的消息
* @param @return 发送成功返回true,反则返回false
*/
public Boolean sendMessageToUser(String message){
for(Entry<String, Set<websocketchat>> entry:userSocket.entrySet()){
logger.info(" 给用户id为:{"+entry.getKey()+"}的所有终端发送消息:{"+message+"}");
for(websocketchat ws:entry.getValue()){
try {
ws.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
logger.info(" 给用户id为:{"+userId+"}发送消息失败");
return false;
}
}
}
return true; } }

前端界面

<%@ 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>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(function() {
var websocket;
if('WebSocket' in window) {
console.log("此浏览器支持websocket");
websocket = new WebSocket("ws://127.0.0.1:8080/websocket/chat/tom");
} else if('MozWebSocket' in window) {
alert("此浏览器只支持MozWebSocket");
} else {
alert("此浏览器只支持SockJS");
}
websocket.onopen = function(evnt) {
$("#tou").html("链接服务器成功!")
};
websocket.onmessage = function(evnt) {
$("#msg").html($("#msg").html() + "<br/>" + evnt.data);
};
websocket.onerror = function(evnt) {};
websocket.onclose = function(evnt) {
$("#tou").html("与服务器断开了链接!")
} $('#send').click(function(){
send();
}); function send() {
if(websocket != null) {
var message = document.getElementById('message').value;
websocket.send(message);
} else {
alert('未与服务器链接.');
}
}
});
</script> <title>chat</title>
</head>
<body>
<div >
<div class="page-header" id="tou" style = "text-align:center">
webSocket多终端聊天测试
</div>
<div class="well" id="msg" style = "width:800px;margin:0 auto"></div>
&nbsp;
<div class="col-lg">
<div class="input-group" style = "width:800px;margin:0 auto">
<input type="text" class="form-control" placeholder="发送信息..." id="message">
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="send" >发送</button>
</span>
</div>
</div>
</div>
</body>
</html>

在参考文章的基础上将发送消息改为群发形式,即一个人发送所有在线终端均可接收。chat.jsp,chat2.jsp,chat3.jsp用来模拟三个用户的登录。

websocket = new WebSocket("ws://127.0.0.1:8080/websocket/chat/tom") 中websocket是我的工程名字,chat是服务端路径,tom是服务端参数,定义为用户ID。其实只用写一个界面即可,通过其他方式动态获取用户ID。这里为了方便测试,后续会增加一个登陆功能,然后将用户ID放到session中,获取用户ID后创建websocket对象,类似一个简易的聊天室功能。chat2和chat3 和chat 一模一样,只是更改了路径中的用户ID。这三个用户ID分别是tom jone jack,实现效果如下图。

Websocket --(2)实现的更多相关文章

  1. 漫扯:从polling到Websocket

    Http被设计成了一个单向的通信的协议,即客户端发起一个request,然后服务器回应一个response.这让服务器很为恼火:我特么才是老大,我居然不能给小弟发消息... 轮询 老大发火了,小弟们自 ...

  2. 细说WebSocket - Node篇

    在上一篇提高到了 web 通信的各种方式,包括 轮询.长连接 以及各种 HTML5 中提到的手段.本文将详细描述 WebSocket协议 在 web通讯 中的实现. 一.WebSocket 协议 1. ...

  3. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  4. WebSocket - ( 一.概述 )

    说到 WebSocket,不得不提 HTML5,作为近年来Web技术领域最大的改进与变化,包含CSS3.离线与存储.多媒体.连接性( Connectivity )等一系列领域,而即将介绍的 WebSo ...

  5. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

  6. Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!

    随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...

  7. Cowboy 开源 WebSocket 网络库

    Cowboy.WebSockets 是一个托管在 GitHub 上的基于 .NET/C# 实现的开源 WebSocket 网络库,其完整的实现了 RFC 6455 (The WebSocket Pro ...

  8. 借助Nodejs探究WebSocket

    文章导读: 一.概述-what's WebSocket? 二.运行在浏览器中的WebSocket客户端+使用ws模块搭建的简单服务器 三.Node中的WebSocket 四.socket.io 五.扩 ...

  9. 细说websocket - php篇

    下面我画了一个图演示 client 和 server 之间建立 websocket 连接时握手部分,这个部分在 node 中可以十分轻松的完成,因为 node 提供的 net 模块已经对 socket ...

  10. webSocket and LKDBHelper的使用说明

    socketket与lkdbhelper来处理数据 客户需求: 当我们有需要从自己的后台推送消息给我们的用户时,用户需要实时的接收到来自我们的推送消息.前提是没有使用第三方的推送框架,那么这个使用we ...

随机推荐

  1. 对vue-router的研究--------------引用

    pushState/replaceState/popstate 解析 HTML5提供了对history栈中内容的操作.通过history.pushState/replaceState实现添加地址到hi ...

  2. C# 常用方法——图片转base64字符串

    其他扩展方法详见:https://www.cnblogs.com/zhuanjiao/p/12060937.html /// <summary> /// Image 转成 base64 / ...

  3. PHP教程-反序列化的方法

    序列化是将变量转换为可保存或传输的字符串的过程:反序列化就是在适当的时候把这个字符串再转化成原来的变量使用.这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性.兄弟连PHP培训() 1. ...

  4. 《python cookbook》学习笔记

    2016.5.3 第8章  类与对象 8.1 改变对象的字符串显示 __str__ 和 __repr__   %s 和 %r,提到了eval,我没有用过 8.2 自定义字符串的格式化  __forma ...

  5. #4 div1E Parentheses 括号匹配

    E - Parentheses Time Limit:2000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu Subm ...

  6. OCWA提高组模拟赛一 Solution

    Problem A RecMin 给出一个$n \times m$的矩阵,其中$1 \leq n,m \leq 3\ times 10^3$ 给出整数$a,b$,求出在矩阵中所有$a\ times b ...

  7. lcez校内模拟赛: 小R与苹果派——题解

    题目传送 首先对两个数组排序. 然后预处理出数组p[i]表示b[x]<a[i]的最大的x. 然后我们设f[i][k]表示对于前i个派,我单独选出来k组a[y]>b[y].(即此时有k组a& ...

  8. 网络安全监控实战(一):Snort,Wazuh&VT

    https://cloud.tencent.com/developer/news/222711

  9. 建立WIN32 DLL,并使用静态加载和动态加载

    新建工程,选择win32 dll 编写.cpp(或.c) MyDll.cpp #include "windows.h" BOOL APIENTRY DllMain(HANDLE h ...

  10. 手动清空微信PC客户端数据

    微信PC客户端,用久了之后,会产生大量数据,包括聊天记录.聊天图片.视频等等,非常占存储空间,除非很重要的聊天记录或文件,建议额外保存,其他的可以手动删掉就好,可以节省存储空间. 1.找到[C:\Us ...