本文是项目中使用了websocket进行一些数据的推送,对比项目做了一个demo,ws的相关问题不做细数,仅做一下记录。

此demo针对ws的搭建主要逻辑背景是一个服务端B:通讯层 产生消息推送出去,另外一个项目A充当客户端和服务端,A的客户端:是接收通讯层去无差别接收这些消息,A的服务端:根据地址ip去订阅。用户通过订阅A的ws,同时记录下自己的信息,项目B推送的消息,项目A接收到之后通过当初订阅的逻辑和一些权限过滤条件对项目B产生的消息进行过滤再推送到用户客户端上。

一、项目中服务端的创建

首先引入maven仓库

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

websocket的服务端搭建

同时注意springboot要开启ws服务

启动类加上@EnableScheduling

简要解读demo

/webSocket/{id}:链接的id是业务上的一个id,这边之前做过类似拍卖的,相当于一个服务端或者业务上的一个标识,是客户端指明链接到哪一个拍卖间的标识

@ServerEndpoint:作为服务端的注解。

package com.ghh.myproject.websocket;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint("/webSocket/{id}")
@Component
public class WebSocket {
    private Logger log = LoggerFactory.getLogger(WebSocket.class);
    private static int onlineCount = 0;
    /** 创建一个map存放   产生的ws链接推送 */
    private static Map<String, WebSocket> clients = new ConcurrentHashMap<>();
    /** 创建一个map存放   当前接入的客户端 */
    private static Map<String, String> idMap = new ConcurrentHashMap<>();
    
    private Session session;
    /** 链接进入的一个场景id */
    private String id;
    /** 每一个链接的一个唯一标识 */
    private String userNo;
    /**
    * @Description: 第三方文接入当前项目websocket后的记录信息
    * @DateTime: 2021/7/5 10:02
    * @Author: GHH
    * @Params: [id, session]
    * @Return void
    */
    @OnOpen
    public void onOpen(@PathParam("id") String id, Session session) throws IOException {
        log.info("已连接到id:{}竞拍场,当前竞拍场人数:{}", id, getUserNosById(id).size());
        this.id = id;
        this.session = session;
        // 生成一个随机序列号来存储一个id下的所有用户
        this.userNo = UUID.fastUUID().toString();
        addOnlineCount();
        //根据随机序列号存储一个socket连接
        clients.put(userNo, this);
        idMap.put(userNo, id);
    }
    /**
    * @Description: 关闭连接
    * @DateTime: 2021/7/5 10:02
    * @Author: GHH
    * @Params: []
    * @Return void
    */
    @OnClose
    public void onClose() throws IOException {
        clients.remove(userNo);
        idMap.remove(userNo);
        subOnlineCount();
    }
    /**
    * @Description: 客户端发送消息调用此方法
    * @DateTime: 2021/6/16 15:35
    * @Author: GHH
    * @Params: [message]
    * @Return void
    */
    @OnMessage
    public void onMessage(String message) throws IOException {
//        JSONObject jsonTo = JSONObject.parseObject(message);
//        String mes = (String) jsonTo.get("message");
//        if (!("All").equals(jsonTo.get("To"))) {
//            sendMessageTo(mes, jsonTo.get("To").toString());
//        } else {
//            sendMessageAll(message);
//        }
        log.info("onMessage方法成功");
    }
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("{}", error);
    }
    public static void sendMessageTo(String message, String userNo) throws IOException {
        // session.getBasicRemote().sendText(message);
        //session.getAsyncRemote().sendText(message);
        WebSocket webSocket = clients.get(userNo);
        if (webSocket != null && webSocket.session.isOpen()) {
            webSocket.session.getAsyncRemote().sendText(JSON.toJSONString(message));
        }
    }
    /**
    * @Description: 推送到指定的id值的记录
    * @DateTime: 2021/6/15 17:11
    * @Author: GHH
    * @Params: [message, id]
    * @Return void
    */
    public static void sendMessageToById(String message, String id) {
        // session.getBasicRemote().sendText(message);
        //session.getAsyncRemote().sendText(message);
        //根据id获取所有的userNo链接的用户
        List<String> userNos = getUserNosById(id);
        for (WebSocket item : clients.values()) {
            //遍历链接的value值,如果当前传入的id中链接的用户包含value值,则推送。
            if (userNos.contains(item.userNo)) {
                item.session.getAsyncRemote().sendText(message);
            }
        }
    }
    /**
    * @Description: 推送所有开启的信息
    * @DateTime: 2021/6/15 17:13
    * @Author: GHH
    * @Params: [message]
    * @Return void
    */
    public static void sendMessageAll(String message){
        for (WebSocket item : clients.values()) {
            item.session.getAsyncRemote().sendText(message);
        }
    }
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount  ;
    }
    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }
    public static synchronized Map<String, WebSocket> getClients() {
        return clients;
    }
    /**
    * @Description: 根据相应场景的一些逻辑处理
    * @DateTime: 2021/7/5 10:03
    * @Author: GHH
    * @Params: [id]
    * @Return java.util.List<java.lang.String>
    */
    public static List<String> getUserNosById(String id) {
        ArrayList<String> userNos = new ArrayList<>();
        for (Map.Entry<String, String> entry : idMap.entrySet()) {
            if (entry.getValue().equals(id)) {
                userNos.add(entry.getKey());
            }
        }
        return userNos;
    }
}

 demo中模拟的是定时器推送,第一个参数是消息内容,第二个是推送到哪一个拍卖间或者其他业务上的内容。方法的具体内容上一段代码有详细解释,有通过id,或者发送给全部ws链接的客户端

