0


java后端+前端使用WebSocket实现消息推送

java后端+前端使用WebSocket实现消息推送(流程+详细代码)

在项目的开发时,遇到实现服务器主动发送数据到前端页面的功能的需求。实现该功能不外乎使用轮询和websocket技术,但在考虑到实时性和资源损耗后,最后决定使用websocket。现在就记录一下用Java实现Websocket技术吧~

    Java实现Websocket通常有两种方式:1、创建WebSocketServer类,里面包含open、close、message、error等方法;2、利用Springboot提供的webSocketHandler类,创建其子类并重写方法。我们项目虽然使用Springboot框架,不过仍采用了第一种方法实现。

创建WebSocket的简单实例操作流程

1.引入Websocket依赖

  1. <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.7.0</version></dependency>

2.创建配置类WebSocketConfig

  1. importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.socket.server.standard.ServerEndpointExporter;/**
  2. * 开启WebSocket支持
  3. */@ConfigurationpublicclassWebSocketConfig{@BeanpublicServerEndpointExporterserverEndpointExporter(){returnnewServerEndpointExporter();}}

3.创建WebSocketServer

在websocket协议下,后端服务器相当于ws里面的客户端,需要用@ServerEndpoint指定访问路径,并使用@Component注入容器

@ServerEndpoint:当ServerEndpointExporter类通过Spring配置进行声明并被使用,它将会去扫描带有@ServerEndpoint注解的类。被注解的类将被注册成为一个WebSocket端点。所有的配置项都在这个注解的属性中
( 如:@ServerEndpoint(“/ws”) )

下面的栗子中@ServerEndpoint指定访问路径中包含sid,这个是用于区分每个页面

  1. importcom.alibaba.fastjson.JSONObject;importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Component;importorg.springframework.util.StringUtils;importjavax.websocket.*;importjavax.websocket.server.PathParam;importjavax.websocket.server.ServerEndpoint;importjava.io.IOException;importjava.net.Socket;importjava.util.*;importjava.util.concurrent.ConcurrentHashMap;/**
  2. * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
  3. * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
  4. */@ServerEndpoint("/notice/{userId}")@Component@Slf4jpublicclassNoticeWebsocket{//记录连接的客户端publicstaticMap<String,Session> clients =newConcurrentHashMap<>();/**
  5. * userId关联sid(解决同一用户id,在多个web端连接的问题)
  6. */publicstaticMap<String,Set<String>> conns =newConcurrentHashMap<>();privateString sid =null;privateString userId;/**
  7. * 连接成功后调用的方法
  8. * @param session
  9. * @param userId
  10. */@OnOpenpublicvoidonOpen(Session session,@PathParam("userId")String userId){this.sid = UUID.randomUUID().toString();this.userId = userId;
  11. clients.put(this.sid, session);Set<String> clientSet = conns.get(userId);if(clientSet==null){
  12. clientSet =newHashSet<>();
  13. conns.put(userId,clientSet);}
  14. clientSet.add(this.sid);
  15. log.info(this.sid +"连接开启!");}/**
  16. * 连接关闭调用的方法
  17. */@OnClosepublicvoidonClose(){
  18. log.info(this.sid +"连接断开!");
  19. clients.remove(this.sid);}/**
  20. * 判断是否连接的方法
  21. * @return
  22. */publicstaticbooleanisServerClose(){if(NoticeWebsocket.clients.values().size()==0){
  23. log.info("已断开");returntrue;}else{
  24. log.info("已连接");returnfalse;}}/**
  25. * 发送给所有用户
  26. * @param noticeType
  27. */publicstaticvoidsendMessage(String noticeType){NoticeWebsocketResp noticeWebsocketResp =newNoticeWebsocketResp();
  28. noticeWebsocketResp.setNoticeType(noticeType);sendMessage(noticeWebsocketResp);}/**
  29. * 发送给所有用户
  30. * @param noticeWebsocketResp
  31. */publicstaticvoidsendMessage(NoticeWebsocketResp noticeWebsocketResp){String message =JSONObject.toJSONString(noticeWebsocketResp);for(Session session1 :NoticeWebsocket.clients.values()){try{
  32. session1.getBasicRemote().sendText(message);}catch(IOException e){
  33. e.printStackTrace();}}}/**
  34. * 根据用户id发送给某一个用户
  35. * **/publicstaticvoidsendMessageByUserId(String userId,NoticeWebsocketResp noticeWebsocketResp){if(!StringUtils.isEmpty(userId)){String message =JSONObject.toJSONString(noticeWebsocketResp);Set<String> clientSet = conns.get(userId);if(clientSet !=null){Iterator<String> iterator = clientSet.iterator();while(iterator.hasNext()){String sid = iterator.next();Session session = clients.get(sid);if(session !=null){try{
  36. session.getBasicRemote().sendText(message);}catch(IOException e){
  37. e.printStackTrace();}}}}}}/**
  38. * 收到客户端消息后调用的方法
  39. * @param message
  40. * @param session
  41. */@OnMessagepublicvoidonMessage(String message,Session session){
  42. log.info("收到来自窗口"+this.userId+"的信息:"+message);}/**
  43. * 发生错误时的回调函数
  44. * @param error
  45. */@OnErrorpublicvoidonError(Throwable error){
  46. log.info("错误");
  47. error.printStackTrace();}}

