@(文章目錄) 前言 一、建項目 1. 在父項目ams-cloud下建立maven子項目ams-websocket 2.pom文件添加常用依賴,另外添加redis依賴等,我這裡直接引用common模塊 <dependencies> <dependency> <groupId>com.alibaba. ...
@
目錄前言
一、建項目
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!*
**歡迎點贊、關註、留言,一起學習、交流!**