@
目录
- [/code][size=5]一、建项目[/size]
- [size=3]1. 在父项目ams-cloud下建立maven子项目ams-websocket[/size]
- [img]https://img-blog.csdnimg.cn/e57204e3c5f64ce386ce31e0ffc60544.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAZm9seWg=,size_20,color_FFFFFF,t_70,g_se,x_16[/img]
- [size=3]2.pom文件添加常用依赖,另外添加redis依赖等,我这里直接引用common模块[/size]
- [code] <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]
复制代码 |