今天让写一个简单的webSocket ,以便于达到统计在线人数
1.导入jar
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.webSocket 配置类
@Configuration
public class WebSocketConfig{
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3.webSocket服务端
package com.ht.cps.service;
import com.alibaba.fastjson.JSONObject;
import com.ht.cps.common.constantInterface.ConstantStatus;
import com.ht.cps.common.utils.RabbitAdminUtils;
import com.ht.cps.entity.india.HtIndiaMemberInfo;
import com.ht.cps.entity.india.MemberOnlineCountMsg;
import com.ht.springboot.snake.utils.FastJsonUtils;
import com.ht.springboot.snake.utils.ValidationUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
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.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @Description ContentWebSocket
* @Author not a good person
* @Date 2020/7/27 12:20
*/
@ServerEndpoint("/websocket/{sid}")//该注解表示该类被声明为一个webSocket终端
@Component
@Slf4j
public class WebSocketServer {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
private final static Set<String> set =new HashSet<>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//接收sid
private String sid="";
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Autowired
private RabbitAdminUtils rabbitAdminUtils;
/**
* 连接建立成功调用的方法
* @param session
* @param sid
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) throws IOException {
log.info("有一连接开启 :" + sid);
this.session = session;
webSocketSet.add(this); //加入set中
if (!set.contains(sid)){
set.add(sid);
HtIndiaMemberInfo info = this.getOoIdAndMemberId(sid);
if (ValidationUtil.isNotBlank(info)){
try {
this.setParam(1,info.getMemberId(),info.getOoId());
} catch (Exception e) {
e.printStackTrace();
}
log.info(info.getOoId()+" 机构下的 userId : " + info.getMemberId()+" 用户上线");
}
}
this.sid=sid;
sendMessage("连接成功");
}
public HtIndiaMemberInfo getOoIdAndMemberId(String str) {
String userKey = ConstantStatus.MEMBER_INFORMATION + str;
String s = redisTemplate.opsForValue().get(userKey);
if (ValidationUtil.isNotBlank(s)){
JSONObject jsonObject = FastJsonUtils.parseObject(s);
String ooId = jsonObject.getString("ooId");
Integer memberId = jsonObject.getInteger("memberId");
return new HtIndiaMemberInfo(ooId, memberId);
}else {
return null;
}
}
public void setParam(Integer type,Integer userId,String ooId)throws Exception{
MemberOnlineCountMsg msg = new MemberOnlineCountMsg();
msg.setStatus(type);
msg.setMemberId(userId);
msg.setOoId(ooId);
this.send(msg);
}
public void send(MemberOnlineCountMsg msg) throws Exception{
try {
rabbitAdminUtils.sendMessageForFanout("membercount", null,FastJsonUtils.toJSONString(msg));
} catch (Exception e) {
log.error("rabbitAdminUtils 发送消息失败");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
String sid = this.sid;
log.info("有一连接关闭 :" + sid);
if (set.contains(sid)){
set.remove(sid);
HtIndiaMemberInfo info = this.getOoIdAndMemberId(sid);
if (ValidationUtil.isNotBlank(info)){
try {
this.setParam(2,info.getMemberId(),info.getOoId());
} catch (Exception e) {
log.error(e.getMessage());
}
log.info(info.getOoId()+" 机构下的 userId : " + info.getMemberId()+" 用户下线");
}
}
}
/**
* 接收客户端发送过来的消息
* @param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到来自窗口" + sid + "的信息:" + message);
//群发消息
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 实现服务器主动推送
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
* @param message
* @param sid
* @throws IOException
*/
public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {
log.info("推送消息到窗口"+sid+",推送内容:"+message);
for (WebSocketServer item : webSocketSet) {
try {
//这里可以设定只推送给这个sid的,为null则全部推送
if(sid==null) {
item.sendMessage(message);
}else if(item.sid.equals(sid)){
item.sendMessage(message);
}
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
return webSocketSet;
}
}
接过这个样子,redisTemplate 和RabbitAdminUtils 这2个bean都是无法注入的,然后就开始百度找攻略。。。
4.先写一个上下文工具类SpringUtils
package com.ht.cps.common.utils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Repository;
/**
* @Description SpringUtils
* @Author not a good person
* @Date 2020/7/29 17:11
*/
@Repository
public class SpringUtils implements BeanFactoryPostProcessor {
//Spring应用上下文环境
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtils.beanFactory = beanFactory;
}
public static ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws org.springframework.beans.BeansException
*
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T) getBeanFactory().getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws org.springframework.beans.BeansException
*
*/
public static <T> T getBean(Class<T> clz) throws BeansException {
T result = (T) getBeanFactory().getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return getBeanFactory().containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* @param name
* @return
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getAliases(name);
}
}
5.更改websocket注入bean的获取方式如下
package com.ht.cps.service;
import com.alibaba.fastjson.JSONObject;
import com.ht.cps.common.constantInterface.ConstantStatus;
import com.ht.cps.common.utils.RabbitAdminUtils;
import com.ht.cps.common.utils.SpringUtils;
import com.ht.cps.entity.india.HtIndiaMemberInfo;
import com.ht.cps.entity.india.MemberOnlineCountMsg;
import com.ht.springboot.snake.utils.FastJsonUtils;
import com.ht.springboot.snake.utils.ValidationUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
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.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @Description ContentWebSocket
* @Author not a good person
* @Date 2020/7/27 12:20
*/
@ServerEndpoint("/websocket/{sid}")//该注解表示该类被声明为一个webSocket终端
@Component
@Slf4j
public class WebSocketServer {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
private final static Set<String> set =new HashSet<>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//接收sid
private String sid="";
private StringRedisTemplate stringRedisTemplate = SpringUtils.getBean(StringRedisTemplate.class);
private static RabbitAdminUtils rabbitAdminUtils = SpringUtils.getBean(RabbitAdminUtils.class);
/**
* 连接建立成功调用的方法
* @param session
* @param sid
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) throws IOException {
log.info("有一连接开启 :" + sid);
this.session = session;
webSocketSet.add(this); //加入set中
if (!set.contains(sid)){
set.add(sid);
HtIndiaMemberInfo info = this.getOoIdAndMemberId(sid);
if (ValidationUtil.isNotBlank(info)){
try {
this.setParam(1,info.getMemberId(),info.getOoId());
} catch (Exception e) {
e.printStackTrace();
}
log.info(info.getOoId()+" 机构下的 userId : " + info.getMemberId()+" 用户上线");
}
}
this.sid=sid;
sendMessage("连接成功");
}
public HtIndiaMemberInfo getOoIdAndMemberId(String str) {
String userKey = ConstantStatus.MEMBER_INFORMATION + str;
String s = stringRedisTemplate.opsForValue().get(userKey);
if (ValidationUtil.isNotBlank(s)){
JSONObject jsonObject = FastJsonUtils.parseObject(s);
String ooId = jsonObject.getString("ooId");
Integer memberId = jsonObject.getInteger("memberId");
return new HtIndiaMemberInfo(ooId, memberId);
}else {
return null;
}
}
public void setParam(Integer type,Integer userId,String ooId)throws Exception{
MemberOnlineCountMsg msg = new MemberOnlineCountMsg();
msg.setStatus(type);
msg.setMemberId(userId);
msg.setOoId(ooId);
this.send(msg);
}
public void send(MemberOnlineCountMsg msg) throws Exception{
try {
rabbitAdminUtils.sendMessageForFanout("membercount", null,FastJsonUtils.toJSONString(msg));
} catch (Exception e) {
log.error("rabbitAdminUtils 发送消息失败");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
String sid = this.sid;
log.info("有一连接关闭 :" + sid);
if (set.contains(sid)){
set.remove(sid);
HtIndiaMemberInfo info = this.getOoIdAndMemberId(sid);
if (ValidationUtil.isNotBlank(info)){
try {
this.setParam(2,info.getMemberId(),info.getOoId());
} catch (Exception e) {
log.error(e.getMessage());
}
log.info(info.getOoId()+" 机构下的 userId : " + info.getMemberId()+" 用户下线");
}
}
}
/**
* 接收客户端发送过来的消息
* @param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到来自窗口" + sid + "的信息:" + message);
//群发消息
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 实现服务器主动推送
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
* @param message
* @param sid
* @throws IOException
*/
public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {
log.info("推送消息到窗口"+sid+",推送内容:"+message);
for (WebSocketServer item : webSocketSet) {
try {
//这里可以设定只推送给这个sid的,为null则全部推送
if(sid==null) {
item.sendMessage(message);
}else if(item.sid.equals(sid)){
item.sendMessage(message);
}
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
return webSocketSet;
}
}
最终问题解决,达到我了预期的效果这里还是非常感谢其他博主,这里贴上他的原文
https://blog.csdn.net/qq_21082615/article/details/91373094?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param