引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import java.util.Map;
/***
* @Description: 握手拦截器
*/
@Component
public class MyWsInterceptor extends HttpSessionHandshakeInterceptor {
private static final Logger LOG= LoggerFactory.getLogger(MyWsInterceptor.class);
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
LOG.info(request.getRemoteAddress().toString()+"开始握手");
return super.beforeHandshake(request, response, wsHandler, attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
LOG.info(request.getRemoteAddress().toString()+"完成握手");
super.afterHandshake(request, response, wsHandler, ex);
}
}
用于自定义Bean用于扩展要用的数据
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.web.socket.WebSocketSession;
@Data
@AllArgsConstructor
public class SessionBean {
private WebSocketSession webSocketSession;
private Integer clientId;
}
配置类
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import javax.annotation.Resource;
@Configuration
@EnableWebSocket
public class MyWsConfig implements WebSocketConfigurer {
@Resource
MyWsHandler myWsHandler;
@Resource
MyWsInterceptor myWsInterceptor;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(myWsHandler,"/myWs").addInterceptors(myWsInterceptor).setAllowedOrigins("*");
}
}
消息处理
import org.springframework.boot.logging.LoggerGroups;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import javax.websocket.Session;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
public class MyWsHandler extends AbstractWebSocketHandler {
private static final Logger LOG=LoggerFactory.getLogger(MyWsHandler.class);
private static Map<String , SessionBean> sessionBeanMap;
private static AtomicInteger clientIdMaker;
static{
sessionBeanMap=new ConcurrentHashMap<>();
clientIdMaker=new AtomicInteger(0);
}
//连接建立
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
LOG.info(sessionBeanMap.get(session.getId()).getClientId()+""+"连接建立了");
SessionBean sessionBean = new SessionBean(session,clientIdMaker.getAndIncrement());
sessionBeanMap.put(session.getId(),sessionBean);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
LOG.info(sessionBeanMap.get(session.getId()).getClientId()+""+message.getPayload());
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
super.handleTransportError(session, exception);
if (session.isOpen()){
session.close();
}
sessionBeanMap.remove(session.getId());
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
LOG.info(sessionBeanMap.get(session.getId()).getClientId()+""+"连接关闭了");
super.afterConnectionClosed(session, status);
}
@Override
public boolean supportsPartialMessages() {
return super.supportsPartialMessages();
}
@Scheduled(fixedRate = 1000)
public void sendMsg() {
Map<String,String> map = new HashMap<>();
try {
for (String sessionId : sessionBeanMap.keySet()) {
WebSocketSession webSocketSession = sessionBeanMap.get(sessionId).getWebSocketSession();
if (webSocketSession.isOpen()){
// 业务逻辑
。。。
// 发送消息
webSocketSession.sendMessage(new TextMessage("要发送的消息"));
}else {
sessionBeanMap.remove(sessionId);
}
}
}catch (CustomException | IOException | ModbusTransportException e){
LOG.error("发送数据失败:"+e.getMessage());
}
}
}
Tip:在使用webSocket推送消息的时候,可以使用异步化注解@Async进行解耦,对于该注解在同一个类中使用加上该注解的方法的时候,注解不会生效(类似这样的注解还有@Transactional)
因为在使用spring异步化注解的时候,本质上会创建一个代理类来扩展目标类,并将带有@Async注解的方法的调用委派给另一个线程执行。当在同一个类中调用带有@Async注解的方法时,这个调用是通过目标类的内部调用来完成的,而不是通过代理类的调用。因此,注解不会生效。