1.后端实时推送数据到前端,前端实时更新数据
要满足后端实时推送数据这个要求,就不能使用http方式,因为在http方式下需要浏览器向服务端主动发起请求,然后建立连接,服务端返回数据给浏览器。于是便准备使用websocket方式建立一个接口,浏览器和服务端建立连接后,通过请求这个接口便可以不断的活动服务器推送的数据。
websocket简介
WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息
理解STOMP
https://blog.csdn.net/javazhudong/article/details/120594063
面向消息的简单文本协议。websocket定义了两种传输信息类型: 文本信息和二进制信息。类型虽然被确定,但是他们的传输体是没有规定的。所以,需要用一种简单的文本传输类型来规定传输内容,它可以作为通讯中的文本传输协议,即交互中的高级协议来定义交互信息。 STOMP本身可以支持流类型的网络传输协议: websocket协议和tcp协议。 Stomp还提供了一个stomp.js,用于浏览器客户端使用STOMP消息协议传输的js库。消息协议则是指用于实现消息队列功能时所涉及的协议,支持STOMP协议的消息队列有Apache ActiveMQ、RabbitMQ等很多
2.图表的展示考虑用echarts进行,开箱即用。
因为也是第一次用spring websocket,所以后端部分基本上是参照这篇文章https://www.jianshu.com/p/969da26d5bea进行的,前端展示部分可以看下echarts的官方文档https://echarts.apache.org/handbook/zh/basics/import
1.创建websocket配置类
ps:
AbstractWebSocketMessageBrokerConfigurer 类已经过时,目前的实现方式是 通过implements WebSocketMessageBrokerConfigurer来进行
注解说明:
@Configuration :将配置类添加的spring bean容器中,使配置生效
@EnableWebSocketMessageBroker:开启WebSocket对高级通信协议的支持,例如支持基于代理的STOMP协议
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* ClassName WebSocketStompConfig
* Author tutu
* Date 2022-05-26 11:36:37
* Version 1.0
* Description TODO
**/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
// 设置socket连接
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry
// websocket的服务端地址,后面前端通过这个地址和服务端建立连接,http://localhost:8089/testSocket
.addEndpoint("/testSocket")
//.setAllowedOrigins("*")
//解决跨域问题
.setAllowedOriginPatterns("*")
//开启sockJS模式支持
.withSockJS();
//.setAllowedOrigins("*")
//解决跨域问题
.setAllowedOriginPatterns("*")
//开启sockJS模式支持
.withSockJS();
}
// 设置发布订阅的主题
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/top");
}
}
2.Controller
关于ModelAndView注解的介绍
https://blog.csdn.net/qq_36306340/article/details/78542918
import com.delta.boot.pojo.ProgressEntity;
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.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* ClassName WebsocketController
* Author tutu
* Date 2022-05-26 11:37:34
* Version 1.0
* Description TODO
**/
@Controller
public class WebsocketController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
/**
* 服务端向客户端发送消息
*/
@RequestMapping("/send01")
@ResponseBody
public ModelAndView send2() throws InterruptedException {
// 订阅主题,只有订阅了这个主题的连接才会接收消息
String topic = "/topic/businessUserId/162";
// 消息内容
// 模拟实时向前端发送数据
for (int i = 0; i < 101; i++) {
Thread.sleep(1000);
String message = String.valueOf(i);
simpMessagingTemplate.convertAndSend(topic, message);
}
// 返回原页面
return new ModelAndView("socket");;
}
/**
* 客户端向客户端发送消息
*/
@MessageMapping("/test")
@SendTo("/topic/businessUserId/162")
@ResponseBody
public String call(String msg) {
System.out.println(msg);
return msg;
}
@RequestMapping("/socketPage")
public String socketPage() {
return "socket";
}
}
socket.html
前端通过var socket = new SockJS(“http://localhost:8089/testSocket”);来创建websocket连接,用的js包为sockjs.min.js、stomp.js
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webSockettitle>
head>
<body>
<div>
<h2>Socket 网络实时交互测试h2>
<div>
<button id="connect" onclick="connect();">建立连接button>
<button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接button>
div>
<div id="conversationDiv">
<label>What is your name?label>
<input type="text" id="name" />
<button id="sendName" onclick="sendName();">Sendbutton>
<p id="response">p>
div>
<form action="/send01" method="get">
<input type="submit" value="查看进度">
form>
<div id="main" style="width: 400px;height:50px;">div>
div>
body>
<script src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.min.js">script>
<script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.js">script>
<script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js">script>
<script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js">script>
<script type="text/javascript">
var stompClient = null;
var processBar= $("#progressBar");
var myChart = echarts.init(document.getElementById('main'));
$(function(){
connect();
});
function setConnected(connected) {
$("#connect").attr("disabled", connected);
$("#disconnect").attr("disabled", !connected);
if (connected) {
$("#conversationDiv").show();
}else{
$("#conversationDiv").hide();
}
$("#response").html("");
}
//this line.
function connect() {
var socket = new SockJS("http://localhost:8089/testSocket");
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
// console.log('Connected: ' + frame);
// stompClient.subscribe('/top/test', function(frame){
stompClient.subscribe('/topic/businessUserId/162', function(frame){
//showGreeting(JSON.parse(greeting.body).content);
console.info(frame);
// showGreeting(frame.body);
option = {
xAxis: {
// 隐藏x轴
show:false,
// data: []
min:0,
max:100
},
yAxis: {
//隐藏y轴
show:false,
// 均分
type: "category",
},
series: [
{
type: 'bar',
data: [frame.body],
color:"cyan",
barWidth:10
}
],
label: {
show: true,
position: 'right'
}
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
});
});
}
function sendName() {
var name = $("#name").val();
stompClient.send("/test", {}, name);
}
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function showGreeting(message) {
$("#response").append("" + message + " ");
}
function returnMessage(message){
var completePercent = Math.round(message / 100 * 100);
// + '%';
return completePercent
}
script>
html>
http://localhost:8089/socketPage
算是走通了一个demo,后面要真正漂亮的用起来还需要调整不少地方。
前端要想灵活的用起来是真的不容易
websocket确实是一个很强大的利器
https://www.ucloud.cn/yun/99576.html
WebSocket、SockJs、STOMP三者关系
简而言之,WebSocket 是底层协议,SockJS 是WebSocket 的备选方案,也是底层协议,而 STOMP 是基于 WebSocket(SockJS)的上层协议。
1、HTTP协议解决了 web 浏览器发起请求以及 web 服务器响应请求的细节,假设 HTTP 协议 并不存在,只能使用 TCP 套接字来 编写 web 应用。
2、直接使用 WebSocket(SockJS) 就很类似于 使用 TCP 套接字来编写 web 应用,因为没有高层协议,就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义;
3、同HTTP在TCP 套接字上添加请求-响应模型层一样,STOMP在WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义;