Springboot实现websocket

Websocket

在前面的文章中我们讲到了websocket和传统的http有什么区别,以及websocket用来实现服务器推的优势,那么这篇文章就来说说,在Java中如果要实现一个websocket应该怎么实现,这里采用的是更加方便的Springboot的方式,如果项目中没有使用springboot框架,也是可以实现的,本文不涉及。

代码

服务端

1、先引入springboot-websocket的starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2、定义一个WebSocketBean,用来保存组装的信息,这个Bean也可以自己添加其他的属性

@Getter
@Setter
public class WebSocketBean {
    
    
    private WebSocketSession webSocketSession;
    private int clientId;
    private String token;
}

3、连接或断开处理类

@Slf4j
public class MyWebsocketHandler extends AbstractWebSocketHandler {
    
    

    public static final Map<String, WebSocketBean> webSocketBeanMap;

    /**
     * 仅用用于标识客户端编号
     */
    private static final AtomicInteger clientIdMaker;

    static {
    
    
        webSocketBeanMap = new ConcurrentHashMap<>();
        clientIdMaker = new AtomicInteger(0);
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    
    
        // 当WebSocket连接正式建立后,将该Session加入到Map中进行管理
        Map<String, Object> attributes = session.getAttributes();
        WebSocketBean webSocketBean = new WebSocketBean();
        webSocketBean.setWebSocketSession(session);
        webSocketBean.setClientId(clientIdMaker.getAndIncrement());
        webSocketBean.setToken(attributes.get("token").toString());
        webSocketBeanMap.put(session.getId(), webSocketBean);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    
    
        //当连接关闭后,从Map中移除session实例
        webSocketBeanMap.remove(session.getId());
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
    
    
        //传输过程中出现了错误
        if (session.isOpen()) {
    
    
            session.close();
        }
        webSocketBeanMap.remove(session.getId());
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    
    
        //处理接收到的消息
        log.info("Received message from client[ID:" + webSocketBeanMap.get(session.getId()).getClientId() +
                "]; Content is [" + message.getPayload() + "].");
        TextMessage textMessage = new TextMessage("Server has received your message.");
        session.sendMessage(textMessage);
    }
}

4、把连接监控类配置进spring,用于程序启动时启动websocket

@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
    
    

    @Bean
    public MyWebSocketInterceptor webSocketInterceptor() {
    
    
        return new MyWebSocketInterceptor();
    }

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
    
    
        return new ServerEndpointExporter();
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
    
    
        webSocketHandlerRegistry
                .addHandler(new MyWebsocketHandler(), "/websocket")
                .addInterceptors(webSocketInterceptor());
    }
}

5、可以做一个简单的鉴权

@Slf4j
public class MyWebSocketInterceptor extends HttpSessionHandshakeInterceptor {
    
    

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
    
    
        logger.info("[MyWebSocketInterceptor#BeforeHandshake] Request from " + request.getRemoteAddress().getHostString());
        if (request instanceof ServletServerHttpRequest) {
    
    
            ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
            String token = serverHttpRequest.getServletRequest().getParameter("token");

            //这里做一个简单的鉴权,只有符合条件的鉴权才能握手成功
            if ("123456".equals(token)) {
    
    
                // 保存认证用户
                attributes.put("token", token);
                return super.beforeHandshake(request, response, wsHandler, attributes);
            } else {
    
    
                log.error("token错误。token:[{}]!", token, new ConsumablesCabinetException("token错误"));
                return false;
            }
        }
        return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
    
    
        logger.info("[MyWebSocketInterceptor#afterHandshake] Request from " + request.getRemoteAddress().getHostString());
    }
}

到此,websocket的服务端就完成了,启动工程,就会启动一个websocket服务,现在来实现客户端

客户端

客户端这里也是用java列出,实际上js等各种方式都可以实现
1、先引包

<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.5.1</version>
</dependency>

2、客户端连接断开监控类

public class MyWebSocketClient extends WebSocketClient {
    
    

    private Logger logger = LoggerFactory.getLogger(getClass());

    public MyWebSocketClient(URI serverUri) {
    
    
        super(serverUri);
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
    
    
        logger.info("[MyWebSocketClient#onOpen]The WebSocket connection is open.");
    }

    @Override
    public void onMessage(String s) {
    
    
        logger.info("[MyWebSocketClient#onMessage]The client has received the message from server." +
                "The Content is [" + s + "]");
    }

    @Override
    public void onClose(int i, String s, boolean b) {
    
    
        logger.info("[MyWebSocketClient#onClose]The WebSocket connection is close.");
    }

    @Override
    public void onError(Exception e) {
    
    
        logger.info("[MyWebSocketClient#onError]The WebSocket connection is error.");
    }
}

3、启动类

public class MyWebSocketMain {
    
    

    private static final AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) {
    
    
        URI uri = URI.create("ws://localhost:8001/websocket?token=123456");
        MyWebSocketClient client = new MyWebSocketClient(uri);
        try {
    
    
            // 在连接成功之前会一直阻塞
            client.connectBlocking();

            Timer timer = new Timer();
            MyTimerTask timerTask = new MyTimerTask(client);
            timer.schedule(timerTask, 1000, 2000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }

    static class MyTimerTask extends TimerTask {
    
    

        private final MyWebSocketClient client;

        public MyTimerTask(MyWebSocketClient client) {
    
    
            this.client = client;
        }

        @Override
        public void run() {
    
    
            client.send("Test message from client, the number is " + count.getAndIncrement());
        }
    }
}

运行服务端和客户端就可以看到服务器端不停的输出

Received message from client[ID:0]; Content is [Test message from client, the number is 0].

客户端不停的输出

The client has received the message from server.The Content is [Server has received your message.]

这样就说明成功了

猜你喜欢

转载自blog.csdn.net/qq32933432/article/details/127052431