首先js:
var socket;
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
}else{
console.log("您的浏览器支持WebSocket");
var socketUrl="ws://127.0.0.1:端口(api)/访问地址(nationalwebsocket)/直播主键ID1";
console.log(socketUrl);
socket = new WebSocket(socketUrl);
//打开事件,服务器连接成功会自动调用onopen方法然后会回调此方法
socket.onopen = function() {
console.log("websocket已打开");
};
//获得消息事件,服务器调用了message方法会回调此方法
socket.onmessage = function(msg) {
console.log(msg.data);
var da=eval("(" + msg.data + ")");
//发现消息进入 开始处理前端触发逻辑
};
//发生了错误事件
socket.onerror = function() {
console.log("websocket发生了错误");
//关闭事件
socket.onclose = function() {
console.log("websocket已关闭");
};
}
}
java:
pom.xml的引入包
org.springframework.boot
spring-boot-starter-websocket
springboot配置websocket
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
websocket类:
说明:每个用户在浏览器打开直播页面如果当前直播资源是直播中的话就会连接websocket,每连一次都会调用onOpen, 然后会往数据库里直播观看人数添加1
package com.hy.mtgwhy.util;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSONObject;
import com.hy.mtgwhy.common.Constant;
import com.hy.mtgwhy.config.RedisPublicManager;
import com.hy.mtgwhy.response.Response;
import com.hy.mtgwhy.service.MtgLiveVisitService;
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.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint(value = "/nationalwebsocket/{liveId}")
@Component
public class WebSocketServer {
static Log log= LogFactory.get(WebSocketServer.class);
/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。应该用volatile修饰比较好,之前不太懂没有加*/
private static int onlineCount = 0;
/**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
private static ConcurrentHashMap> webSocketMap = new ConcurrentHashMap<>();
/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
private Session session;
/**接收liveId*/
private Integer liveId=0;
/**
* 连接建立成功调用的方法*/
@OnOpen
public void onOpen(Session session,@PathParam("liveId") Integer liveId) {
log.info("进来open方法了===============================================:"+liveId);
this.session = session;
if(liveId!=null && liveId!=0){
MtgLiveVisitService mtgLiveVisitService=SpringBeanUtils.getBean(MtgLiveVisitService.class);
mtgLiveVisitService.insertLiveVisitService(0,liveId); //添加到数据库 访问人数+1
Integer redisNum=0;
if(Utils.isNotEmpty(RedisPublicManager.get(ResRedisKeyConstans.LIVE_COUNT+"_"+liveId+""))){ //如果该直播ID在redis不为空
redisNum=Integer.valueOf(RedisPublicManager.get(ResRedisKeyConstans.LIVE_COUNT+"_"+liveId+""));
}else{ //到数据库里查询该直播资源的观看人数
redisNum=mtgLiveVisitService.getLiveVisitService(liveId);
}
this.liveId=liveId;
if(webSocketMap.containsKey(liveId)){
webSocketMap.get(liveId).add(this);
//加入set中
addOnlineCount();
}else{
CopyOnWriteArraySet c = new CopyOnWriteArraySet();
c.add(this);
webSocketMap.put(liveId, c);
//加入set中
addOnlineCount();
//在线数加1
}
Map num=new HashMap<>();
num.put(liveId,redisNum);
sendMessage(new Response(Constant.RESULT_LIVE_VISIT,"直播API访问人数调用成功",num)); //发送消息给前端
}
log.info("直播连接:"+liveId+",当前在线人数为:" + getOnlineCount());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
log.info("进来onClose方法了===============================================:"+liveId);
MtgLiveVisitService mtgLiveVisitService=SpringBeanUtils.getBean(MtgLiveVisitService.class);
mtgLiveVisitService.updateLiveVisitService(liveId); //更改数据库的 访问人数-1
//copyOnWriteArraySet删除
CopyOnWriteArraySet copyOnWriteArraySet = webSocketMap.get(liveId);
if (copyOnWriteArraySet != null) {
copyOnWriteArraySet.remove(this);
subOnlineCount();
}
Integer redisNum=0;
if(Utils.isNotEmpty(RedisPublicManager.get(ResRedisKeyConstans.LIVE_COUNT+"_"+liveId+""))){ //如果该直播ID在redis不为空
redisNum=Integer.valueOf(RedisPublicManager.get(ResRedisKeyConstans.LIVE_COUNT+"_"+liveId+""));
}else{ //到数据库里查询该直播资源的观看人数
redisNum=mtgLiveVisitService.getLiveVisitService(liveId);
}
Map num=new HashMap<>();
num.put(liveId,redisNum);
sendMessage(new Response(Constant.RESULT_LIVE_VISIT,"直播API访问人数调用成功",num));
log.info("该用户退出直播:"+liveId+",当前在线人数为:" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("程序发生错误了===============================================:"+liveId);
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
log.info("用户消息:"+liveId+",报文:"+message);
}
/**
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:"+this.liveId+",原因:"+error.getMessage());
error.printStackTrace();
this.onClose();
}
/**
* 实现服务器主动推送 给所有连接这个直播ID的用户发送消息 最新的直播查看人数
*/
public void sendMessage(Object message){
log.info("进来sendMessage方法了===============================================:"+liveId);
try {
//遍历客户端
CopyOnWriteArraySet copyOnWriteArraySet = webSocketMap.get(liveId);
if (copyOnWriteArraySet != null) {
for (WebSocketServer item : copyOnWriteArraySet) {
item.session.getBasicRemote().sendText(JSONObject.toJSONString(message));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发送自定义消息
* */
public static void sendInfo(Object message,Integer liveId) throws IOException {
log.info("发送消息到:"+liveId+",报文:"+message);
try {
if(Utils.isNotEmpty(message)&&webSocketMap.containsKey(liveId)){
//遍历客户端updateLiveStatus
CopyOnWriteArraySet copyOnWriteArraySet = webSocketMap.get(liveId);
if (copyOnWriteArraySet != null) {
for (WebSocketServer item : copyOnWriteArraySet) {
item.session.getBasicRemote().sendText(JSONObject.toJSONString(message));
}
}
}else{
log.error("直播"+liveId+",不在线!");
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}
另外如果直播状态更改,从服务器推送给前端:
//更改直播状态
@Override
public Response updateLiveStatus(Integer liveId, Integer status,String session,String sysUserId) {
log.info("开始修改直播状态:");
/// 修改逻辑因为涉及公司代码 已去掉/
//状态更换通知消息给前端
Map map=new HashMap<>();
String url=""; //播放的 地址
if(status==1){ //开启直播
url=mtgLive.getUrl(); //直播地址
}else{
url=mtgLive.getAfterUrl(); //直播地址
}
map.put("status",status+"");
map.put("url",url);
try {
WebSocketServer.sendInfo(new Response(Constant.RESULT_LIVE_STATUS,"直播状态无感
切换",map),liveId); //用websocket发送消息给前端
} catch (IOException e) {
e.printStackTrace();
}
return new Response(Constant.RES_SUCCESS,count>0?"成功":"失败");
}
最后还出现一个bug.在本地可以连,但是到服务器上去要在nginx里配置ws,重要在: proxy_pass http://wsserver/;
location /ws/ {
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://wsserver/;
index index.html index.htm;
}