当前位置: 首页 > news >正文

JAVA Spring WebSocket 实时消息

代码环境:

        jdk8, spring-boot1.5.22

依赖:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.22.RELEASE</version><relativePath /> <!-- lookup parent from repository -->
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!-- spring-boot的web启动的jar包 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion><exclusion><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></exclusion><exclusion><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></exclusion><exclusion><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId></exclusion><exclusion><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId></exclusion><exclusion><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId></exclusion></exclusions></dependency></dependencies>

代码:

package cn.com.trinitygo.scm.common.util.websocket;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;/*** websocket的配置类* @ClassName: CustomWebSocketConfig* @Author: peilei* @Date: 2021/9/13 14:59* @Description*/
@Configuration
@EnableWebSocket
public class CustomWebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(customWebSocketHandler(), "/webSocketBySpring/customWebSocketHandler").addInterceptors(new CustomWebSocketInterceptor()).setAllowedOrigins("*");registry.addHandler(customWebSocketHandler(), "/sockjs/webSocketBySpring/customWebSocketHandler").addInterceptors(new CustomWebSocketInterceptor()).setAllowedOrigins("*").withSockJS();}@Beanpublic WebSocketHandler customWebSocketHandler() {return new CustomWebSocketHandler();}
}
package cn.com.trinitygo.scm.common.util.websocket;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;/*** WebSocket握手时的拦截器* @ClassName: CustomWebSocketInterceptor* @Author: peilei* @Date: 2021/9/13 15:00* @Description*/
public class CustomWebSocketInterceptor implements HandshakeInterceptor {private Logger logger = LoggerFactory.getLogger(CustomWebSocketInterceptor.class);/*** 关联HeepSession和WebSocketSession,* beforeHandShake方法中的Map参数 就是对应websocketSession里的属性*/@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Map<String, Object> map) throws Exception {if (request instanceof ServletServerHttpRequest) {logger.info("*****beforeHandshake******");HttpServletRequest httpServletRequest = ((ServletServerHttpRequest) request).getServletRequest();HttpSession session = httpServletRequest.getSession(true);logger.info("userId:{}", httpServletRequest.getParameter("userId"));if (session != null) {map.put("sessionId",session.getId());map.put("userId", httpServletRequest.getParameter("userId"));}}return true;}@Overridepublic void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {logger.info("******afterHandshake******");}
}
package cn.com.trinitygo.scm.common.util.websocket;import cn.com.trinitygo.scm.service.SysMsgService;
import com.alibaba.fastjson.JSONObject;
import httl.util.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.slf4j.Logger;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;/*** 创建一个WebSocket server** @ClassName: CustomWebSocketHandler* @Author: peilei* @Date: 2021/9/13 14:48* @Description*/
@Service
public class CustomWebSocketHandler extends TextWebSocketHandler implements WebSocketHandler {@AutowiredSysMsgService sysMsgService;private Logger logger = LoggerFactory.getLogger(CustomWebSocketHandler.class);// 在线用户列表private static final Map<String, WebSocketSession> users;// 用户标识private static final String CLIENT_ID = "userId";static {users = new HashMap<>();}@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {logger.info("成功建立websocket-spring连接");String userId = getUserId(session);if (StringUtils.isNotEmpty(userId)) {users.put(userId, session);session.sendMessage(new TextMessage("成功建立websocket-spring连接"));logger.info("用户标识:{},Session:{}", userId, session.toString());}}@Overridepublic void handleTextMessage(WebSocketSession session, TextMessage message) {logger.info("收到客户端消息:{}", message.getPayload());JSONObject msgJson = JSONObject.parseObject(message.getPayload());String to = msgJson.getString("to");String msg = msgJson.getString("msg");WebSocketMessage<?> webSocketMessageServer = new TextMessage("server:" + message);try {session.sendMessage(webSocketMessageServer);if ("all".equals(to.toLowerCase())) {sendMessageToAllUsers(new TextMessage(getUserId(session) + ":" + msg));} else {sendMessageToUser(to, new TextMessage(getUserId(session) + ":" + msg));}} catch (IOException e) {logger.info("handleTextMessage method error:{}", e);}}@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {if (session.isOpen()) {session.close();}logger.info("连接出错");users.remove(getUserId(session));}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {logger.info("连接已关闭:" + status);users.remove(getUserId(session));}@Overridepublic boolean supportsPartialMessages() {return false;}public void sendMessage(String jsonData) {logger.info("收到客户端消息sendMessage:{}", jsonData);JSONObject msgJson = JSONObject.parseObject(jsonData);String userId = StringUtils.isEmpty(msgJson.getString(CLIENT_ID)) ? "陌生人" : msgJson.getString(CLIENT_ID);String to = msgJson.getString("to");String msg = msgJson.getString("msg");if ("all".equals(to.toLowerCase())) {sendMessageToAllUsers(new TextMessage(userId + ":" + msg));} else {sendMessageToUser(to, new TextMessage(userId + ":" + msg));}}/*** 发送信息给指定用户** @param userId* @param message* @return* @Title: sendMessageToUser* @Description: TODO* @Date 2021/9/14 17:33* @author OnlyMate*/public boolean sendMessageToUser(String userId, TextMessage message) {if (users.get(userId) == null)return false;WebSocketSession session = users.get(userId);logger.info("sendMessage:{} ,msg:{}", session, message.getPayload());if (!session.isOpen()) {logger.info("客户端:{},已断开连接,发送消息失败", userId);return false;}try {session.sendMessage(message);} catch (IOException e) {logger.info("sendMessageToUser method error:{}", e);return false;}return true;}/*** 发送信息给指定多用户** @return* @Title: sendMessageToUser* @Description: TODO* @Date 2021/9/14 17:33* @author OnlyMate*/public boolean sendMessageToUsers(Long businessId, Integer type, String cnContent, String enContent, List<Long> ids, Integer businessType, Integer sendType, String tokenUserId) {if (ids != null && ids.size() > 0) {sysMsgService.sendMessage(businessId, type, cnContent, enContent, ids, businessType, sendType, tokenUserId);for (Long userId : ids) {String userIdstr = userId.toString();if (users.get(userIdstr) == null){continue;}WebSocketSession session = users.get(userIdstr);TextMessage message = new TextMessage(cnContent);logger.info("sendMessage:{} ,msg:{}", session, message.getPayload());if (!session.isOpen()) {logger.info("客户端:{},已断开连接,发送消息失败", userIdstr);continue;}try {session.sendMessage(message);} catch (IOException e) {logger.info("sendMessageToUser method error:{}", e);continue;}}}return true;}/*** 广播信息** @param message* @return* @Title: sendMessageToAllUsers* @Description: TODO* @Date 2021/9/14 17:33* @author OnlyMate*/public boolean sendMessageToAllUsers(TextMessage message) {boolean allSendSuccess = true;Set<String> userIds = users.keySet();WebSocketSession session = null;for (String userId : userIds) {try {session = users.get(userId);if (session.isOpen()) {session.sendMessage(message);} else {logger.info("客户端:{},已断开连接,发送消息失败", userId);}} catch (IOException e) {logger.info("sendMessageToAllUsers method error:{}", e);allSendSuccess = false;}}return allSendSuccess;}/*** 获取用户标识** @param session* @return* @Title: getUserId* @Description: TODO* @Date 2021/9/14 17:33* @author OnlyMate*/private String getUserId(WebSocketSession session) {try {String userId = session.getAttributes().get(CLIENT_ID).toString();return userId;} catch (Exception e) {return null;}}
}

