springBoot集成WebSocket,实现后台向前端推送信息
- 先在搭建好的springBoot项目中引入对应的websocket包。地址如下。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 这里集成下thymeleaf模板,在配置文件中添加thymeleaf配置信息。
thymeleaf: cache: false prefix: classpath:/templates/ suffix: .html mode: HTML5 encoding: UTF-8 content-type: text/html
- 自定义WebsocketServer,使用底层的websocket方法,编写对应的onOpen()、onClose()、onMessage()、onError()方法,
先添加webSocketConfig配置类。
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
- 在Controller层创建WebSocketServer类,在里面编写逻辑代码。
package com.dehui.info.surveyingmanagementback.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.dehui.info.surveyingmanagementback.utils.StringUtils; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; 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.concurrent.ConcurrentHashMap; @ServerEndpoint("/imserver/{userId}") @Component public class WebSocketServer { static Log log= LogFactory.getLog(WebSocketServer.class); private static int onLineCount=0; /** * concurrent包的线程安全Set,用来存放每个客户端对应的wwebsocket对象. */ private static ConcurrentHashMap<String,WebSocketServer> webSocketMap=new ConcurrentHashMap<>(); /** * 与某个客户端的连接会话,需要通过它来给客户端发送数据。 */ private Session session; //创建userId private String userId=""; //连接建立成功调用的方法 @OnOpen public void onOpen(Session session, @PathParam("userId")String userId){ this.session=session; this.userId=userId; if(webSocketMap.containsKey(userId)){ webSocketMap.remove(userId);//如果重复就将以前的删掉 webSocketMap.put(userId,this); //加入Set }else{ webSocketMap.put(userId,this); //加入set addOnlineCount(); //调用在线人数增加方法 } log.info("用户连接:"+userId+",当前在线人数为:"+ getOnlineCount()); try{ //将在线人数群发给所有在线用户 for(String key:webSocketMap.keySet()){ JSONObject jsonObject1= new JSONObject(); jsonObject1.put("code",200); jsonObject1.put("type",1); jsonObject1.put("data",getOnlineCount()); webSocketMap.get(key).sendMessage(jsonObject1.toJSONString()); } }catch (IOException e){ log.error("用户:"+userId+",网络异常!!!"); } } /** * 关闭连接方法 */ @OnClose public void onClose(){ if(webSocketMap.containsKey(userId)){ webSocketMap.remove(userId); //从set中删除 subOnlineCount(); } log.info("用户退出:"+userId+",当前在线人数为:"+getOnlineCount()); } /** * 收到客户端消息后调用的方法 */ @OnMessage public void onMessage(String message,Session session){ log.info("用户消息:"+userId+",报文"+message); //可以进行群发消息,信息也可以保存在数据库中,或者redis中 System.out.println("判断条件"+StringUtils.isNotBlank(message)); if(StringUtils.isNotBlank(message)){ try{ //解析发送的报文 JSONObject jsonObject= JSON.parseObject(message); //追加发送人防止串改 jsonObject.put("fromUserId",this.userId); jsonObject.put("type",2); String toUserId=jsonObject.getString("toUserId"); //向指定的userId用户发送消息 if(StringUtils.isNotBlank(toUserId)&&webSocketMap.containsKey(toUserId)){ webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString()); }else{ log.error("请求的userId:"+toUserId+"不在该服务器上"); //如果服务器上没有可以存在数据库中 } }catch (Exception e){ e.printStackTrace(); } } } /** * 连接报错 */ @OnError public void onErrot(Session session,Throwable error){ log.error("用户错误:"+this.userId+",原因"+error.getMessage()); error.printStackTrace(); } /** * 服务主动推送消息 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 发送自定义信息 */ public static void sendInfo(String message,@PathParam("userId")String userId) throws IOException { log.info("发送消息到:"+userId+",报文:"+message); if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){ webSocketMap.get(userId).sendMessage(message); }else { log.error("用户:"+userId+",不在线!!"); } } public static synchronized int getOnlineCount(){ return onLineCount; } public static synchronized void addOnlineCount(){ WebSocketServer.onLineCount++; } public static synchronized void subOnlineCount(){ WebSocketServer.onLineCount--; } }
5.然后再创建WebSocketTestController层,实现登陆访问时跳转到对应的页面。
@Controller
public class WebSocketTestController {
@GetMapping("page")
public ModelAndView page(){
return new ModelAndView("page");
}
}
6.创建page页面,测试websocket。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>websocket通讯</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var socket;
function openSocket() {
if(typeof(WebSocket)=="undefined"){
console.log("您的浏览器不支持websocket");
}else{
console.log("您的浏览器支持websocket");
//与websocket服务端建立连接
var socketUrl="ws://localhost:8091/imserver/"+$("#userId").val();
if(socket!=null){
socket.close();
socket=null
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen=function () {
console.log("websocket已打开");
};
//获得消息事件
socket.onmessage=function (msg) {
let data=JSON.parse(msg.data)
if(data.type===1){
document.getElementById("msg_data").innerHTML = "当前在线人数:"+ data.data;
}else if(data.type===2){
$("#info").append('<div >用户'+data.fromUserId+':'+data.contentText+'</div>');
}
}
//关闭事件
socket.onclose=function () {
console.log("websocket已关闭");
}
//发生错误
socket.onerror=function () {
console.log("websocket发生了错误")
}
}
}
function sendMessage() {
if(typeof(WebSocket)=="undefined"){
console.log("您的浏览器不支持websocket")
}else{
console.log("您的浏览器支持websocket")
console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
socket.send('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
}
}
</script>
<div><span>用户id:</span><input id="userId" name="userId" type="text" value="10"><span>连接-></span><span>聊天对象id:</span><input id="toUserId" name="toUserId" type="text" value="20"></div>
<p>【信息输入框】:<div><input id="contentText" name="contentText" type="text" value="hello friend"><div><button onclick="sendMessage()">发送消息</button></div></div>
<p>【操作】:<div><button onclick="openSocket()">开启socket</button></div>
<p><div id="msg_data"></div></p>
<p>【接收信息面板】:<div id="info"></div></p>
</body>
</html>