目录
1、引入websocket依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、websocket消息处理器
@Slf4j
@Component
public class WebSocketHandler extends TextWebSocketHandler {
private static final ConcurrentHashMap<String, List<WebSocketSession>> POOL_SESSION = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String userId = (String) session.getAttributes().get(SecurityConstants.DETAILS_USER_ID);
List<WebSocketSession> sessionList = getSessionList(session);
if (CollectionUtils.isEmpty(sessionList)) {
sessionList = new ArrayList<>();
POOL_SESSION.put(userId, sessionList);
}
sessionList.add(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
List<WebSocketSession> sessionList = getSessionList(session);
if (CollectionUtils.isEmpty(sessionList)) {
return;
}
sessionList.remove(session);
}
private List<WebSocketSession> getSessionList(WebSocketSession session) {
String userId = (String) session.getAttributes().get(SecurityConstants.DETAILS_USER_ID);
if (userId == null) {
throw new BusinessServiceException("未认证");
}
return POOL_SESSION.get(userId);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 获得客户端传来的消息
String payload = message.getPayload();
log.info("server 接收到消息 {}", payload);
session.sendMessage(new TextMessage(payload));
}
/**
* 发送消息
*/
public boolean sendMsg(Long userId, String content) {
List<WebSocketSession> sessionList = POOL_SESSION.get(userId);
if (CollUtil.isEmpty(sessionList)) {
return false;
}
int result = 0;
for (WebSocketSession session : sessionList) {
try {
if (session.isOpen()) {
session.sendMessage(new TextMessage(content));
result++;
}
} catch (IOException e) {
log.error("发送消息给{}失败", userId, e);
}
}
return result != 0;
}
}
3、websocket 鉴权拦截器
@Component
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor {
/**
* 加密密钥
*/
private static final String SECRET_KEY = "hdsfasdfqzsdfdsfsf";
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
//Authorization
String authorization = ((ServletServerHttpRequest) request).getServletRequest().getParameter(SecurityConstants.AUTH_HEADER);
if (StringUtils.isEmpty(authorization)) {
return false;
}
//验证token有效性
String token = authorization.substring(SecurityConstants.BEARER_.length());
DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build().verify(token);
if (jwt.getExpiresAt().before(new Date())) {
return false;
}
//将参数放到attributes
attributes.put(SecurityConstants.DETAILS_USER_ID, jwt.getClaim(SecurityConstants.DETAILS_USER_ID).asString());
return super.beforeHandshake(request, response, wsHandler, attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
}
4、websocket 配置类
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private WebSocketHandler webSocketHandler;
@Autowired
private WebSocketInterceptor webSocketInterceptor;
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry
.addHandler(webSocketHandler, "/ws")
.addInterceptors(webSocketInterceptor)
.setAllowedOrigins("*");
}
}
5、h5页面
<script type="text/javascript">
let ws = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
ws = new WebSocket("ws://localhost:9999/ws?Authorization="+"Bearer qqqqqq");
ws.send("发送消息");
}
</script>