封装了一个发送消息的对象可以直接使用

  1. importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;@Data@ApiModel("ws通知返回对象")publicclassNoticeWebsocketResp<T>{@ApiModelProperty(value ="通知类型")privateString noticeType;@ApiModelProperty(value ="通知内容")privateT noticeInfo;}

4.websocket调用

一个用户调用接口,主动将信息发给后端,后端接收后再主动推送给指定/全部用户

  1. @RestController@RequestMapping("/order")publicclassOrderController{@GetMapping("/test")publicRtest(){NoticeWebsocket.sendMessage("你好,WebSocket");returnR.ok();}}

前端WebSocket连接

  1. <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>SseEmitter</title></head><body><divid="message"></div></body><script>var limitConnect =0;init();functioninit(){var ws =newWebSocket('ws://192.168.2.88:9060/notice/1');// 获取连接状态
  2. console.log('ws连接状态:'+ ws.readyState);//监听是否连接成功
  3. ws.onopen=function(){
  4. console.log('ws连接状态:'+ ws.readyState);
  5. limitConnect =0;//连接成功则发送一个数据
  6. ws.send('我们建立连接啦');}// 接听服务器发回的信息并处理展示
  7. ws.onmessage=function(data){
  8. console.log('接收到来自服务器的消息:');
  9. console.log(data);//完成通信后关闭WebSocket连接// ws.close();}// 监听连接关闭事件
  10. ws.onclose=function(){// 监听整个过程中websocket的状态
  11. console.log('ws连接状态:'+ ws.readyState);reconnect();}// 监听并处理error事件
  12. ws.onerror=function(error){
  13. console.log(error);}}functionreconnect(){
  14. limitConnect ++;
  15. console.log("重连第"+ limitConnect +"次");setTimeout(function(){init();},2000);}</script></html>

项目启动,打开页面后控制台打印连接信息
在这里插入图片描述
调用order/test方法后前端打印推送消息内容
在这里插入图片描述
这样,就可以接口或者ws调用网址的方式进行websocket的通信啦~
如果没有前端页面也可以使用在线WebSocket测试
在这里插入图片描述

OK,下课!!!

标签: java websocket 前端

本文转载自: https://blog.csdn.net/poker_zero/article/details/126184697
版权归原作者 poker_zero 所有, 如有侵权,请联系我们删除。

“java后端+前端使用WebSocket实现消息推送”的评论:

还没有评论