SpringBoot-WebSocket

SpringBoot整合WebSocket服务 springboot整合websocket springboot使用websocket springboot使用websocket 仅使用 SpringBoot封装好的服务,并不是使用第三方Netty或者: 底层使用实现: 底层使用Netty实现(没有使用过,不知道具体)官方文档1官方文档2。 阅读详情
  1. Vue
    1. wsUrl:
    2. Sec-WebSocket-Protocol:
    3. webSocket = new WebSocket(wsUrl, Sec-WebSocket-Protocol)
    4. webSocket.onopen = function(){}
    5. webSocket.onmessage = function(){}
    6. webSocket.onclose = function(){}
    7. webSocket.onerror = function(){}
    8. heartCheck
  2. Nginx
    http {
    
        upstream branchBackup {
            server 117.51.156.xxx:18081;
            server 117.51.156.xxx:28081 backup;
        }
    
        #后端平台管理系统接口
        location ^~ /branch/api-v1/ws/ {
            proxy_pass http://branchBackup;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_read_timeout 86400s;
            proxy_send_timeout 86400s;
        }
    }

     

  3. ApplicationContext发布通知事件
    1. 发布事件
      applicationContext.publishEvent(new ServiceNonstandardCheckEvent(this, id, checkStatus, serviceNonstandardEntity.getOperatorId()));

       

    2. 定义事件实体类(继承ApplicationEvent)
      package com.das.listener.event.notification;
      
      import lombok.Getter;
      import lombok.Setter;
      import org.springframework.context.ApplicationEvent;
      
      /**
       * @Author liangmy
       * @Description:
       * @Create: 2021/1/19 上午11:26
       */
      @Getter
      @Setter
      public class ServiceNonstandardCheckEvent extends ApplicationEvent {
          /**
           * 询价服务唯一标志
           */
          private Long serviceNonstandardId;
          /**
           * 询价服务审核操作
           * true :审核通过
           * false : 审核拒绝
           */
          private Boolean checkStatus;
          /**
           * 通知接收账号唯一标志
           */
          private Long systemUserId;
      
      
          /**
           * Create a new ApplicationEvent.
           *
           * @param source the object on which the event initially occurred (never {@code null})
           */
          public ServiceNonstandardCheckEvent(Object source) {
              super(source);
          }
      
          public ServiceNonstandardCheckEvent(Object source, Long serviceNonstandardId, Boolean checkStatus, Long systemUserId) {
              super(source);
              this.serviceNonstandardId = serviceNonstandardId;
              this.checkStatus = checkStatus;
              this.systemUserId = systemUserId;
          }
      }
      

       

    3. 定义事件监听者(实现ApplicationListener<ApplicationEvent>)
      package com.das.listener.notification;
      
      import com.alibaba.fastjson.JSON;
      import com.das.common.constant.EtcConstant;
      import com.das.common.constant.RedisPrefixConstant;
      import com.das.entity.system.NotificationEntity;
      import com.das.listener.event.notification.ServiceNonstandardCheckEvent;
      import com.das.service.notification.NotificationServiceManager;
      import com.das.service.redis.RedisService;
      import com.das.thirdParty.tim.TimService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.ApplicationListener;
      import org.springframework.stereotype.Component;
      
      /**
       * @Author liangmy
       * @Description:
       * @Create: 2021/1/19 上午11:33
       */
      @Slf4j
      @Component
      public class ServiceNonstandardCheckListener implements ApplicationListener<ServiceNonstandardCheckEvent> {
      
      
          @Autowired
          private NotificationServiceManager notificationServiceManager;
          @Autowired
          private RedisService redisService;
          @Autowired
          private TimService timService;
      
      
          @Override
          public void onApplicationEvent(ServiceNonstandardCheckEvent event) {
              // 1. 持久化通知信息
              log.info("saveNotificationAndReceiverForServiceNonstandarCheck(Long serviceNonstandardId, Boolean checkStatus, Long systemUserId) : {}, {}, {}", event.getServiceNonstandardId(), event.getCheckStatus(), event.getSystemUserId());
              Long notificationId = notificationServiceManager.saveNotificationAndReceiverForServiceNonstandarCheck(event.getServiceNonstandardId(), event.getCheckStatus(), event.getSystemUserId());
              if (EtcConstant.assertLegalParam(notificationId)) {
                  // 2. 发布消息到 serviceNonstandarCheck 频道
                  NotificationEntity notificationEntity = new NotificationEntity();
                  notificationEntity.setId(notificationId);
                  log.info("convertAndSend(RedisPrefixConstant.SubcribeTopic.serviceNonstandarCheck : {}", JSON.toJSONString(notificationEntity));
                  redisService.convertAndSend(RedisPrefixConstant.SubcribeTopic.serviceNonstandarCheck, notificationEntity);
                  // 3. 发布消息到 IM
                  log.info("sendmsgForServiceNonstandardCheck(Long systemUserId, Long serviceNonstandardId, Boolean checkStatus) : {}, {}, {}", event.getSystemUserId(), event.getServiceNonstandardId(), event.getCheckStatus());
                  timService.sendmsgForServiceNonstandardCheck(event.getSystemUserId(), event.getServiceNonstandardId(), event.getCheckStatus());
              }
          }
      }
      

       

      1. 持久化通知信息
        1. 定义通知信息Subjoin类
          package com.das.entity.system.notification;
          
          import lombok.Getter;
          import lombok.Setter;
          
          /**
           * @Author liangmy
           * @Description:
           * @Create: 2021/1/19 下午2:04
           */
          @Getter
          @Setter
          public class NotificationSubjoinServiceNonstandardCheckEntity {
          
              /**
               * 询价服务唯一标志
               */
              private Long serviceNonstandardId;
              /**
               * 询价服务审核状态
               * true : 审核通过
               * false : 审核拒绝
               */
              private Boolean checkStatus;
              /**
               * 询价服务创建人账号标志
               */
              private Long operatorId;
          
          
          }
          

           

        2. 持久化通知信息逻辑
          /**
               * 持久化通知及通知接收人,并返回通知id(询价服务审核通过/审核拒绝)
               *
               * @param serviceNonstandardId
               * @param checkStatus
               * @param systemUserId         接收通知账号唯一标志
               * @return
               */
              @Override
              public Long saveNotificationAndReceiverForServiceNonstandarCheck(Long serviceNonstandardId, Boolean checkStatus, Long systemUserId) {
                  if (!EtcConstant.assertLegalParam(serviceNonstandardId) || null == checkStatus) {
                      throw DasException.internalError(null, messageSource.getMessage(EtcConstant.MessageCode.param_missing, null, LocaleContextHolder.getLocale()));
                  }
                  NotificationEntity notificationEntity = new NotificationEntity();
          
                  notificationEntity.setType(NotificationTypeEnum.SERVICE_NONSTANDAR_CHECK);
          
                  notificationEntity.setContent(EtcConstant.WsMessage.NotificationConstant.content_service_nonstandar_check);
                  NotificationSubjoinServiceNonstandardCheckEntity notificationSubjoinServiceNonstandardCheckEntity = new NotificationSubjoinServiceNonstandardCheckEntity();
                  notificationSubjoinServiceNonstandardCheckEntity.setServiceNonstandardId(serviceNonstandardId);
                  notificationSubjoinServiceNonstandardCheckEntity.setCheckStatus(checkStatus);
                  notificationEntity.setSubjoin(JSON.toJSONString(notificationSubjoinServiceNonstandardCheckEntity));
                  notificationMapper.save(notificationEntity);
          
                  List<NotificationReceiverEntity> notificationReceiverEntityList = new LinkedList<>();
          
                  NotificationReceiverEntity notificationReceiverEntity = new NotificationReceiverEntity();
                  notificationReceiverEntity.setNotificationId(notificationEntity.getId());
                  SystemUserEntity systemUserEntity = systemUserService.getSysUser(systemUserId);
                  if (null == systemUserEntity) {
                      throw DasException.notAllowed(null, messageSource.getMessage(EtcConstant.MessageCode.system_user_not_exist, null, LocaleContextHolder.getLocale()));
                  }
                  String receiverKey = EtcConstant.getKey(systemUserId, systemUserEntity.getStoreBaseId());
                  notificationReceiverEntity.setReceiverKey(receiverKey);
          
                  notificationReceiverEntityList.add(notificationReceiverEntity);
          
                  notificationReceiverMappper.saveBatch(notificationReceiverEntityList);
                  return notificationEntity.getId();
              }

           

      2. 发布消息到指定频道
        1. 定义Redis 发布订阅频道
              /**
               * Redis 发布订阅频道
               */
              public static class SubcribeTopic {
                  public static final String completeWork = "channel:ws:completeWork";
                  public static final String serviceNonstandarCheck = "channel:ws:serviceNonstandarCheck";
                  public static final String appointmentService = "channel:ws:appointmentService";
                  public static final String carPlanRemind = "channel:ws:carPlanRemind";
              }

           

        2. 发布消息到 serviceNonstandarCheck 频道
                      NotificationEntity notificationEntity = new NotificationEntity();
                      notificationEntity.setId(notificationId);
                      redisService.convertAndSend(RedisPrefixConstant.SubcribeTopic.serviceNonstandarCheck, notificationEntity);

           

  4. Redis 发布订阅模式

    1. 定义观察者RedisReceiver(实现org.springframework.data.redis.connection.MessageListener)
      package com.das.listener.redis;
      
      import com.alibaba.fastjson.JSON;
      import com.das.common.constant.EtcConstant;
      import com.das.common.constant.RedisPrefixConstant;
      import com.das.entity.system.NotificationEntity;
      import com.das.mapper.system.NotificationMapper;
      import com.das.service.ws.WsMessageService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.ApplicationContext;
      import org.springframework.data.redis.connection.Message;
      import org.springframework.data.redis.connection.MessageListener;
      import org.springframework.stereotype.Component;
      import org.springframework.util.CollectionUtils;
      
      import java.util.LinkedList;
      import java.util.List;
      import java.util.concurrent.TimeUnit;
      
      /**
       * @Author liangmy
       * @Description:
       * @Create: 2020/11/4 下午7:35
       */
      @Slf4j
      @Component
      public class RedisReceiver implements MessageListener {
      
          @Autowired
          private ApplicationContext applicationContext;
          @Autowired
          private NotificationMapper notificationMapper;
          @Autowired
          private WsMessageService wsMessageService;
      
      
          @Override
          public void onMessage(Message message, byte[] bytes) {
              String channel = new String(message.getChannel());
              String body = new String(message.getBody());
              log.info("message.getChannel():{}", channel);
              log.info("message.getBody():{}", body);
              log.info("term:{}", EtcConstant.notificationTerm);
              body = body.substring(1, body.length() - 1);
              log.info("message.getBody():{}", body);
              NotificationEntity notificationEntity = JSON.parseObject(body, NotificationEntity.class);
              log.info("message.getBody()::parseObject:{}", JSON.toJSONString(notificationEntity));
              log.info("notificationEntity.getId() : {}", notificationEntity.getId());
              List<NotificationEntity> notificationEntityPushList = notificationMapper.getNotificationEntityPushList(notificationEntity.getId());
              for (int i = 0; CollectionUtils.isEmpty(notificationEntityPushList) && i < 5; i++) {
                  log.info("notificationMapper.getNotificationEntityPushList(notificationEntity.getId()) is empty, try again. times : {}. notificationEntity.getId() : {}", i, notificationEntity.getId());
                  try {
                      TimeUnit.SECONDS.sleep(2);
                  } catch (InterruptedException e) {
                      log.info("notificationMapper.getNotificationEntityPushList(notificationEntity.getId()) sleep Interrupted. notificationEntity.getId() : {}", notificationEntity.getId());
                  }
                  notificationEntityPushList = notificationMapper.getNotificationEntityPushList(notificationEntity.getId());
              }
              List<String> alarmCountMessageOperatorKeyList = new LinkedList<>();
      
              switch (channel) {
                  case RedisPrefixConstant.SubcribeTopic.completeWork:
                  case RedisPrefixConstant.SubcribeTopic.appointmentService:
                  case RedisPrefixConstant.SubcribeTopic.carPlanRemind:
                  case RedisPrefixConstant.SubcribeTopic.serviceNonstandarCheck:
                      log.info("推送通知:{}", JSON.toJSONString(notificationEntityPushList));
                      wsMessageService.pushNotificationList(notificationEntityPushList);
                      for (NotificationEntity notificationEntityAlarmCount : notificationEntityPushList) {
                          alarmCountMessageOperatorKeyList.add(notificationEntityAlarmCount.getReceiverKey());
                      }
                      wsMessageService.pushAlarmCountMessageList(alarmCountMessageOperatorKeyList);
                      log.info("推送通知数量:{}", JSON.toJSONString(alarmCountMessageOperatorKeyList));
                      break;
                  default:
                      break;
              }
          }
      }
      

       

      1. 推送通知
            @Override
            public void pushNotificationList(List<NotificationEntity> notificationEntityPushList) {
                WsMessageEntity wsMessageEntity = null;
                for (NotificationEntity notificationEntity : notificationEntityPushList) {
                    String receiverKey = notificationEntity.getReceiverKey();
                    log.info("推送通知。获取接受人:{}", receiverKey);
        
                    if (StringUtils.isBlank(receiverKey)) {
                        continue;
                    }
                    log.info("推送通知。获取通知类型:{}", notificationEntity.getType());
                    notificationEntity.setTypeDesc(littleBear.getEnumValue(notificationEntity.getType()));
        
                    log.info("parse Notification::subjoin : {}", notificationEntity.getSubjoin());
                    switch (notificationEntity.getType()) {
                        case SERVICE_NONSTANDAR_CHECK:
                            String downloadUrl = "";
                            NotificationSubjoinServiceNonstandardCheckEntity notificationSubjoinServiceNonstandardCheckEntity = JSON.parseObject(notificationEntity.getSubjoin(), NotificationSubjoinServiceNonstandardCheckEntity.class);
                            if (null != notificationSubjoinServiceNonstandardCheckEntity) {
                                SystemUserEntity systemUserEntity = systemUserMapper.getById(notificationSubjoinServiceNonstandardCheckEntity.getOperatorId());
                                if (null != systemUserEntity) {
                                    downloadUrl = ossService.getDownloadUrl(systemUserEntity.getPortraitResourceId());
                                    notificationSubjoinServiceNonstandardCheckEntity.setOperatorImgUrl(downloadUrl);
                                }
                            }
                            notificationEntity.setOperatorImgUrl(downloadUrl);
                            notificationEntity.setSubjoin(JSON.toJSONString(notificationSubjoinServiceNonstandardCheckEntity));
                            notificationEntity.setSubjoinEntity(notificationSubjoinServiceNonstandardCheckEntity);
                            break;
                        default:
                            break;
                    }
                    WsMessageTermEnum term = WsMessageTermEnum.valueOf(EtcConstant.notificationTerm);
                    String receiverKeyTerm = EtcConstant.getKey(receiverKey, term);
                    wsMessageEntity = new WsMessageEntity(WsMessageTypeEnum.notify, receiverKeyTerm);
                    wsMessageEntity.setBodyClazz(notificationEntity.getClass().getName());
                    wsMessageEntity.setBody(notificationEntity);
        
                    AbstractWebSocketServer.sendMsg(receiverKeyTerm, wsMessageEntity);
                    log.info("通知推送。用户:{}, 通知:{}", receiverKeyTerm, JSON.toJSONString(wsMessageEntity));
                }
        
            }

         

      2. 推送通知数量
            @Override
            public void pushAlarmCountMessageList(List<String> alarmCountMessageOperatorKeyList) {
                for (String receiverKey : alarmCountMessageOperatorKeyList) {
                    if (StringUtils.isBlank(receiverKey)) {
                        continue;
                    }
        
                    // 所有类型通知数量
                    long getNonReadNofificationCount = notificationMapper.getNonReadNofificationCount(receiverKey);
        
                    WsMessageTermEnum term = WsMessageTermEnum.valueOf(EtcConstant.notificationTerm);
                    String receiverKeyTerm = EtcConstant.getKey(receiverKey, term);
                    WsMessageEntity wsMessageEntity = new WsMessageEntity(WsMessageTypeEnum.message, receiverKeyTerm);
        
                    wsMessageEntity.setBody(getNonReadNofificationCount);
                    wsMessageEntity.setBodyClazz(EtcConstant.WsMessage.AlarmCount);
        
                    AbstractWebSocketServer.sendMsg(receiverKeyTerm, wsMessageEntity);
                    // 各个类型通知数量
        
                    List<LabelNonReadNofificationCountDO> labelNonReadNofificationCountList = notificationMapper.getLabelNonReadNofificationCount(receiverKey);
                    Map<String, Integer> labelNonReadNofificationCount = new HashMap<>();
                    for (LabelNonReadNofificationCountDO labelNonReadNofificationCountDO : labelNonReadNofificationCountList) {
                        labelNonReadNofificationCount.put(labelNonReadNofificationCountDO.getType().name(), labelNonReadNofificationCountDO.getAmount());
                    }
        
                    wsMessageEntity.setBody(labelNonReadNofificationCount);
                    wsMessageEntity.setBodyClazz(EtcConstant.WsMessage.labelNonReadNofificationCount);
        
                    AbstractWebSocketServer.sendMsg(receiverKeyTerm, wsMessageEntity);
        
                }
            }

         

    2. RedisConfig(继承CachingConfigurerSupport)
      1. JedisPool
        1. JedisPoolConfig
              @Bean
              public JedisPool redisPoolFactory() {
                  JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
                  jedisPoolConfig.setMaxTotal(maxTotal);
                  jedisPoolConfig.setMaxIdle(maxIdle);
                  jedisPoolConfig.setMinIdle(minIdle);
                  jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
                  return new JedisPool(jedisPoolConfig, host, port, timeout, password);
              }
          

           

      2. RedisTemplate
        1. StringRedisTemplate
          private static final ObjectMapper om = new ObjectMapper();
          
          
              @Bean
              public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
                  StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(factory);
                  Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
                  om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
                  om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
                  jackson2JsonRedisSerializer.setObjectMapper(om);
                  stringRedisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
                  stringRedisTemplate.afterPropertiesSet();
                  return stringRedisTemplate;
              }
          

           

        2. Jackson2JsonRedisSerializer
                  Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
                  om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
                  om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
                  jackson2JsonRedisSerializer.setObjectMapper(om);
          

           

      3. MessageListenerAdapter
      4. RedisMessageListenerContainer
        1. MessageListener
        2. PatternTopic
  5. 定义通知推送的终端
    1. notificationTerm=mech
  6. Filter
    1. 获取WS子协议
      1. String token = request.getHeader("Sec-WebSocket-Protocol");
      2. response.setHeader("Sec-WebSocket-Protocol", token);
  7. AbstractWebSocketService
    1. javax.websocket.Session
    2. @OnOpen
    3. @OnMessage
    4. @OnError
    5. @OnClose
    6. session.getBasicRemote().sendText(String text) throws IOException;
  8. WebSocketServiceImpl
    1. @Component
    2. @ServerEndpoint(value = "/ws/imServer/{term}")
  9. 啦啦啦
