SpringBoot集成websocket

说明

这里因为公司有个项目需要使用kafka生产和消费消息,然后我这里要将消费到的kafka消息主动推送给前端,所以这里使用了websocket向客户端主动推送消息。
对应我的这篇文章:SpringBoot集成Kafka低版本和高版本,这个里面我没有写websocket相关的代码,这里额外单独写一篇说明。

依赖

fastjson版本自己随便选择,websocket这里选择的是1.4.2.RELEASE版本,因为项目的SpringBoot版本依赖是1.4.2.RELEASE。

		<!--json对象与字符串互转-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.83</version>
		</dependency>
		<!--集成websocket,与springboot版本相对应-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
			<version>1.4.2.RELEASE</version>
		</dependency>

项目结构

只需要配置这2个,websocket即可集成成功。
在这里插入图片描述

WebSocketServer 代码

这里我是将uuid作为唯一进行连接,这里的uuid为前端生成

package com.gmcc.project.controllers.websocket;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * webSocket服务端
 * 客户端本地测试可以使用这个网站:https://www.dute.org/websocket
 */
@ServerEndpoint("/webSocket/{uuid}")
@Component
public class WebSocketServer {
    private final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
    /**
     * 以uuid为key,连接会话为对象保存起来
     */
    public static Map<String, Session> websocketClients = new ConcurrentHashMap<>();
    /**
     * 会话
     */
    private Session session;
    /**
     * 根据uuid唯一标识建立websocket通道
     */
    private String uuid;

