引入对应maven依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> 复制代码
注入ServerEndpointExporter
@Configuration
public class WebSocketConfig {
/**
* 服务器节点
*
* 如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
复制代码 代码实现webSocket,具体的实现还要看业务需求,GuavaCacheUtil是我本地的一个guava的缓存工具类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.renren.common.exception.RRException;
import io.renren.common.utils.GuavaCacheUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Auther zxl
* @Date 2020/3/8 16:49
* @Description
**/
@ServerEndpoint("/websocket/{sToken}")
@Component
@Slf4j
public class WebSocketServer {
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
/**
* 管理员聊天用户数目
*/
private static ConcurrentHashMap<String,Integer> adminUserCountMap = new ConcurrentHashMap<>();
/**
* 在线的管理员
*/
private static AtomicInteger adminCount = new AtomicInteger(0);
/**
* 在线的用户
*/
private static AtomicInteger userCount = new AtomicInteger(0);
private Session session;
private String sToken;
private static final String SYS_STOKEN = "SYS";
/**
* 连接建立成功
* @param session
* @param sToken
*/
@OnOpen
public void onOpen(Session session,@PathParam("sToken") String sToken){
if (sToken.endsWith("000")){
// 测试使用
GuavaCacheUtil.put(sToken,0);
}
if(GuavaCacheUtil.getIfPresent(sToken) == null){
// sToken无效或失效
return;
}
this.session = session;
this.sToken = sToken;
if (webSocketMap.containsKey(sToken)){
webSocketMap.remove(sToken);
}
webSocketMap.put(sToken,this);
if (sToken.startsWith("ADMIN")){
adminCount.incrementAndGet();
if (adminUserCountMap.containsKey(sToken)){
adminUserCountMap.remove(sToken);
}
adminUserCountMap.put(sToken,0);
}else if (sToken.startsWith("USER")){
userCount.incrementAndGet();
// 分配管理员
String adminSToken = getAdmin();
// 通知用户管理员sToken
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg",adminSToken);
jsonObject.put("toUser",sToken);
jsonObject.put("fromUser",SYS_STOKEN);
jsonObject.put("code",1);
this.sendMessage(jsonObject.toJSONString());
// 管理员用户数+1
adminUserCountMap.put(adminSToken,adminUserCountMap.get(adminSToken) + 1);
}
}
@OnClose
public void onClose(){
if (webSocketMap.containsKey(sToken)){
webSocketMap.remove(sToken);
}
if (sToken.startsWith("ADMIN")){
adminCount.decrementAndGet();
}else if (sToken.startsWith("USER")){
userCount.decrementAndGet();
}
GuavaCacheUtil.remove(sToken);
}
@OnMessage
public void onMessage(String message, Session session){
JSONObject jsonObject = JSON.parseObject(message);
String toUser = jsonObject.getString("toUser");
if (StringUtils.isNotBlank(toUser)&&webSocketMap.containsKey(toUser)){
jsonObject.put("fromUser",sToken);
jsonObject.put("code",0);
webSocketMap.get(toUser).sendMessage(jsonObject.toJSONString());
}else {
jsonObject.remove("toUser");
jsonObject.remove("msg");
jsonObject.put("toUser",sToken);
jsonObject.put("fromUser",SYS_STOKEN);
jsonObject.put("code",404);
jsonObject.put("msg","对方已下线");
webSocketMap.get(sToken).sendMessage(jsonObject.toJSONString());
}
log.info("sToken: {},message:{}",sToken,jsonObject.toJSONString());
}
@OnError
public void onError(Session session, Throwable error) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("toUser",sToken);
jsonObject.put("fromUser",SYS_STOKEN);
jsonObject.put("code",500);
jsonObject.put("msg","系统异常");
webSocketMap.get(sToken).sendMessage(jsonObject.toJSONString());
log.error("用户错误:"+sToken+",原因:"+error.getMessage());
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message){
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("socket error: {}",e);
}
log.info("socket send msg : {}",message);
}
/**
* 获取聊天用户最少的管理员sToken
* @return
*/
private String getAdmin(){
if (adminUserCountMap.size() == 0){
return null;
}
String sToken = "";
int count = 0;
Iterator<Map.Entry<String,Integer>> iterator = adminUserCountMap.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String,Integer> m = iterator.next();
if (StringUtils.isBlank(sToken)){
sToken = m.getKey();
count = m.getValue();
}else if (m.getValue() < count){
sToken = m.getKey();
count = m.getValue();
}
}
return sToken;
}
/**
* 自定义发送游戏
* @param msg
* @param sToken
*/
public static void sendMsg(String msg,String sToken){
if (StringUtils.isNotBlank(sToken) && webSocketMap.containsKey(sToken)){
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg",msg);
jsonObject.put("toUser",sToken);
jsonObject.put("fromUser",SYS_STOKEN);
jsonObject.put("code",0);
webSocketMap.get(sToken).sendMessage(jsonObject.toJSONString());
}else {
throw new RRException("用户已下线");
}
}}
复制代码 开放一个http接口用于推送消息,R是我自定义的全局返回对象
/**
* @Auther zxl
* @Date 2020/3/8 19:11
* @Description
**/
@RestController
public class ScoketController {
@RequestMapping("/push/{sToken}")
public R pushToWeb(@RequestParam String message, @PathVariable String sToken) {
WebSocketServer.sendMsg(message,sToken);
return R.ok();
}
}
复制代码 管理员页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>管理员scoket</title>
</head>
<body id="body">
<h1>当前用户:<span id="userCount"></span></h1>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var socket;
var sToken;
var user_sToken = []
var userCount = 0
$(function(){
getStoken();
initSocket();
$("#userCount").html(0)
})
// 获取sToken
function getStoken(){
// 模拟sToken,测试使用管理员sToken(ADMIN开头,000结尾),真实环境掉接口获取sToken
sToken = "ADMIN1000"
}
// 初始化socket
function initSocket(){
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
alert("您的浏览器不支持WebSocket");
}else{
console.log("您的浏览器支持WebSocket");
var socketUrl="http://localhost:8082/bocai-api/websocket/"+sToken;
socketUrl=socketUrl.replace("https","ws").replace("http","ws");
console.log(socketUrl);
if(socket!=null){
socket.close();
socket=null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function() {
console.log("websocket已打开");
alert("socket打开成功")
};
//获得消息事件
socket.onmessage = function(msg) {
console.log(msg.data);
var data = JSON.parse(msg.data)
if(data.code != 0){
alert(data.msg)
return;
}
console.log(data)
console.log(user_sToken)
if($.inArray(data.fromUser,user_sToken) >= 0){
$("#"+data.fromUser).append('<tr><td>'+data.msg+'</td><td><td></tr>')
console.log('table添加新记录')
}else {
// 新用户消息
console.log('创建新table')
$("#body").append('<table style="margin-top:10px" border="2" bordercolor="black" width="500" cellspacing="0" cellpadding="5" id='+data.fromUser+'></table>')
$("#"+data.fromUser).append('<tr><td>通信用户:'+data.userName+data.mobile+'</td><td>用户sToken:'+data.fromUser+'</td></tr>')
$("#"+data.fromUser).append('<tr><td colspan="2"><input id=ip'+data.fromUser+' type="text"><button data-st='+data.fromUser+' onclick="sendMsg(this)">发送</button></td></tr>')
$("#"+data.fromUser).append('<tr><td>用户</td><td>我</td></tr>')
$("#"+data.fromUser).append('<tr><td>'+data.msg+'</td><td><td></tr>')
user_sToken.push(data.fromUser)
userCount++
$("#userCount").html(userCount)
}
};
//关闭事件
socket.onclose = function() {
console.log("websocket已关闭");
};
//发生了错误事件
socket.onerror = function() {
console.log("websocket发生了错误");
}
}
}
function sendMsg(e){
var user_st = e.getAttribute("data-st")
console.log(user_st)
console.log($("#ip"+user_st).val())
var data = {msg:$("#ip"+user_st).val(),toUser:user_st,fromUser:sToken}
sendMessage(JSON.stringify(data))
$("#"+user_st).append('<tr><td></td><td>'+$("#ip"+user_st).val()+'</td></tr>')
}
function sendMessage(data) {
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
}else {
console.log("您的浏览器支持WebSocket");
console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
socket.send(data);
}
}
</script>
</html>
复制代码 用户页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>用户scoket</title>
</head>
<body id="body">
<h1>当前用户:<span id="userName"></span></h1>
<table border="2" bordercolor="black" width="300" cellspacing="0" cellpadding="5" id="msgTable">
<tr>
<td colspan="2">
<input id="msg" type="text"><button onclick="sendMsg()">发送</button>
</td>
</tr>
<tr>
<td>客服</td>
<td>我</td>
</tr>
</table>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var socket;
var sToken;
var admin_sToken;
var userName = '小明'
var mobile = '18539442736'
$(function(){
getStoken();
initSocket();
$("#userName").html(userName+mobile)
})
// 获取sToken
function getStoken(){
// 模拟sToken,测试使用管理员sToken(USER开头,000结尾),真实环境掉接口获取sToken
sToken = "USER2000"
}
// 初始化socket
function initSocket(){
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
alert("您的浏览器不支持WebSocket");
}else{
console.log("您的浏览器支持WebSocket");
var socketUrl="http://39.105.129.210:8082/bocai-api/websocket/"+sToken;
socketUrl=socketUrl.replace("https","ws").replace("http","ws");
console.log(socketUrl);
if(socket!=null){
socket.close();
socket=null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function() {
console.log("websocket已打开");
alert("socket打开成功")
};
//获得消息事件
socket.onmessage = function(msg) {
console.log(msg.data);
var data = JSON.parse(msg.data)
if(data.code == 1){
admin_sToken = data.msg
}else if(data.code == 0){
$("#msgTable").append('<tr><td>'+data.msg+'</td><td></td></tr>')
console.log('table添加新记录')
}else {
alert(data.msg)
}
};
//关闭事件
socket.onclose = function() {
console.log("websocket已关闭");
};
//发生了错误事件
socket.onerror = function() {
console.log("websocket发生了错误");
}
}
}
function sendMsg(){
var msg = $("#msg").val()
var data = {userName:userName,mobile:mobile,msg:msg,toUser:admin_sToken,fromUser:sToken}
sendMessage(JSON.stringify(data))
$("#msgTable").append('<tr><td></td><td>'+msg+'</td></tr>')
}
function sendMessage(data) {
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
}else {
console.log("您的浏览器支持WebSocket");
console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
socket.send(data);
}
}
</script>
</html>
只是一个简单的demo,期待分享更优质的内容复制代码