Spring Boot 实现 WebSocket 示例 WebSocket协议提供了一种标准化的方法,通过单个TCP连接在客户机和服务器之间建立全双工、双向的通信通道。它是一种不同于HTTP的TCP协议,但被设计为在HTTP上工作,使用端口80和443,并允许重用现有的防火墙规则。WebSocket 协议是独立的基于 TCP 协议。它与 HTTP 的唯一关系是,它的握手会被 HTTP 服务器解释为 Upgrade 请求。 阅读详情

相关推荐

springboot整合WebSocket

springboot整合WebSocket WebSocket通信过程 客户端构建一个websocket实例,并且为它绑定一个需要连接到的服务器地址,当客户端连接服务端的候,会向服务端发送一个http get报文,告诉服务端需要将通信协议切换到websocket,服务端收到http请求后将通信协议切换到websocket,同时发给客户端一个响应报文,返回的状态码为101,表示同意客户端协议转请求,并转换为websocket协议。以上过程都是利用http通信完成的,称之为websocket协议握手(webs

weixin_43757027的博客 2万+

Spring boot Websocket 添加授权校验(校验Header)

继承ServerEndpointConfig.Configurator 并重写modifyHandshake方法,在这里拦截header中Authorization的内容,并将其设置到websocket session 中。获取之前设置入session中的Authorization信息,这里为了方便,仅仅只是校验了有没有传入,没有传入则代表校验失败。取消送入header内容Authorization时,连接先成功,后失败,则代表已经连接到服务器,但因为校验失败,被断开了连接。

Riteny的博客 5804

SpringBoot整合WebSocket遇到的坑

websocket failed: Error during WebSocket handshake: Unexpected response 1、pom.xml 中引入 spring-boot-starter-websocket <dependency> <groupId>org.springframework.boot</groupId> ...

qq_30238195的博客 2380

springboot+vue整合websocket(含鉴权)

springboot+vue+websocket 包含spring security鉴权

程序员 3873

SpringBoot整合WebSocket服务

1、前言注意: 仅使用 SpringBoot封装好的 spring-boot-starter-websocket 服务,并不是使用第三方 Netty或者 Apache MINAspring-boot-starter-web: 底层使用 Java WebSocket API (JSR-356)实现spring-boot-starter-webflux: 底层使用 Netty实现(没有使用过,不知道具体)官方文档1官方文档22、开始使用2.1、加入Maven依赖。

2403_88533107的博客 5739

websocket-protocol:websocket协议

近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。 轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服

【websocket】使用websocket实现springboot与浏览器的通信

网上翻了很多介绍的使用方法都是没有请求头条件下使用的,但是为了安全问题一般都会加上请求头进行验证,这是携带token进行连接的方法

游码客的博客 2261

命令行删除描述文件_写一个删除lock文件的skill脚本

来源:IC技能搬运工 作者:小目Cadence软件使用过程中偶尔会遇到文件被lock的情况,这是Cadence软件对文件的一种保护措施,大部分情况都是对用户友好的,但是偶尔也会给用户带来困扰,给工作带来的一定的不便。文件是如何被锁的Cadence在用户打开文件进行编辑的时候会在文件的同一级目录新建一个lock文件,用来标识文件的状态。一般情况下如果文件被正常关闭,这个lock文件会在...

weixin_39781452的博客 1352

Spring Boot WebSocket 客户端_springboot创建websocket客户端

外链图片转存中…(img-MoMKOEeI-1712914457688)]