    /**
     * 发送消息到指定连接
     * @param uuid uuid唯一标识
     * @param jsonString 消息
     */
    public static void sendMessage(String uuid,String jsonString){
        Session nowSession = websocketClients.get(uuid);
        if(nowSession!=null){
            try {
                nowSession.getBasicRemote().sendText(jsonString);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //建立连接成功调用
    @OnOpen
    public void onOpen(@PathParam("uuid") String uuid, Session session)
    {
        this.uuid = uuid;
        this.session = session;
        if(websocketClients.get(uuid)==null){
            websocketClients.put(uuid, session);
            System.out.println("当前uuid:"+uuid+"已创建连接");
        }
    }

    //错误时调用
    @OnError
    public void onError(Session session, Throwable error) {
        logger.info("服务端发生了错误"+error.getMessage());
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose()
    {
        websocketClients.remove(uuid);
        System.out.println("当前uuid:"+uuid+"已退出连接");
    }

    /**
     * 接收客户端的消息
     *
     * @param message 消息
     * @param session 会话
     */
    @OnMessage
    public void onMessage(String message, Session session){
        System.out.println("服务端从客户端uuid为"+uuid+"收到了一条消息:"+message);
        //向客户端回传消息
        //session.getAsyncRemote().sendText("来自服务器:"+uuid+"你的消息我收到啦");
    };

    /**
     * 向所有连接主动推送消息
     * @param jsonObject 消息体
     * @throws IOException
     */
    public static void sendMessageAll(JSONObject jsonObject) throws IOException {
        for (Session item : websocketClients.values()) {
            item.getAsyncRemote().sendText(jsonObject.toJSONString());
        }
    }
}


WebSocketConfig代码

package com.gmcc.project.controllers.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebScoket配置处理器
 */
@Configuration
public class WebSocketConfig {
    /**
     * ServerEndpointExporter 作用
     *
     * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
     *
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

Controller测试代码

package com.gmcc.project.controllers.kafka;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gmcc.project.controllers.websocket.WebSocketServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

//kafka生产者
@RestController
@RequestMapping("kafkaProducer")
public class KafkaProducerController {

    @RequestMapping(value = "/message", method = RequestMethod.POST)
    public void message(@RequestParam(value = "uuid", required = false) String uuid,
                     @RequestParam(value = "message", required = false) String message) {
        try {
            //向webSocket客户端里面的指定uuid推送消息
            WebSocketServer.sendMessage(uuid,message);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @RequestMapping(value = "/messageAll", method = RequestMethod.POST)
    public void messageAll(@RequestParam(value = "message", required = false) String message) {
        try {
            //向所有连接主动推送消息
            String msg="{\"code\": \"200\", \"message\": \""+message+"\",\"result\": \""+message+"\"}";
            JSONObject jsonObject= JSON.parseObject(msg);
            WebSocketServer.sendMessageAll(jsonObject);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

页面测试

后端服务启动后,这里使用这个网站:https://www.dute.org/websocket,模拟前端连接后端服务。这里我项目的端口是17890,如果你的项目端口是8080的话,改为8080就可以了。
注意:websocket地址格式,如果是http请求,那就是ws开头。如果是https开头,那就是wss开头才能连接上。
websocket中http格式:ws://ip:项目端口号/项目名称(得看你的项目有没有配置,没有可不写)/@ServerEndpoint注解里面的路径值
在这里插入图片描述
然后点击连接按钮,连接成功
在这里插入图片描述

后端日志打印:
在这里插入图片描述
这里我打开三个页面进行模拟连接,如下:
第一个:
在这里插入图片描述
第二个,这里的第二个我的uuid写的和第一个一样,这里是故意写的,原因后面会说:
在这里插入图片描述
第三个:
在这里插入图片描述
连接成功后,我这里使用postman进行测试:
向指定uuid发送消息
在这里插入图片描述
然后看页面结果:
这是第一个
在这里插入图片描述
第二个,结果如下:
发现没有接收到消息,这里之所以这样是代码里面使用了ConcurrentHashMap,只会对第一个连接的有效,后面相同的uuid连接就不会收到消息,这里之所以这样做,是基于这样考虑的,如果你使用的是用户名进行登录的,然后这个用户名又可以同时登录多台电脑,然后这时候假设有一个人使用了这个用户名进行了websocket操作,其他人也登录了这个用户,但是没有进行websocket操作,这时候是不是就是只有那个进行了websocket操作的才能接收到后端返回的消息,如果其他登录的没有进行websocket操作的用户也收到了消息,是不是就会不合理。
这里还是得看个人功能需求。需求不一样,功能实现也就不一样。
在这里插入图片描述
第三个,结果如下:
结果正常,没有消息,因为是往uuid为111的发送消息,所以uuid为222的理当收不到消息
在这里插入图片描述
向所有连接主动推送消息:
在这里插入图片描述
结果如下:
第一个正常收到消息
在这里插入图片描述
第二个:
没有收到消息,因为第一个已经有了
在这里插入图片描述
第三个:
正常收到消息
在这里插入图片描述
好了,我的websocket集成demo到这里就分享完成了。

SpringBoot集成WebSocket可以使用Spring框架提供的WebSocket API来实现。在SpringBoot中,使用WebSocket需要进行以下几个步骤: 1. 添加依赖:在pom.xml文件中添加spring-boot-starter-websocket依赖。 2. 创建WebSocket配置类:创建一个WebSocket配置类,用于配置WebSocket相关的参数,如注册EndPoint、消息编解码器、拦截器等。 3. 创建EndPoint:创建一个WebSocket的EndPoint类,用于处理WebSocket连接、消息发送、关闭等操作。可以通过实现Spring提供的WebSocketHandler接口或者继承TextWebSocketHandler来实现。 4. 添加拦截器:可以添加自定义的拦截器,用于处理WebSocket连接建立、消息发送等事件。 5. 配置WebSocket消息代理:使用Spring提供的消息代理,可以实现WebSocket消息的广播和点对点传递。 以下是一个简单的SpringBoot集成WebSocket的示例代码: 1. 添加依赖 ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建WebSocket配置类 ``` @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(), "/myHandler") .addInterceptors(new WebSocketInterceptor()); } @Bean public WebSocketHandler myHandler() { return new MyHandler(); } } ``` 3. 创建EndPoint ``` public class MyHandler extends TextWebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { // 处理连接建立事件 } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { // 处理消息事件 } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { // 处理连接关闭事件 } } ``` 4. 添加拦截器 ``` public class WebSocketInterceptor extends HandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { // 处理连接建立前事件 return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { // 处理连接建立后事件 } } ``` 5. 配置WebSocket消息代理 ``` @Configuration @EnableWebSocketMessageBroker public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/myEndpoint") .setAllowedOrigins("*") .withSockJS(); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值