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到这里就分享完成了。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值