详解spring boot实现websocket
前言
qq这类即时通讯工具多数是以桌面应用的方式存在。在没有websocket出现之前,如果开发一个网页版的即时通讯应用,则需要定时刷新页面或定时调用ajax请求,这无疑会加大服务器的负载和增加了客户端的流量。而websocket的出现,则完美的解决了这些问题。
spring boot对websocket进行了封装,这对实现一个websocket网页即时通讯应用来说,变得非常简单。
一、准备工作
pom.xml引入
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-websocket</artifactid> </dependency>
完整的pom.xml文件代码如下:
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>com.example</groupid> <artifactid>spring-boot-16</artifactid> <version>0.0.1-snapshot</version> <packaging>jar</packaging> <name>spring-boot-16</name> <description>demo project for spring boot</description> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>1.5.3.release</version> <relativepath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceencoding>utf-8</project.build.sourceencoding> <project.reporting.outputencoding>utf-8</project.reporting.outputencoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-thymeleaf</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-websocket</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-devtools</artifactid> <scope>runtime</scope> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> </plugins> </build> </project>
二、代码编写
1.创建名为“websocketconfig.java”的类来配置websocket,并继承抽象类“abstractwebsocketmessagebrokerconfigurer”
此类声明“@enablewebsocketmessagebroker”的注解
package com.example; import org.springframework.context.annotation.configuration; import org.springframework.messaging.simp.config.messagebrokerregistry; import org.springframework.web.socket.config.annotation.abstractwebsocketmessagebrokerconfigurer; import org.springframework.web.socket.config.annotation.enablewebsocketmessagebroker; import org.springframework.web.socket.config.annotation.stompendpointregistry; @configuration @enablewebsocketmessagebroker public class websocketconfig extends abstractwebsocketmessagebrokerconfigurer { @override public void configuremessagebroker(messagebrokerregistry config) { config.enablesimplebroker("/topic"); config.setapplicationdestinationprefixes("/app"); } @override public void registerstompendpoints(stompendpointregistry registry) { registry.addendpoint("/my-websocket").withsockjs(); } }
这里配置了以“/app”开头的websocket请求url。和名为“my-websocket”的endpoint(端点)
2.编写一个dto类来承载消息:
package com.example; public class socketmessage { public string message; public string date; }
3.创建app.java类,用于启用spring boot和用于接收、发送消息的控制器。
package com.example; import java.text.dateformat; import java.text.simpledateformat; import java.util.date; import org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.messaging.handler.annotation.messagemapping; import org.springframework.messaging.handler.annotation.sendto; import org.springframework.messaging.simp.simpmessagingtemplate; import org.springframework.scheduling.annotation.enablescheduling; import org.springframework.scheduling.annotation.scheduled; import org.springframework.stereotype.controller; import org.springframework.web.bind.annotation.getmapping; @controller @enablescheduling @springbootapplication public class app { public static void main(string[] args) { springapplication.run(app.class, args); } @autowired private simpmessagingtemplate messagingtemplate; @getmapping("/") public string index() { return "index"; } @messagemapping("/send") @sendto("/topic/send") public socketmessage send(socketmessage message) throws exception { dateformat df = new simpledateformat("yyyy-mm-dd hh:mm:ss"); message.date = df.format(new date()); return message; } @scheduled(fixedrate = 1000) @sendto("/topic/callback") public object callback() throws exception { // 发现消息 dateformat df = new simpledateformat("yyyy-mm-dd hh:mm:ss"); messagingtemplate.convertandsend("/topic/callback", df.format(new date())); return "callback"; } }
“send”方法用于接收客户端发送过来的websocket请求。
@enablescheduling注解为:启用spring boot的定时任务,这与“callback”方法相呼应,用于每隔1秒推送服务器端的时间。
4.在“resources/templates”目录下创建index.html文件:
<!doctype html> <html> <head> <title>玩转spring boot——websocket</title> <script src="//cdn.bootcss.com/angular.js/1.5.6/angular.min.js"></script> <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script> <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script> <script type="text/javascript"> /*<![cdata[*/ var stompclient = null; var app = angular.module('app', []); app.controller('maincontroller', function($rootscope, $scope, $http) { $scope.data = { //连接状态 connected : false, //消息 message : '', rows : [] }; //连接 $scope.connect = function() { var socket = new sockjs('/my-websocket'); stompclient = stomp.over(socket); stompclient.connect({}, function(frame) { // 注册发送消息 stompclient.subscribe('/topic/send', function(msg) { $scope.data.rows.push(json.parse(msg.body)); $scope.data.connected = true; $scope.$apply(); }); // 注册推送时间回调 stompclient.subscribe('/topic/callback', function(r) { $scope.data.time = '当前服务器时间:' + r.body; $scope.data.connected = true; $scope.$apply(); }); $scope.data.connected = true; $scope.$apply(); }); }; $scope.disconnect = function() { if (stompclient != null) { stompclient.disconnect(); } $scope.data.connected = false; } $scope.send = function() { stompclient.send("/app/send", {}, json.stringify({ 'message' : $scope.data.message })); } }); /*]]>*/ </script> </head> <body ng-app="app" ng-controller="maincontroller"> <h2>玩转spring boot——websocket</h2> <h4> 出处:刘冬博客 <a href="http://www.cnblogs.com/goodhelper" rel="external nofollow" >http://www.cnblogs.com/goodhelper</a> </h4> <label>websocket连接状态:</label> <button type="button" ng-disabled="data.connected" ng-click="connect()">连接</button> <button type="button" ng-click="disconnect()" ng-disabled="!data.connected">断开</button> <br /> <br /> <div ng-show="data.connected"> <label>{{data.time}}</label> <br /> <br /> <input type="text" ng-model="data.message" placeholder="请输入内容..." /> <button ng-click="send()" type="button">发送</button> <br /> <br /> 消息列表: <br /> <table> <thead> <tr> <th>内容</th> <th>时间</th> </tr> </thead> <tbody> <tr ng-repeat="row in data.rows"> <td>{{row.message}}</td> <td>{{row.date}}</td> </tr> </tbody> </table> </div> </body> </html>
除了引用angular.js的cdn文件外,还需要引用sockjs和stomp。
完整的项目结构,如下图所示:
三、运行效果
点击“连接”按钮,出现发送消息的输入框。并接收到服务器端的时间推送。
输入发送内容并点击“发送”按钮后,页面显示出刚才发送的消息。
点击“断开”按钮,则服务器端不会再推送消息。
总结
在开发一个基于web的即时通讯应用的过程中,我们还需考虑session的机制。
还需要一个集合来承载当前的在线用户,并做一个定时任务,其目的是用轮询的方式定时处理在线用户的状态,有哪些用户在线,又有哪些用户离线。
参考:
代码地址:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
Spring Boot 数据校验@Valid+统一异常处理的实现
-
详解spring boot实现websocket
-
Spring boot搭建web应用集成thymeleaf模板实现登陆
-
详解如何在spring boot中使用spring security防止CSRF攻击
-
Spring Boot中实现定时任务应用实践
-
Spring-boot结合Shrio实现JWT的方法
-
spring boot+thymeleaf+bootstrap实现后台管理系统界面
-
详解Spring AOP 实现“切面式”valid校验
-
Spring boot中PropertySource注解的使用方法详解
-
详解如何在低版本的Spring中快速实现类似自动配置的功能