1.websocket 不能注入redisTemplate 问题?
2. 注入注解使用问题?
3. 前后端分离 传输的参数格式问题?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
@Configuration
@EnableWebSocket //开启支持websocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
package com.moxi.mogublog.web.websocket;
import com.alibaba.fastjson.JSON;
import com.moxi.mogublog.utils.*;
import com.moxi.mogublog.web.global.RedisConf;
import com.moxi.mogublog.web.global.SysConf;
import com.moxi.mougblog.base.global.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @Author: lkz
* @Title: WebSocketServer
* @Description: TODO
* @Date: 2022/10/11 23:10
*/
@ServerEndpoint("/ws/websocket/{token}")
@Component // 该注解只能放@ServerEndpoint下面 否则会注册失败
@Slf4j
public class WebSocketServer {
/**
** websocket不能注入问题,通过工具类获取,网上资料说在项目启动的时候 依赖加载优先级的问题
还有的说websocket本身不支持注入
**/
@Resource
private StringRedisTemplate stringRedisTemplate=SpringBeanUtils.getBean("stringRedisTemplate");
private static Map<String,Session> sessionPool = new HashMap<>();
private String userId;
/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
private static int onlineCount = 0;
/**concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。*/
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
private Session session;
/**
* 打开新的连接
* 这里转token 我是为了根据token获取用户信息 貌似只能通过这种路径的方式传参
*/
@OnOpen
public void onOpen(Session session,@PathParam("token") String token) {
try {
if(StringUtils.isNotEmpty(token)){
String userInfo= stringRedisTemplate.opsForValue().get(RedisConf.USER_TOKEN + Constants.SYMBOL_COLON + token);
Map<String, Object> map = JsonUtils.jsonToMap(userInfo);
String uid = (String)map.get(SysConf.UID);
this.userId=uid;
this.session = session;
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId); //至于这里为什么这样每次都删除 ,如果每次都是直接添加的话,map中的数量好像一直在增加
webSocketMap.put(userId,this);
}else{
webSocketMap.put(userId,this);
sessionPool.put(token, session);
addOnlineCount();
}
System.out.println("【websocket消息】有新的连接,总数为:"+webSocketMap.size());
/**
*发送的消息 我这里是转换了json个格式 这样前端 可以通过JSON.parse(res.data)获取 否则会出错,或者其他方式,
*/
this.sendAllMessage(JSON.toJSONString("恭喜您上线"));
}
}catch (Exception e){
this.onClose();
}
}
@OnClose
public void onClose() {
webSocketMap.remove(this);
System.out.println("【websocket消息】连接断开,总数为:"+webSocketMap.size());
}
@OnMessage
public void onMessage(String message) {
System.out.println("【websocket消息】收到客户端消息:"+message);
this.sendAllMessage(JSON.toJSONString(message));
}
// 此为广播消息
public void sendAllMessage(String message) {
for(WebSocketServer webSocket : webSocketMap.values()) {
// System.out.println("群发 【websocket消息】广播消息:"+message);
try {
webSocket.session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 此为单点消息
public void sendOneMessage(String code, String message) {
Session session = sessionPool.get(code);
// System.out.println("单点消息 【websocket消息】 唯一标识" +code);
// 在发送数据之前先确认 session是否已经打开 使用session.isOpen() 为true 则发送消息
if (session != null && session.isOpen()) {
try {
// System.out.println("单点消息 【websocket消息】广播消息:" + message);
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 获得此时的
* 在线人数
* @return
*/
public static synchronized int getOnlineCount() {
return onlineCount;
}
/**
* 在线人
* 数加1
*/
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
/**
* 在线人
* 数减1
*/
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}
可以通过getBean的方式获取,解决无法注入问题
@Repository
public class SpringBeanUtils implements BeanFactoryPostProcessor {
//Spring应用上下文环境
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringBeanUtils.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);
}
}
//websocket 相关开始
//我这里是根据点击事件触发
initWebsocket(){
if ('WebSocket' in window) {
var token=getCookie("token");
this.websocket = new WebSocket('ws://localhost:8607/mogu-web/ws/websocket/'+token);
this.websocket.onmessage = this.websocketOnMessage
this.websocket.onerror = this.websocketOnerror
this.websocket.onopen = this.websocketOnopen
this.websocket.onclose = this.websocketClose
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = this.onbeforeunload
} else {
alert('当前浏览器不支持WebSocket!!!')
}
},
websocketOnopen(){
//链接建立之后执行send方法发送数据
console.log("websocket连接成功")
},
websocketOnerror(){
console.log("websocket连接失败")
},
websocketOnMessage(res){
//数据接收 建议数据格式未json
var date= JSON.parse(res.data);
console.log("数据接收:"+date)
},
//客户端发送数据给前端
websocketSend(data){
this.websocket.send(data);
},
websocketClose(){
console.log("websocket关闭")
},
onbeforeunload() {
this.closeWebSocket()
},
closeWebSocket() {
this.websocket.close()
},
//websocket 相关结束
websocket在线工具测试 :http://websocket.jsonin.com/?添加链接描述
不同的浏览器 --浏览器一
浏览器二;