font color=#999AAA /font @TOC hr style= border:solid; width:100px; height:1px; color=#000000 size=1 前言 font color=#999AAA /font hr style= border:solid; width:100px; height:1px; color=#000000 size=1 一、建项目 1. 在父项目ams-clo
<font color=#999AAA >
</font>
@TOC
<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">
前言
<font color=#999AAA ></font>
<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">
一、建项目
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.: DEBUG4.创建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]<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">
<font color=#999AAA >随心所往,看见未来。Follow your heart,see night!<br/>欢迎点赞、关注、留言,一起学习、交流!
【文章原创作者:防ddos攻击 http://www.558idc.com/shsgf.html 复制请保留原URL】