WebSocket.sendMessageToById("" count,2 "");
@Scheduled(cron = "*/5 * * * * ?")
    public void job1(){
        log.info("测试生成次数:{}",count);
        redisTemplate.opsForValue().set("测试" count, "" count  );
        if (count%2==0){
            WebSocket.sendMessageToById("" count,2 "");
        }else {
            WebSocket.sendMessageToById("" count,1 "");
        }

        log.info("websocket发送" count);
    }

二、java充当客户端链接ws

上述是java作为ws服务端推送当前业务信息的一个demo。我们项目目前做的是一个通讯层的概念,只能够推送数据内容,却无法根据用户权限去推送不同的数据。

ws客户端的搭建,首先链接ws服务端。首先是我们另外一个服务的ws配置信息,我这边demo是模拟链接上面的ws服务

1、ws客户端的配置

package com.ghh.websocketRecive.wsMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.ContainerProvider;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import java.net.URI;
/**
 * @author ghh
 * @date 2019-08-16 16:02
 */
@Component
@Slf4j
public class WSClient {
    public static Session session;
    public static void startWS() {
        try {
            if (WSClient.session != null) {
                WSClient.session.close();
            }
            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
            //设置消息大小最大为10M
            container.setDefaultMaxBinaryMessageBufferSize(10*1024*1024);
            container.setDefaultMaxTextMessageBufferSize(10*1024*1024);
            // 客户端,开启服务端websocket。
            String uri = "ws://192.168.0.108:8082/webSocket/1";
            Session session = container.connectToServer(WSHandler.class, URI.create(uri));
            WSClient.session = session;
        } catch (Exception ex) {
            log.info(ex.getMessage());
        }
    }
}

2、配置信息需要在项目启动的时候去启用和链接ws服务

package com.ghh.websocketRecive;
import com.ghh.websocketRecive.wsMessage.WSClient;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import javax.annotation.PostConstruct;
@Slf4j
@EnableScheduling
@SpringBootApplication
@MapperScan("com.ghh.websocketRecive.dao")
public class WebsocketReciveApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebsocketReciveApplication.class, args);
    }
    @PostConstruct
    public void init(){
        log.info("初始化应用程序");     // 初始化ws,链接服务端
        WSClient.startWS();
    }
}

3、接收服务端推送的消息进行权限过滤demo

@ClientEndpoint:作为ws的客户端注解,@OnMessage接收服务端推送的消息。

