完成效果图:
项目准备提要:
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!-- 热加载 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- google.guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>
<!-- thymeleaf模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocket配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketExporter {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
package com.lazyknow.websocket;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.annotation.PostConstruct;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.lazyknow.entity.user.User;
import com.lazyknow.service.user.UserService;
import com.lazyknow.vo.UserVo;
@ServerEndpoint(value = "/socket/{cmd}/{id}")
@Component
public class WebSocketHandler {
public static Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WebSocketHandler> webSocketSet = new CopyOnWriteArraySet<WebSocketHandler>();
private String uid = "";
private Session session;
// 用于查询用户信息
@Autowired
private UserService userService;
private static UserService userServiceMapper;
@PostConstruct
public void init(){
WebSocketHandler.userServiceMapper = this.userService;
}
/**
* 开启WebSocket请求
*/
@OnOpen
public void onOpen(Session session, @PathParam("cmd") String cmd,@PathParam("id") String id) throws Exception {
this.session = session;
webSocketSet.add(this);
uid = id;
// 可以根据不同类型在选择执行的SQL
if("user".equals(cmd)) {
List<String> skirt = Lists.newArrayList();
List<Integer> nums = Lists.newArrayList();
// 查询前10页数据
for (int i = 0; i < 10; i++) {
PageInfo<User> user = userServiceMapper.findUserInfo(i, 20);
List<User> list = user.getList();
for (User info : list) {
skirt.add(info.getId()+"");
nums.add(info.getAge());
UserVo vo = new UserVo();
vo.setSkirt(skirt);
vo.setNumber(nums);
Thread.sleep(300);
this.sendMessage(JSON.toJSONString(vo));
}
}
}else {
this.onClose();
}
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
logger.info("参数信息:{},uid:{}",message,uid);
//群发消息
for (WebSocketHandler item : webSocketSet) {
try {
item.sendMessage(JSON.toJSONString(message));
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnClose
public void onClose(){
webSocketSet.remove(this);
if (session != null){
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 自定义消息推送、可群发、单发
* */
public static void sendInfo(String message,@PathParam("id") String id) throws IOException {
logger.info("推送消息到前端:{},推送信息:{}",id,message);
for (WebSocketHandler item : webSocketSet) {
try {
//这里可以设定只推送给这个id的,为null则全部推送
if(id==null) {
item.sendMessage(message);
}else if(item.uid.equals(id)){
item.sendMessage(message);
}
} catch (IOException e) {
continue;
}
}
}
@OnError
public void onError(Session session, Throwable error) {
logger.error("连接异常!");
error.printStackTrace();
}
// 发送信息
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
}
前端页面
<!DOCTYPE HTML>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<title>页面展示</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<link rel="stylesheet" type="text/css" href="/static/css/bootstrap.min.css">
<script src="/static/js/jquery-3.2.1.js"></script>
<script src="/static/js/echarts.min.js"></script>
<script type="text/javascript">
var userID="888";
var websocket=null;
$(function(){
connectWebSocket();
})
//建立WebSocket连接
function connectWebSocket(){
console.log("开始...");
//建立webSocket连接
websocket = new WebSocket("ws://127.0.0.1:8888/socket/user/id="+userID);
//打开webSokcet连接时,回调该函数
websocket.onopen = function (data) {
console.info("onpen=>",data);
}
//关闭webSocket连接时,回调该函数
/* websocket.onclose = function () {
//关闭连接
console.log("onclose");
} */
//接收信息
websocket.onmessage = function (event) {
console.info("info==>",event.data);
var val = JSON.parse(event.data);
console.info("json-info==>",val);
var skirt=val.skirt;
var nums=val.number;
var dom = document.getElementById("chartColumn");
var myChart = echarts.init(dom);
var option = null;
option = {
title: {
text: '股票基金走势图'
},
tooltip: {},
xAxis: {
type: 'category',
data: skirt,
axisLabel: {
color: "#333"
}
},
yAxis: {
type: 'value',
axisLabel: {
color: "#333"
}
},
series: [{
//data: [100, 932, 901, 934, 1290, 1330, 1320],
data: nums,
type: 'line',
smooth: true
}]
};
;
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
}
}
//发送消息
function send(){
var postValue={};
postValue.id=userID;
postValue.cmd="测试信息";
websocket.send(JSON.stringify(postValue));
}
//关闭连接
function closeWebSocket(){
if(websocket != null) {
websocket.close();
}
}
</script>
<body>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="chartColumn" style="width: 1500px;height:530px;margin: auto;margin-top:50px; border: 1px solid #ddd;"></div>
</body>
</html>
还有一些Springboot和thymeleaf的常规配置,这里就不全部写下了。