在自己整合websocket时踩了一些坑,给大家分享出来希望可以帮到有需要的小伙伴,我的测试案例中有什么问题请指出,大家共同学习,现在开始上代码;
第一步,添加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>zenithink-demo</groupId> <artifactId>zenithink-demo</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <com.alibaba.dubbo.version>2.5.3</com.alibaba.dubbo.version> <dubbo-spring-boot>1.0.0</dubbo-spring-boot> <org.apache.zookeeper.version>3.4.6</org.apache.zookeeper.version> <com.github.sgroschupf.zkclient.version>0.1</com.github.sgroschupf.zkclient.version> </properties> <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>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> </dependency> <!--Http client组件--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.5</version> </dependency> <!--json对象依赖--> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> <!--字符串工具依赖--> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <!--日志依赖--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.6</version> </dependency> <!--spring data mongodb--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <!--引入websocket依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>lombok</groupId> <artifactId>lombok</artifactId> <version>1.0</version> </dependency> </dependencies> </project>
第二步,添加所需封装实体类
public class SocketMessage { public String message; public String date; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } }
第三步,websochet配置对象
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; /** * websocket设置 */ @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(); } }
第四步,添加前端控制器
import com.demo.entity.SocketMessage; import org.springframework.beans.factory.annotation.Autowired; 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.Scheduled; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; /** * websocket测试前端控制器 */ @Controller public class App { /** * websochet消息发送对象 */ @Autowired private SimpMessagingTemplate messagingTemplate; /** * 跳转到测试页面 * @return */ @GetMapping("/") public String index() { return "test01"; } //测试页面显示后台消息推送次数 private int count=0; //接收浏览器消息路径设置 @MessageMapping("/send") //服务端向浏览器推送地址设置 @SendTo("/topic/send") public SocketMessage send(SocketMessage message) throws Exception { DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); message.date = "浏览器消息"; return message; } //由后台发送到浏览器服务 @SendTo("/topic/callback") //定时5秒给页面推一次数据 @Scheduled(cron="0/5 * * * * ?") public Object callback() throws Exception { DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("推送消息了"+df.format(new Date())); //向页面这个地址推送消息 messagingTemplate.convertAndSend("/topic/callback","客户端消息"+count ); count++; return null; } }
第五步,添加测试页面
<!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"> var stompClient = null; var app = angular.module('app', []); app.controller('MainController', function($rootScope, $scope, $http) { $scope.data = { //连接状态 connected : false, //消息 message : '', rows : [] }; //连接 $scope.connect = function() { //特别注意链接的IP和浏览器访问地址必须保持一致,不然就会出现链接不上的问题 var socket = new SockJS('http://10.0.0.253:1214/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"> <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>
第六步,页面效果展示
总结:
到这就算大功告成,不过链接后台服务的时候折腾了很久,最终发现,通过sockjs链接的时候不加IP端口"/my-websocket"链接是可以的,如果改成"127.0.0.1:1214/my-websocket"这样就链接不成功,后来改成"http://127.0.0.1:1214/my-websocket"又可以,通过"ws://127.0.0.1:1214/my-websocket"这样也是链接不通的,总之,浏览器访问地址和页面链接后台地址保持一致就可以了!