package com.ghh.websocketRecive.wsMessage;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ghh.websocketRecive.entity.Student;
import com.ghh.websocketRecive.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.websocket.*;
import java.util.Objects;
import java.util.Set;
import static com.ghh.websocketRecive.wsMessage.WSClient.startWS;
@ClientEndpoint
@Slf4j
@Component
public class WSHandler {
    @Autowired
    RedisTemplate<String,String> redisTemplate;
    private static RedisTemplate<String,String> redisTemplateService;
    @PostConstruct
    public void init() {
        redisTemplateService=redisTemplate;
    }
    @OnOpen
    public void onOpen(Session session) {
        WSClient.session = session;
    }
    @OnMessage
    public void processMessage(String message) {
        log.info("websocketRecive接收推送消息" message);
        int permission = Integer.parseInt(message)%5;
        //查询所有订阅的客户端的ip。
        Set<String> keys = redisTemplateService.keys("ip:*");
        for (String key : keys) {
            // 根据登录后存储的客户端ip,获取权限地址
            String s = redisTemplateService.opsForValue().get(key);
            String[] split = s.split(",");
            for (String s1 : split) {
                //向含有推送过来的数据权限地址的客户端推送告警数据。
                if (s1.equals(permission "")){
                    WebSocket.sendMessageToByIp(message,key.split(":")[1]);
                }
            }
        }
    }
    @OnError
    public void processError(Throwable t) {
        WSClient.session = null;
        try {
            Thread.sleep(5000);
            startWS();
        } catch (InterruptedException e) {
            log.error("---websocket processError InterruptedException---", e);
        }
        log.error("---websocket processError error---", t);
    }
    @OnClose
    public void processClose(Session session, CloseReason closeReason) {
        log.error(session.getId()   closeReason.toString());
    }
    public void send(String sessionId, String message) {
        try {
            log.info("send Msg:"   message);
            if (Objects.nonNull(WSClient.session)) {
                WSClient.session.getBasicRemote().sendText(message);
            } else {
                log.info("---websocket error----");
            }
        } catch (Exception e) {
            log.error("---websocket send error---", e);
        }
    }
}

4、ws客户端推送消息,推送消息和上面服务端类似。

这边是根据ip

package com.ghh.websocketRecive.wsMessage;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.ghh.websocketRecive.service.UserService;
import lombok.Builder;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint("/webSocket/{ip}")
@Component
public class WebSocket {
    private Logger log = LoggerFactory.getLogger(WebSocket.class);
    private static int onlineCount = 0;
    private static Map<String, WebSocket> clients = new ConcurrentHashMap<>();
    private Session session;
    /** 当前连接服务端的客户端ip */
    private String ip;
    @Autowired
    RedisTemplate<String,String> redisTemplate;
    private static RedisTemplate<String,String> redisTemplateService;
    @PostConstruct
    public void init() {
        redisTemplateService = redisTemplate;
    }
    @OnOpen
    public void onOpen(@PathParam("ip") String ip, Session session) throws IOException {
        log.info("ip:{}客户端已连接:,当前客户端数量:{}", ip, onlineCount 1);
        this.ip = ip;
        this.session = session;
        // 接入一个websocket则生成一个随机序列号
        addOnlineCount();
        //根据随机序列号存储一个socket连接
        clients.put(ip, this);
    }
    @OnClose
    public void onClose() throws IOException {
        clients.remove(ip);
        onlineCount--;
        subOnlineCount();
    }
    /**
    * @Description: 客户端发送消息调用此方法
    * @DateTime: 2021/6/16 15:35
    * @Author: GHH
    * @Params: [message]
    * @Return void
    */
    @OnMessage
    public void onMessage(String message) throws IOException {
        log.info("客户端发送消onMessage方法成功");
    }
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("{}", error);
    }
    public static void sendMessageTo(String message, String userNo) throws IOException {
        WebSocket webSocket = clients.get(userNo);
        if (webSocket != null && webSocket.session.isOpen()) {
            webSocket.session.getAsyncRemote().sendText(JSON.toJSONString(message));
        }
    }
    /**
    * @Description: 推送到指定的ip值的记录
    * @DateTime: 2021/6/15 17:11
    * @Author: GHH
    * @Params: [message, id]
    * @Return void
    */
    public static void sendMessageToByIp(String message, String ip) {
        for (WebSocket item : clients.values()) {
            //遍历链接的value值,如果当前传入的ip中链接的用户包含value值,则推送。
            if (item.ip.equals(ip)) {
                item.session.getAsyncRemote().sendText(message);
            }
        }
    }
    /**
    * @Description: 推送所有开启的信息
    * @DateTime: 2021/6/15 17:13
    * @Author: GHH
    * @Params: [message]
    * @Return void
    */
    public static void sendMessageAll(String message){
        for (WebSocket item : clients.values()) {
            item.session.getAsyncRemote().sendText(message);
        }
    }
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount  ;
    }
    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }
    public static synchronized Map<String, WebSocket> getClients() {
        return clients;
    }
}