相关文章:

  • 【Effective Web】常见的css居中方式
  • http网络服务器
  • Oracle 打开钱包 ORA-28368: cannot auto-create wallet
  • 响应式网页开发方法与实践
  • C++Primer Plus复习题(第六章)
  • Linux 内核 (十二)进程间通讯 之 消息队列
  • 深入掌握SystemVerilog验证:《SystemVerilog验证 测试平台编写指南》(可下载)
  • 巴中青少年编程:开启未来科技的无限可能
  • Science Online《科学周刊》文献在家如何查找下载
  • 针对k8s集群已经加入集群的服务器进行驱逐
  • OpenSSL新手教程:加密与安全通信基础
  • Hadoop 3.X HA集群部署
  • Vue页面生成PDF后调起浏览器打印
  • 基于Pytorch实现AI写藏头诗
  • JWT工具【工具类】
  • CentOS7简单部署NFS
  • Consul Config 使用Git做版本控制的实现
  • django开发-定时任务的使用
  • Java深入 - 深入理解Java集合
  • java中具有继承关系的类及其对象初始化顺序
  • nodejs实现webservice问题总结
  • PAT A1092
  • V4L2视频输入框架概述
  • webpack4 一点通
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 反思总结然后整装待发
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 浏览器缓存机制分析
  • 什么是Javascript函数节流?
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 使用common-codec进行md5加密
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • #APPINVENTOR学习记录
  • #ubuntu# #git# repository git config --global --add safe.directory
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (十一)c52学习之旅-动态数码管
  • (四) 虚拟摄像头vivi体验
  • (五)IO流之ByteArrayInput/OutputStream
  • (原創) 系統分析和系統設計有什麼差別? (OO)
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .NET 8.0 中有哪些新的变化?
  • .net core 依赖注入的基本用发
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • .Net各种迷惑命名解释
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • @Autowired和@Resource装配
  • @Transactional类内部访问失效原因详解
  • [BUUCTF NewStarCTF 2023 公开赛道] week3 crypto/pwn
  • [C\C++]读入优化【技巧】
  • [c]统计数字
  • [CareerCup] 2.1 Remove Duplicates from Unsorted List 移除无序链表中的重复项
  • [Cloud Networking] Layer Protocol (continue)