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

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,实现效果如下图。

最新文章

  1. 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改
  2. iOS 源代码管理工具之SVN
  3. atitit.自适应设计悬浮图片的大小and 位置
  4. Qt入门(20)——Qt模块简介
  5. escape encodeURI encodeURIComponent区别
  6. 编程那些事儿:如何快速地&quot;借用&quot;CSS
  7. 记录——excel导出lua工具(python实现)
  8. phoenix常用命令
  9. 利用wireshark任意获取qq好友IP实施精准定位
  10. 《前端之路》之 webpack 4.0+ 的应用构建
  11. hibernate06--参数的绑定
  12. Maven项目读取resources下文件的路径问题(getClassLoader的作用)
  13. ES系列九、ES优化聚合查询之深度优先和广度优先
  14. Spring 3.1新特性之二:@Enable*注解的源码,spring源码分析之定时任务Scheduled注解
  15. 【jdk源码分析】jdk8的ArrayList初始化长度为0
  16. python ros 回充demo
  17. NOIP2016 组合数问题
  18. 采用dlopen、dlsym、dlclose加载动态链接库
  19. Django的模版引擎与模版使用
  20. BZOJ1257:[CQOI2007]余数之和——题解+证明

热门文章

  1. Python CGI编程Ⅸ
  2. 7、菜单栏、工具栏、状态栏、浮动窗口、TextEdit
  3. 窗体操作:CBrush类
  4. [LOJ3046][ZJOI2019]语言:树链的并+线段树合并
  5. redis-sentinel 主从复制高可用
  6. JAVA_OPT理解及调优理论
  7. 【Spark机器学习速成宝典】模型篇01支持向量机【SVM】(Python版)
  8. leetcode-easy-string-14 Longest Common Prefix
  9. python中_new_()与_init_()的区别
  10. 无界面上(linux)生成测试报告(3)