2401_84254364的博客 1965

IoT 平台架构全景图:从设备到 AI 的完整技术体系深度解析

随着物联网设备规模进入百万级时代,IoT 平台架构已经从简单的设备接入系统演变为完整的数据平台。本文从系统架构师视角,深度解析 IoT 平台的完整技术体系,包括设备接入、MQTT 通信、消息流平台、数据平台与 AI 决策系统,并结合主流云平台实践,构建从设备到 AI 的完整 AIoT 架构认知。

moton2017的博客 855

Keil MDK打开别人工程总报错?手把手教你修复‘找不到main.o’和‘未定义’的路径问题

本文详细解析Keil MDK工程移植时常见的'找不到main.o'和'未定义'编译错误,提供从路径修复到宏定义配置的完整解决方案。通过系统化的检查清单和预防措施,帮助开发者快速解决MDK工程迁移问题,提升嵌入式开发效率。

weixin_28724661的博客 397

spring boot学习第六篇:SpringBoot 集成WebSocket详解

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

heming20122012的专栏 5623

软件测试方法——等价类划分法详解

!如果下面这些资料用得到的话可以直接拿走:1、自学开发或者测试必备的完整项目源码与环境2、测试工作中所有模板(测试计划、测试用例、测试报告等)3、软件测试经典面试题4、Python/Java自动化测试实战.pdf5、Jmeter/postman接口测试全套视频获取6、Python学习路线图。

