SpringCloud整合WebSocket实现用户监控
@
目录
前言
一、建项目
1. 在父项目ams-cloud下建立maven子项目ams-websocket
2.pom文件添加常用依赖,另外添加redis依赖等,我这里直接引用common模块
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.ams</groupId>
<artifactId>ams-common</artifactId>
<version>${ams.version}</version>
</dependency>
</dependencies>
3.添加bootstrap.yml文件
server:
port: 21000
spring:
application:
name: ams-websocket
cloud:
nacos:
# 注册中心
discovery:
server-addr: http://192.168.132.129:8848
# 配置中心
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
shared-configs[0]:
data-id: ams-common.yaml
refresh: true
logging:
level:
spring.: DEBUG
4.创建application
@EnableDiscoveryClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan("com.ams")
public class WebsocketApp {
public static void main(String[] args) {
SpringApplication.run(WebsocketApp.class,args);
}
}
二、添加config类、拦截器类、处理器类等
1.添加config类
@Configuration
@EnableWebSocket
public class WebsocketConfig implements WebSocketConfigurer {
@Autowired
private RedisUtils redisUtils;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册websocket组件 添加处理器和拦截器
// websocket是websocket服务器的请求路径可以自己定义
registry.addHandler(new WebsocketHandler(redisUtils),"/websocket")
//指定自定义拦截器
.addInterceptors(new WebsocketInterceptor(redisUtils))
//允许跨域
.setAllowedOrigins("*");
//在某些低版本的浏览器中不支持websocket可以用sock-js替代
registry.addHandler(new WebsocketHandler(redisUtils),"/sock-js")
// 指定自定义拦截器
.addInterceptors(new WebsocketInterceptor(redisUtils))
// 允许跨域
.setAllowedOrigins("*")
// 开启sockJs支持
.withSockJS();
}
}
2.添加拦截器类
@Slf4j
public class WebsocketInterceptor extends HttpSessionHandshakeInterceptor {
private final RedisUtils redisUtils;
public WebsocketInterceptor(RedisUtils redisUtils){
this.redisUtils=redisUtils;
}
/** 管理握手过程,存入用户信息 */
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response,
WebSocketHandler handler,
Map<String, Object> map) throws Exception {
String header_key = "Sec-WebSocket-Protocol";
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(header_key);
log.info("token = [{}]", token);
HttpHeaders responseHeaders = response.getHeaders();
UserAuthDTO userAuthDTO = getUserInfo(token);
if(userAuthDTO == null){
log.error("socket连接失败 ---> token过期 ---> [{}]", token);
response.setStatusCode(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED);
return false;
}
map.put("userAuthDTO",userAuthDTO);
responseHeaders.add(header_key,token);
return super.beforeHandshake(request, response, handler, map);
}
/** 通过redis读取用户信息 **/
public UserAuthDTO getUserInfo(String token) {
String key = token;
if(StrUtil.isEmpty(key)){
return null;
}
UserAuthDTO userAuthDTO = (UserAuthDTO) redisUtils.get(key);
if(userAuthDTO==null){
log.error("redis用户信息空 ---> 登录过期/token不正确");
return null;
}
return userAuthDTO;
}
}
3.添加处理器类
@Slf4j
public class WebsocketHandler extends AbstractWebSocketHandler {
//定义全局变量用于保存所有用户的会话
/** 系统管理员 **/
public static final Map<String, WebSocketSession> SYSUSER_SOCKETS = new HashMap<>();
private static RedisUtils redisUtils;
public WebsocketHandler(RedisUtils redisUtils){
WebsocketHandler.redisUtils = redisUtils;
}
/**
* webSocket连接创建后调用
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Map<String, Object> attrMap = session.getAttributes();
UserAuthDTO userAuthDTO = (UserAuthDTO) attrMap.get("userAuthDTO");
SYSUSER_SOCKETS.put(userAuthDTO.getUserId().toString(),session);
log.info("管理员[{}]连接成功,当前在线人数[{}]", userAuthDTO.getUsername(), SYSUSER_SOCKETS.size());
}
/**
* 接收到消息会调用
*/
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
try {
log.info("收到客户端消息[{}]", message);
if(session.isOpen()){
session.sendMessage(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 连接关闭会调用
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
log.info("客户端关闭连接....");
Map<String, Object> attrMap = session.getAttributes();
// 删除缓存
deleteSocket(attrMap);
// 关闭连接
session.close();
log.info("已关闭socket连接");
}
/**
* 删除socket缓存
*/
public static void deleteSocket(Map<String, Object> attr) {
UserAuthDTO userAuthDTO = (UserAuthDTO) attr.get("userAuthDTO");
if (!SYSUSER_SOCKETS.isEmpty()) {
SYSUSER_SOCKETS.remove(userAuthDTO.getUserId().toString());
log.info("管理员[{}]关闭连接了,当前在线人数[{}]", userAuthDTO.getUsername(), SYSUSER_SOCKETS.size());
}
}
/**
* 连接出错会调用
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
log.error("socket连接出错...");
exception.printStackTrace();
Map<String, Object> attrMap = session.getAttributes();
//删除缓存
deleteSocket(attrMap);
// 关闭连接
session.close();
log.error("已关闭socket连接");
}
}
三、添加controller
1.controller如下:
@RestController
@RequestMapping("/websocket")
@Slf4j
@RequiredArgsConstructor
public class WebsocketController {
/** 获取在线管理用户 */
@GetMapping(value = "getLoginSysUser")
public R<List<UserAuthDTO>> getLoginSysUser(){
Map<String, WebSocketSession> userMap = WebsocketHandler.SYSUSER_SOCKETS;
List<UserAuthDTO> list = new ArrayList<>();
userMap.forEach((k,v)->{
Map<String, Object> attrMap = v.getAttributes();
UserAuthDTO userAuthDTO = (UserAuthDTO) attrMap.get("userAuthDTO");
list.add(userAuthDTO);
});
return R.ok(list);
}
}
2.运行结果
2022-03-04 16:58:56.822 INFO 15272 --- [nio-21000-exec-2] c.c.f.m.w.config.WebsocketInterceptor : token = [83868c09-a744-4a7a-a16e-24dc3d7e8cdc]
2022-03-04 16:58:59.335 INFO 15272 --- [nio-21000-exec-2] c.c.f.m.w.handler.WebsocketHandler : 管理员[admin]连接成功,当前在线人数[1]
*随心所往,看见未来。Follow your heart,see night!*
**欢迎点赞、关注、留言,一起学习、交流!**