SpringBoot快速搭建WebSocket
目录前言pom的依赖编写WebSocketConfig配置类编写WebSocketServerController配置类前端初始化查询用户创建数测试项目目录结构前言前段时间公司做一个代办收件功能,后来要求在菜单右上角显示有多少笔代办件,由于时间充忙就直接查询数据库了,没有实时想前端推送新增的办件。所以在休息的时候来做这件事,你本文写的demo是查询当...
目录
- 前言
- pom的依赖
- 编写WebSocketConfig配置类
- 编写WebSocketServerController配置类
- 前端初始化查询用户创建数
- 测试
项目目录结构

前言
前段时间公司做一个代办收件功能,后来要求在菜单右上角显示有多少笔代办件,由于时间充忙就直接查询数据库了,没有实时想前端推送新增的办件。所以在休息的时候来做这件事,你本文写的demo是查询当前用户的创建数量,大家一定会想到websocket;什么是websocket呢?这里就不一一介绍了,放入一个图给大家看,可以自行查找看下原理。

POM的依赖
SpringBoot2.0对WebSocket的支持简直非常好,直接就有包可以引入。
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
编写WebSocketConfig配置类
package com.example.demo.config;
import com.example.demo.controller.WebSocketServerController;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author LST
* @version 1.0
* @Description: 开启WebSocket支持
* @date 2019-12-21 16:15
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
/**
* (第二种方法)因 SpringBoot WebSocket 对每个客户端连接都会创建一个
WebSocketServer(@ServerEndpoint 注解对应的) 对象,Bean 注入操作会被直接略过,因而手动
注入一个全局变量
* @param userMapper
*/
@Autowired
public void setUserMapper(UserMapper userMapper){
WebSocketServerController.userMapper = userMapper;
}
}
编写WebSocketServerController配置类
因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller
直接@ServerEndpoint("/websocket")@Component启用即可,然后在里面实现@OnOpen,@onClose,@onMessage等方法。
package com.example.demo.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @author LST
* @version 1.0
* @Description: websocker接口
* 实现查询本人创建的用户数
* @date 2019-12-21 16:52
*/
@ServerEndpoint("/websocket/{uid}")
@Component
@Slf4j
public class WebSocketServerController {
//此处是解决无法注入的关键
private static ApplicationContext applicationContext;
public static UserMapper userMapper;
/**
* 第一种方法(在主入口中注入applicationContext)
* @param applicationContext
*//*
public static void setApplicationContext(ApplicationContext applicationContext) {
WebSocketServerController.applicationContext = applicationContext;
}*/
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
*/
private static CopyOnWriteArraySet<WebSocketServerController> webSocketSet = new CopyOnWriteArraySet<WebSocketServerController>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
//接收sid
private String sid = "";
/**
* 连接建立成功调用的方法
* @param session 与某个客户端的连接会话,需要通过它来给客户端发送数据
* @param uid 用户ID
*/
@OnOpen
public void onOpen(Session session,@PathParam("uid") String uid) {
this.session = session;
webSocketSet.add(this); //加入set中
//查找用户是UID创建的个数
QueryWrapper wrapper = new QueryWrapper();
wrapper.like("create_by", uid);
/*userMapper = SpringContextHolder.getBean(UserMapper.class);*/
List<User> userList = userMapper.selectList(wrapper);
//查询
log.info("用户:{},创建的人数为:{}",uid,userList.size()<=0?0:userList.size());
this.sid = uid;
try {
sendMessage(String.valueOf(userList.size()<=0?0:userList.size()));
} catch (IOException e) {
log.error("websocket IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
/* log.info("有一连接关闭!当前在线人数为" + getOnlineCount());*/
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
* @param session 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到来自窗口"+sid+"的信息:"+ message);
//群发消息
for (WebSocketServerController item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发生错误
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
* @param message
* @param uid
* @throws IOException
*/
public static void sendInfo(String message,@PathParam("uid") String uid) throws IOException {
log.info("推送消息到窗口"+uid+",推送内容:"+message);
for (WebSocketServerController item : webSocketSet) {
try {
//这里可以设定只推送给这个sid的,为null则全部推送
if(uid==null) {
item.sendMessage(message);
}else if(item.sid.equals(uid)){
item.sendMessage(message);
}
} catch (IOException e) {
continue;
}
}
}
/* public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServerController.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServerController.onlineCount--;
}*/
}
这里有一个问题,就是集成websocket想用自己写的server时用@Autowired注入会失败,这里我用两种办法解决,任选其一。
第一种就是在WebSocketConfig 配置手动注入。

第二种是在(在主入口中注入applicationContext)。



前端初始化查询用户创建数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>socket</title>
<script src="/static/js/jquery.min.js"></script>
<script type="text/javascript">
var socket;
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
}else{
console.log("您的浏览器支持WebSocket");
//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接
//等同于socket = new WebSocket("ws://localhost:8083/checkcentersys/websocket/20");
socket = new WebSocket("http://127.0.0.1:8090/websocket/543edaa433ee4d94813fd0ec7527f3ea".replace("http","ws"));
//打开事件
socket.onopen = function() {
console.log("Socket 已打开");
//socket.send("这是来自客户端的消息" + location.href + new Date());
};
//获得消息事件
socket.onmessage = function(msg) {
console.log("服务端链接成功,返回信息"+msg.data)
//发现消息进入 开始处理前端触发逻辑
$('#userNum').val(msg.data);
};
//关闭事件
socket.onclose = function() {
console.log("Socket已关闭");
};
//发生了错误事件
socket.onerror = function() {
alert("Socket发生了错误");
//此时可以尝试刷新页面
}
//离开页面时,关闭socket
//jquery1.8中已经被废弃,3.0中已经移除
// $(window).unload(function(){
// socket.close();
//});
}
</script>
<script type="text/javascript">
function ajaxSend() {
var url = "http://127.0.0.1:8090/checkcenter/socket/push/";
$.ajax({
url: url+"543edaa433ee4d94813fd0ec7527f3ea",
type: 'GET',
dataType: 'JSON',
success: function (data) {
console.log(data)
if(data.data != ''){
alert("创建成功"+data.data);
}
},
error: function (msg) {
}
});
}
</script>
</head>
<body>
<div>
创建的人数:<input type="text" id="userNum">
</div>
<div>
<span onclick="ajaxSend('543edaa433ee4d94813fd0ec7527f3ea')" style="color: rgba(20,146,255,1);">创建用户</span>
</div>
</body>
</html>
后端创建用户推送消息给指定用户
package com.example.demo.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.result.RestResponse;
import com.example.demo.result.ResultGenerator;
import com.example.demo.utils.IdGenerate;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.Date;
import java.util.List;
/**
* @author LST
* @version 1.0
* @Description: 消息推送
* @date 2019-12-21 19:11
*/
@RestController
@RequestMapping("/checkcenter")
@Api(value = "CheckCenterController", tags = "socket")
public class CheckCenterController {
@Autowired
private UserMapper userMapper;
/**
* 用户创建和推送数据接口
* @param uid 用户ID
* @return
*/
@ResponseBody
@RequestMapping("/socket/push/{uid}")
public RestResponse pushToWeb(@PathVariable String uid) {
String message ="";
try {
User user = new User();
user.setCreateBy(uid);
user.setCreateDate(new Date());
user.setUpdateBy(uid);
user.setUpdateDate(new Date());
user.setDelFlag("0");
user.setId(IdGenerate.generateId());
if(userMapper.insert(user) > 0){
//查找用户是UID创建的个数
QueryWrapper wrapper = new QueryWrapper();
wrapper.like("create_by", uid);
List<User> userList = userMapper.selectList(wrapper);
message = String.valueOf(userList.size()<=0?0:userList.size());
}
WebSocketServerController.sendInfo(message,uid);
} catch (IOException e) {
e.printStackTrace();
return ResultGenerator.genFailResult(uid+"#"+e.getMessage());
}
return ResultGenerator.genSuccessResult(uid+":"+message);
}
}
测试
1、将项目启动后访问http://127.0.0.1:8090/socket。

2、点击创建用户按钮创建用户,默认是当前用户,用户数据也是模拟的。消息会通过sendInfo发到指定的用户(这个用户已经创建了websocket通信)。

前端显示如图

需要源码的伙伴可前往自行下载,附上下载地址:https://download.csdn.net/download/qq_33612228/12046066
更多推荐

所有评论(0)