MXB1220的博客 1万+

Springboot集成websocket

Springboot集成websocket

囚徒之困 9460

Windows版本Carla(含RoadRunner插件)源码安装+RoadRunner地图导入

通过跳转浏览器账号密码登录github,不要选择Fine-grained personal access tokens,在git clone时会显示非授权,也不要使用Windows凭据!核心指令:编译PythonAPI–make PythonAPI,,编译Server–make launch,封装”游戏“–make package。完成安装后,在已安装->2022版本右侧->更多->导入配置,选择配置文件(需将配置文件内容更新为手册内容,如下图)->详细信息,更新。不要修改版本,执行上面指令即可!

winnizap的博客 1467

脑影像分析软件推荐 | JuSpace

JuSpace是一种允许基于 MRI 测量与核成像衍生估计的跨模态关联的工具包,它涵盖各种神经递质系统,包括多巴胺能、血清素能、去甲肾上腺素能和 GABA(γ-氨基丁酸) 神经传递。JuSpace 由一组 Matlab 功能以及涵盖各种受体系统的 PET 受体图谱组成。

NHKJ_ZF的博客 1706

SpringBoot实现WebSocket

WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议) 它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的。

山不见我,我自见山 3万+

103.在 Vue 3 中使用 OpenLayers 控制图层来显示/隐藏地图

