SpringBoot 实现WebSocket进行消息发送(适用于SpringMVC)
来源:互联网 发布:求免费数据恢复软件 编辑:程序博客网 时间:2024/06/05 17:27
Spring框架中自带了WebSocket的jar包,利用它可以实现与H5中WebSocket进行对接,实现交互。使用Spring WebSocket并不复杂,下面一起来看下怎么实现吧(注:本例子是通过SpringBoot构建的项目,除了项目的启动代码配置不一样外,WebSocket的配置代码可在SpringMVC上无缝使用)。
这个例子会通过模拟登陆,在Session中保存用户信息,然后进行WebSocket通信时,从Session中将用户信息取出来,并将信息转发给指定用户。
一、所需POM配置
SpringMVC配置:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.3.10.RELEASE</version></dependency>
通过SpringMVC来构建项目的话,除了一些基本的Spring jar包之外,只需要添加上面这个jar包即可。
SpringBoot配置:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.6.RELEASE</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> </dependency> </dependencies>
使用SpringBoot来构建项目的话,需要使用上面这些jar包,上面的jar包包含了SpringBoot的配置、WebSocket的配置。
二、代码实现
启动类
@SpringBootApplication@Controller@ComponentScan(basePackages={"com.test.spring.boot"}) //自定义自动扫描public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
上面代码是SpringBoot的一个项目启动类,执行main方法就可以启动服务,相关配置在这篇文章里不是重点,就不写出来了,感兴趣可以看这篇文章:SpringBoot+Thymeleaf整合开发实例。
这里需要注意的是 @ComponentScan(basePackages={"com.test.spring.boot"})
,代表了扫描的包名。
访问Controller
@Controller@RequestMapping("/")public class HelloController { private static final String SESSION_USER = "user"; @Autowired private MyWebSocketHandler myWebSocketHandler; // 访问跳转到websocket.html页面 @RequestMapping("/socket") public String websocket() { return "websocket"; } // 模拟登陆操作,将用户信息存入Session @RequestMapping("/login") public @ResponseBody String login(UserBean userBean, HttpServletRequest request) { System.out.println("========================== 开始登录 ==================="); System.out.println("userId="+userBean.getId()); System.out.println("userId="+userBean.getUsername()); System.out.println("userId="+userBean.getPhone()); request.getSession().setAttribute(SESSION_USER, userBean); System.out.println("========================== 登录成功 ==================="); return "success"; } // 普通操作,触发WebSocket通信 @RequestMapping("/send/message") public @ResponseBody String sendMessage(HttpServletRequest request) { UserBean userBean = (UserBean) request.getSession().getAttribute(SESSION_USER); boolean isSuccess = myWebSocketHandler.sendMessageToUser(userBean.getId(), "测试发送消息"); System.out.println(isSuccess); return "message"; }}
注册WebSocket处理类
@Configuration@EnableWebSocketpublic class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new MyWebSocketHandler(), "/websocket").addInterceptors(new WebSocketInterceptor()); }}
这是一个WebSocket配置类,实现接口来配置Websocket请求的路径和拦截器。 这里是将请求路径 /websocket
绑定到MyWebSocketHandler()
类,并设置一个拦截器WebSocketInterceptor()
,
注解不要忘掉,否则无法注册这个配置类。
WebSocket拦截器
/** * WebSocket 拦截器,用于将用户信息从session中存入map,方便后面websocket请求时从map中找到指定的用户session信息 * @author Administrator * */public class WebSocketInterceptor implements HandshakeInterceptor { private static final String SESSION_USER = "user"; @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> map) throws Exception { if (request instanceof ServletServerHttpRequest) { ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request; HttpSession session = serverHttpRequest.getServletRequest().getSession(); if (session != null) { map.put(SESSION_USER, session.getAttribute(SESSION_USER)); } } return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { }}
这个拦截器的作用是在请求WebSocket时,将Session中的用户信息转存到map中,方便后面WebSocket请求处理时,能够从map中获取到用户信息。
WebSocket具体请求处理类
在贴代码之前,我们先来看下WebSocket具体请求处理类中的那些方法可以重写,他们是什么含义:
在
afterConnectionEstablished
连接建立成功之后,记录用户的连接标识,便于后面发信息,这里我是记录将id记录在Map集合中。在
handleTextMessage
中可以对H5 Websocket的send方法进行处理。handleTransportError
连接出错处理,主要是关闭出错会话的连接,和删除在Map集合中的记录。afterConnectionClosed
连接已关闭,移除在Map集合中的记录。
@Componentpublic class MyWebSocketHandler extends TextWebSocketHandler { //在线用户列表 private static final Map<Integer, WebSocketSession> users = new HashMap<Integer, WebSocketSession>(); //用户标识 private static final String SESSION_USER = "user"; /** * 连接已关闭,移除在Map集合中的记录 */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { users.remove(getUserId(session)); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { if (session.isOpen()) { session.close(); } System.out.println("连接出错"); users.remove(getUserId(session)); } /** * 连接建立成功之后,记录用户的连接标识,便于后面发信息 */ @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { System.out.println("成功建立连接"); Integer userId = getUserId(session); System.out.println(userId); if (userId != null) { users.put(userId, session); session.sendMessage(new TextMessage("成功建立socket连接")); System.out.println(userId); System.out.println(session); } } /** * 处理收到的websocket信息 */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { } /** * 发送信息给指定用户 * @param clientId * @param message * @return */ public boolean sendMessageToUser(Integer clientId, String message) { if (users.get(clientId) == null) { return false; } WebSocketSession session = users.get(clientId); System.out.println("sendMessage:" + session); if (!session.isOpen()) { return false; } try { int count = 1; TextMessage textMessage = null; String newMessage = ""; // 循环向客户端发送数据 while(true) { newMessage = message + String.valueOf(count); textMessage = new TextMessage(newMessage); session.sendMessage(textMessage); Thread.sleep(5000); newMessage = ""; } } catch (IOException e) { e.printStackTrace(); return false; } catch (InterruptedException e) { e.printStackTrace(); return false; } } /** * 广播信息 * @param message * @return */ public boolean sendMessageToAllUsers(TextMessage message) { boolean allSendSuccess = true; Set<Integer> clientIds = users.keySet(); WebSocketSession session = null; for (Integer clientId : clientIds) { try { session = users.get(clientId); if (session.isOpen()) { session.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); allSendSuccess = false; } } return allSendSuccess; } /** * 获取用户标识 * @param session * @return */ private Integer getUserId(WebSocketSession session) { try { UserBean userBean = (UserBean) session.getAttributes().get(SESSION_USER); return userBean.getId(); } catch (Exception e) { return null; } }}
前端实现
<!DOCTYPE HTML><html xmlns:th="http://www.thymeleaf.org"><head><title>WebSocket Test</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="stylesheet" th:href="@{/css/main.css}"/><script th:src="@{/js/jQuery-2.1.4.min.js}" type="text/javascript"></script></head><body> <div> <input type="button" id="btn_test" value="点击获取数据"/> </div> <div> <div id="test_1"> </div> </div></body><script type="text/javascript">//<![CDATA[ $(document).ready(function() { var websocket = null; var sendData = {"id": 1, "username": "tanjin", "phone": "1888221322122"}; // 模拟登陆 $.post("login", sendData, function(data) { // 初始化一个WebSocket连接 websocket = new WebSocket("ws://localhost:8082/websocket"); websocket.onerror = function(event) {onError(event);}; websocket.onopen = function(event) {onOpen(event);}; // websocket接收的信息会通过这个回调方法返回给前端 websocket.onmessage = function(event) {onMessage(event);}; }) // 打印收到的websocket返回信息 function onMessage(event) { $("#test_1").append("<label class='navbar-label'>" + event.data + "</label>").append("</br>"); $("#test_1").scrollTop( $("#test_1")[0].scrollHeight); } // 开启websocket请求回调处理 function onOpen(event) { $("#test_1").empty(); var label = $("<label>").html("开始执行...."); $("#test_1").append(label).append("<br>").append("<br>"); } //报错处理回调函数 function onError(event) { alert(event.data); } //点击页面上的一个按钮,通过一个普通方法来开始一个websocket请求 $("#btn_test").click(function() { $.post("send/message", null, function() {}) })})//]]></script></html>
//<![CDATA[
这个标签在这里是由于thymeleaf的语法限制使用的,如果是JSP则不需要。
处理结果
- SpringBoot 实现WebSocket进行消息发送(适用于SpringMVC)
- SpringBoot学习-(十四)SpringBoot中建立WebSocket连接(STOMP实现发送消息给指定用户)
- SpringBoot中的WebSocket点对点发送消息
- springboot+websocket+sockjs进行消息推送
- SpringBoot-WebSocket广播消息+单点消息(指定用户发送消息)
- SpringBoot webSocket 发送广播、点对点消息,Android接收
- 使用SpringBoot快速搭建WebSocket实现消息推送
- SpringBoot 整合 Websocket 实现消息推送框架的设计笔记
- spring-websocket 配置 websocket发送消息(群发)
- SpringBoot 快速实现WebSocket
- spring配置websocket并实现群发/单独发送消息
- spring配置websocket并实现群发/单独发送消息
- spring配置websocket并实现群发/单独发送消息
- springmvc(18)使用WebSocket 和 STOMP 实现消息功能
- SpringMVC整合websocket实现消息推送及触发
- springmvc(18)使用WebSocket 和 STOMP 实现消息功能
- SpringMVC整合websocket实现消息推送及触发
- springboot整合websocket实现一对一消息推送和广播消息推送
- 莫烦PyTorch学习笔记(三)——分类
- C++重难点知识点总结
- DSS 代码分析【TaskThread与Task】
- 常用的排序算法
- 顺序栈的简单操作
- SpringBoot 实现WebSocket进行消息发送(适用于SpringMVC)
- Netty框架服务端主动向客户端通信
- 简单的弹窗应用(二)--AlertDialog
- 数据结构 — 选择排序
- 第十二周项目一Dijkstra算法的验证
- 【20171120】C语言每日一练
- 来一波面试题
- DSS 代码分析【TimeoutTask】
- MyEclipse8.5汉化方法