概述:

至此,简易的demo搭建完成,项目gitee网址:https://gitee.com/ghhNB/study.git

到此这篇关于SpringBoot整合WebSocket的客户端和服务端的实现的文章就介绍到这了,更多相关SpringBoot整合WebSocket内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

SpringBoot整合WebSocket的客户端和服务端的实现代码的更多相关文章

  1. 五分钟学会HTML5的WebSocket协议

    这篇文章主要介绍了五分钟学会HTML5的WebSocket协议,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 前端监听websocket消息并实时弹出(实例代码)

    这篇文章主要介绍了前端监听websocket消息并实时弹出,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. HTML5 WebSocket实现点对点聊天的示例代码

    这篇文章主要介绍了HTML5 WebSocket实现点对点聊天的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. ios – Websockets可以在移动电话上工作吗?

    相关地,我怀疑长轮询客户端可能是实现类似功能的好方法,但我想知道我可能遇到的移动特定问题.到目前为止,我已经读过长时间的轮询请求可能会对电池寿命产生相当大的影响.我还听说iOS以某种方式限制了对单个服务器的连接数量,这可能是个问题.有没有人在使用实时组件的移动应用程序上工作?

  5. ios-swift,objective-c协议实现

    作为隐式解开的可选项.

  6. ios – 红蜘蛛代表没有被召集

    变量不是nil,我有一个很好的连接,url是正确的,但没有调用委托方法.我也正在实现WebSocketDelegate解决方法套接字应该是您的类的属性或变量,以确保它附近.如果仅在函数堆栈上分配它,它将超出范围,并且永远不会调用委托以下是我在项目中使用的代码,以防万一这是link到故事板,以防万一你想要

  7. swift 实现websocket与后台通信(swift 如何构建简单的json字符串)

    一个应用不可避免要与服务器进行通信,主要有,http与socket。http暂时不论,我们先看看socket下面衍生的websocket,今天我就把自己怎么利用websocket与服务器进行交互记录下来:首先你需要集成websocket到自己的项目,如果不明白如何集成,请看上一篇《swift集成websocket库》集成websocket到自己项目后还需要添加SwiftyJSON到自己项目,具体步骤和集成websocket一样。首先打开你项目,记得通过cocoapods生成的.xcworkspace文件打

  8. 如何在Android上托管REST webservices?

    有没有人知道一个用Java编写的能够在Android上托管REST服务的开源Web服务器?

  9. android – WebSocket没有关闭重装应用程序(React Native)

    附:哦,我用Android进行测试.解决方法你的代码看起来不错.通过刷新你的意思是在调试模式下运行时刷新javascript?

  10. android – 移动设备上的WebSocket支持

    对于Android多人游戏的玩家之间的通信,我正在使用WebSocket服务器和客户端的TooTallNate’sJavalibrary,以在Android应用程序中启用WebSocket支持.所以只是要明确指出,移动浏览器中的WebSocket支持对我来说并不重要.不幸的是,用户报告说他们遇到了连接失败或未接收消息等问题.这是移动设备上WebSockets的一般问题,还是客户端代码中的一个缺陷?您是否具有WebSocket客户端库的经验,例如上面的那个?WebSocket技术不是完全正确的解决方案,因此

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部