是一个强大的开源库,可以用于构建各种地理信息系统应用。在 Vue 3 中,我们可以结合。方法,可以直接控制某个图层是否可见,而不需要删除或重新创建图层。在开始之前,确保你已经搭建了 Vue 3 项目,并安装了。本文将详细介绍如何在 Vue 3 组合式 API (,并实现按钮控制地图的显示/隐藏功能。会导致 OSM 瓦片地图无法加载。方法控制地图图层的显示与隐藏。安装完成后,即可开始编写代码。在本教程中,我们介绍了如何在。来实现地图的显示/隐藏功能。来实现交互式地图,并通过。在 WebGIS 开发中,

小彭的博客 1559

SpringBoot整合WebSocket

一、WebSocket与Http的区别 HTTP是应用层上的一个单向的、无状态的、基于请求与响应的协议。http协议本身是没有持久通信能力的,当客户端向服务器发送HTTP请求时,接收到请求后,服务器会将响应发送给客户端。每个请求都与一个对应的响应相关联,在发送响应后客户端与服务器的连接会被关闭。这种的基于请求响应的通讯方式有一点不足,服务器端无法主动向客户端推送数据。 Websocket是应用层上的一个全双工的有状态协议。websocket以ws://或wss://开头,它必须依赖 HTTP 协议进行一次

Nicholas_GUB的博客 5490

【大模型应用开发-FastAPI框架】(八)Sqlalchemy+postgresql简单增删改查

语言,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型”。SQLAlchemy的理念是,的量级和性能重要于对象集合;而对象集合的抽象又重要于表和行。因此,SQLAlchemy采用了类似于。社区中成为广泛使用的ORM工具之一,不亚于Django的ORM框架。和declarative等可选插件可以让用户使用声明语法。SQLAlchemy首次发行于2006年2月,并迅速地在。SQLAlchemy“采用简单的。二、安装postgresql。一、SQLAlchemy简介。的数据映射模型,而不是其他。

2096

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

spring boot websocket 客户端_SpringBoot集成websocket

第一种:SpringBoot官网提供了一种websocket的集成方式第二种:javax.websocket中提供了元注解的方式下面讲解简单的第二种添加依赖<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-...

weixin_39839018的博客 124

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

springboot集成websocket

​ 这里我们使用springboot搭建一个轻量级的websocket服务,同时提供4个入参。使用websocket服务可以轻松和微信小程序、支付宝小程序、网页就行双向通讯,非常实用方便。wss地址这里是我们自己搭建的中转服务websocket地址。参数说明。

大爱仙尊 3万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

spring boot 搭建websocket_WebSocket 整合 Springboot

WebSocket+Springboot1.1 pom 文件的依赖和插件<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.9.RELEASE<...

weixin_39542111的博客 326

springboot websocket 原理。

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,允许服务器和客户端之间进行实时数据交换。Spring Boot 通过集成 Spring WebSocket 模块,简化了 WebSocket 的实现。WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,允许服务器和客户端之间进行实时数据交换。Spring Boot 通过集成 Spring WebSocket 模块,简化了 WebSocket 的实现。WebSocket 协议通过 HTTP 协议升级实现。

LcL_xll7的博客 617

Springboot整合WebSocket

Springboot整合WebSocket实现点对点、订阅式消息通知,附完整源码

努力提高技术水平 1251
上一篇: CentOs中环境变量和配置文件
下一篇: MQ入门知识点集合
limeOracle
博客等级 码龄10年 11粉丝 566原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值