使用Java实现WebSocket一对一 ,一对多消息推送 亲测有效!!!!!!!
前端:一张HTML页面
后端: SpringBoot
管理工具: Maven
这三个都是Java开发的必备技能,不多做解释了, 直接发车
现在本人前端开发多用Vue,但是都是用的原生的JavaScript,所以用什么框架无所谓…
这里主要实现功能,就不写样式什么的了,但是原理一致
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body></body>
<script>let webSocket = null; // 创建一个变量if ('WebSocket' in window){ // 判断当前的浏览器是否支持WebSocket// 如果支持则创建一个WebSocket赋值给刚才创建的变量// 后面的路径实际上就是一次请求,但是这里用的是WebSocket协议// 记住这个地方后面详细讲到怎么写webSocket = new WebSocket('ws://localhost:8080/webSocket');}else{ // 如果不兼容则弹框,该浏览器不支持alert('该浏览器不支持')}/** * 当WebSocket创建连接(初始化)会触发该方法*/pen = function (event){console.log('建立连接') // 这个代表在浏览器打印日志,跟Java的System.out.println()意思一致}/** * 当WebSocket关闭时候会触发该方法*/lose = function (event){console.log('关闭连接') // 同上}/** * 当WebSocket接受消息会触发该方法*/ssage = function (event){console.log('收到消息:'+event.data)}/** * 当WebSocket连接出错触发该方法*/r = function (event){console.log('websocket发生错误');}/** * 页面关闭,WebSocket关闭*/beforeunload = function (){webSocket.close();}
</script>
</html>
引入WebSocket的依赖,这里给予SpringBoot,所以直接引入SpringBoot-Start的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
书写配置类,其实就是实例化一个Bean
@Component
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}
一般的请求都会写到Controller里面,咱们的WebSocket写到Service方便多次调用
一对一还是一对多,方法的区别在这里,接下来先说群发消息的那种(就是所有加入到WebSocket的用户都会收到该消息)
@Component // 交给IOC容器
@ServerEndpoint("/webSocket") // 这里的路径跟上面Js创建的WebSocket路径一致
public class WebSocketService {// 定义属性private Session session; //创建一个set用来存储用户private static CopyOnWriteArraySet<WebSocketService> websockets = new CopyOnWriteArraySet<>(); /*** 当有用户创建连接时候调用该方法*/@OnOpenpublic void onOpen(Session session) {// 给当前的Session赋值this.session = session; // 将当前对象添加到CopyOnWriteArraySet 中websockets.add(this); // 可以获取该session,但是其实也是一个内存地址println("【建立连接】 用户为:" + this.session); // 获取总数,这个不难理解,实际上这个集合的总数,就是WebSocket连接的总数println("【建立连接】 总数为:" + websockets.size()); }/*** 有用户连接断开时候触发该方法*/@OnClosepublic void onClose() {ve(this); // 将当前的对象从集合中删除println("【连接断开】 用户为:" + this.session); println("【连接断开】 总数为:" + websockets.size());}/*** 这个方法是客户端给服务端发送消息触发该方法* @param message : 消息内容*/@OnMessagepublic void onMessage(String message) {println("【收到客户端发的消息】:" + message);}/*** 发送消息的方法,方便后期别的service调用** @param message 消息内容*/public void sendMessage(String message) {for (WebSocketService websocket : websockets) { // 遍历该Set集合 println("广播消息 【给用户】 :" + websocket + "发送消息" + "【" + message + "】"); // 获取一个,在控制台打印一句话try {BasicRemote().sendText(message); // 发送消息的方法} catch (IOException e) {e.getMessage();}}}
}
为了方便测试,在写一个接口,用来发送消息
@RestController
@RequestMapping("/hello")
public class Controller {@Autowiredprivate WebSocketService webSocketService;@GetMapping("h1")public void h1() {webSocketService.sendMessage("您有新的消息"); // 调用Service的发送消息的方法}
}
接下来就是测试
后端SpringBoot项目启动…
两张页面分别去访问,我直接用两个浏览器方便看清
当页面进去的时候,打开F12可以看到建立连接,则证明与后端WebSocket连接成功
接下来用PostMan等等接口测试工具或者浏览器url都行,去请求刚才写的接口,也就是localhost:8080/hello/h1
请求一次则页面会提示收到消息
就成功了
接下来很多人就会问一对一怎么发,我不想群发
那么接下来就改造一下WebSocketService就好了,跟上步伐 冲冲冲
思路: 看黑板!!!!!!!!!
实际上对于刚才所有的Session都是用的Set存储的,我这里可以使用一个Map存储,将Session作为Value,而key就用用户的唯一标识,比如用户ID等等…
接下来,换曲:
<script>let webSocket = null;if ('WebSocket' in window){webSocket = new WebSocket('ws://localhost:8080/webSocket/2'); // 这里后面拼接一个Id,我这里测试所以就写1和2模拟两个用户}else{alert('该浏览器不支持')}pen = function (event){console.log('建立连接')}lose = function (event){console.log('关闭连接')}ssage = function (event){console.log('收到消息:'+event.data)}r = function (event){console.log('websocket发生错误');}beforeunload = function (){webSocket.close();}
</script>
@Component
@ServerEndpoint("/webSocket/{id}") // 这里建立连接后面跟上一个ID
public class WebSocketService {private Session session;// 这里用ConcurrentHashMap 因为他是一个线程安全的Mapprivate static ConcurrentHashMap<Long, WebSocketService> websockets = new ConcurrentHashMap<>();@OnOpenpublic void onOpen(@PathParam("id") Long id, Session session) { // 接收到前端传来的用户IDthis.session = session;websockets.put(id, this); //将ID作为key,当前的对象作为println("【建立连接】 用户为:" + this.session);println("【建立连接】 用户Id为:" + id);println("【建立连接】 总数为:" + websockets.size());}/*** 发送消息方法 【为了方便大家理解,我这里直接不封装了】** @param message 消息* @param userId 用户ID*/public void sendMessage(String message, Long userId) {if (userId == null) { // 如果等于null则证明是群发// 获取当前Map的一个迭代器,遍历Map的方式有很多种,看着来Iterator<Map.Entry<Long, WebSocketService>> iterator = Set().iterator(); // 这个就是遍历这个集合的过程....while (iterator.hasNext()) { // 获取每一个Entry实例Map.Entry<Long, WebSocketService> entry = (); // 获取每一个Value,而这个Value就是WebSocket的实例WebSocketService webSocket = Value(); // 接下来就是遍历群发println("广播消息 【给用户】 :" + webSocket + "发送消息" + "【" + message + "】"); try {BasicRemote().sendText(message); // 发送!!!!!!!!!} catch (IOException e) {throw new RuntimeException(e);}}} else { // 如果不是群发,则判断ID,其余步骤一致// 获取当前Map的一个迭代器,遍历Map的方式有很多种,看着来Iterator<Map.Entry<Long, WebSocketService>> iterator2 = Set().iterator(); // 这个就是遍历这个集合的过程....while (iterator2.hasNext()) {// 获取每一个Entry实例Map.Entry<Long, WebSocketService> entry = (); // 获取每一个Value,而这个Value就是WebSocket的实例WebSocketService webSocket = Value(); // 获取每一个Key,这个Key就是用户IDLong key = Key(); // 判断用户ID与当前的Key相等if (userId == key) { println("广播消息 【给用户】 :" + key + "发送消息" + "【" + message + "】"); // 打印try {BasicRemote().sendText(message); // 则发送给当前的用户即可} catch (IOException e) {throw new RuntimeException(e);}}return; }}}
本文发布于:2024-01-28 03:10:25,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063826314353.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |