[实战]Springboot与GB28181摄像头对接。摄像头注册上线(一)

与支持国标摄像头对接

  • 前言:不想看教程?
  • 1、准备阶段
    • 1.1、我们会学到什么?
    • 1.2、创建项目
    • 1.3、pom中用到的依赖
    • 1.4 打开摄像头的网址(了解配置方式)
  • 2、代码编写
    • 2.1、增加项目配置
    • 2.2、在config目录下创建SipConfig
    • 2.3、在service目录下创建SipService
    • 2.4、在adapter目录下创建如下类
    • 2.5、在listener准备如下类
    • 2.7、准备基础的枚举类(enums目录下)
  • 3、按照项目配置摄像头的SIP
  • 4、启动项目

前言:不想看教程?

   想直接拿源码?Qq:1101165230

1、准备阶段

  电脑和idea这个肯定是要准备的,然后准备几台(或一台)支持国标对接的摄像头。要知道摄像头的访问地址账号和密码。

1.1、我们会学到什么?

   在这个项目中我们会用到一些设计模式以及一些注解平时可能不太常用的注解。我们还额外的知道了与物联网相关的一些对接知识。(文章中可能更多的是代码上的,为了便于大家直接CV。对于理论知识的大家可以私我,我可以出一期视频讲解这个项目)

1.2、创建项目

  我们在这里创建的是一个WebFlux的项目,便须后期处理设备的命令。
结构如下:(ps: 在idea的Terminal中输入tree或者tree -f,-f会包含目录下文件名)

<!--打印目录-->
tree
<!--打印目录带文件-->
tree -f
<!--将目录输出到文件并保存-->
tree /f >> D:/tree.txt
gb28181-sg
│
├─src
│  ├─main
│  │  ├─java
│  │  │  └─org
│  │  │      └─ougnuhs
│  │  │          └─gb
│  │  │              │  GbApplication.java 
│  │  │              ├─adapter
│  │  │              ├─config 
│  │  │              ├─controller     
│  │  │              ├─enums
│  │  │              │  └─base        
│  │  │              ├─listener    
│  │  │              ├─service     
│  │  │              └─utils                   
│  │  └─resources         
│  └─test
│      └─java
└─target

1.3、pom中用到的依赖

 &emsp(这里只放了dependencies)SIP依赖特别需要。

 <dependencies><!-- SpringBoot 核心包 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><artifactId>spring-boot-starter-logging</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--SIP--><!-- sip协议栈 --><dependency><groupId>javax.sip</groupId><artifactId>jain-sip-ri</artifactId><version>1.3.0-91</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!-- 引入log4j2依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency></dependencies>

1.4 打开摄像头的网址(了解配置方式)

这里大家先看一下,熟悉摄像头配置位置,不用填写。
找到如图位置
我这里用的是海康摄像头,摄像头的网页配置地址就是摄像头的ip地址。我们可以看到在平台接入的地方需要填写SIP的一些信息,以及提供服务的ip。
红框里的就是我们在项目中的
这个是我之前配置过的,对于新摄像头可能没有,不过没关系,我们在项目中配置成什么这里就填写成什么即可。

2、代码编写

2.1、增加项目配置

  在前面我们创建好了项目,并知道了摄像头SIP的配置位置。接着我们在application.yml文件中增加我们的sip配置。
application.yml

server:port: 8087sip:ip: 192.168.20.78port: 5060id: 34020000002000000001domain: 3402000000password: sg@123456

2.2、在config目录下创建SipConfig

  需要在config目录下创建。


import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;/*** @author by Guoshun* @version 1.0.0* @description SipConfig* @date 2024/3/22 10:44*/
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = SipConfig.SIP)
public class SipConfig {public static final String SIP = "sip";/*** 默认使用 0.0.0.0*/private String monitorIp = "0.0.0.0";private String ip;private Integer port;private String id;private String password;private String domain;}

2.3、在service目录下创建SipService


import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import lombok.extern.slf4j.Slf4j;
import org.ougnuhs.gb.config.SipConfig;
import org.ougnuhs.gb.listener.MySipListener;
import org.ougnuhs.gb.utils.SIPDefaultProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;import javax.sip.*;
import java.util.Properties;/*** @author by Guoshun* @version 1.0.0* @description SipService need SipConfig* @date 2024/3/22 11:02*/
@Slf4j
@Configuration
public class SipService {@Autowiredprivate SipConfig sipConfig;@Autowiredprivate MySipListener mySipListener;private SipFactory sipFactory;private SipStackImpl sipStack;@Bean("sipFactory")SipFactory createSipFactory(){sipFactory = SipFactory.getInstance();sipFactory.setPathName("gov.nist");return sipFactory;}@Bean("sipStack")@DependsOn("sipFactory")SipStackImpl createSipStackImpl() throws PeerUnavailableException {Properties sipProperties = SIPDefaultProperties.getSipProperties(sipConfig.getMonitorIp(), false);sipStack =(SipStackImpl) sipFactory.createSipStack(sipProperties);return sipStack;}/*** 监听TCP 对于产生的异常需要在这个地方处理* @return* @throws Exception*/@Bean("tcpSipProvider")@DependsOn("sipStack")public SipProviderImpl startTcpListener() throws Exception {// 创建SIP Provider并绑定到SIP StackListeningPoint lp = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "TCP");SipProviderImpl sipProvider = (SipProviderImpl)sipStack.createSipProvider(lp);// 注册SIP ServletsipProvider.addSipListener(mySipListener);log.info("TCP Start SUCCESS");return sipProvider;}/*** 监听TCP 对于产生的异常需要在这个地方处理* @return* @throws Exception*/@Bean("udpSipProvider")@DependsOn("sipStack")public SipProviderImpl startUdpListener() throws Exception {// 创建SIP Provider并绑定到SIP StackListeningPoint lp = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP");SipProviderImpl sipProvider =  (SipProviderImpl)sipStack.createSipProvider(lp);// 注册SIP ServletsipProvider.addSipListener(mySipListener);log.info("UDP Start SUCCESS");return sipProvider;}}

2.4、在adapter目录下创建如下类

import org.springframework.beans.factory.InitializingBean;import javax.sip.RequestEvent;/*** @author by Guoshun* @version 1.0.0* @description SIP事件处理接口* @date 2024/3/22 13:59*/
public interface ISIPEventHandler extends InitializingBean {/*** 事件处理方法* @param requestEvent*/void process(RequestEvent requestEvent);}
@Slf4j
public class SIPFactory {public static Map<String, ISIPEventHandler> requestHandlerMap = new ConcurrentHashMap<>();public static void register(String key, ISIPEventHandler handler){if(!StringUtils.hasText(key) || ObjectUtils.isEmpty(handler)){log.info("error: key or handler is null");return;}requestHandlerMap.put(key, handler);log.info("id:{}, handler:{}, register success", key, handler );}public static ISIPEventHandler getInvokeStrategy(String key) throws NoSuchMethodException {if(!requestHandlerMap.containsKey(key)){throw new NoSuchMethodException("未找到执行该方法的策略 key: " + key);}return requestHandlerMap.get(key);}
}
package org.ougnuhs.gb.adapter;import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.stack.SIPServerTransactionImpl;
import lombok.extern.slf4j.Slf4j;
import org.ougnuhs.gb.enums.TransportTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;import javax.sip.*;
import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;/*** @author by Guoshun* @version 1.0.0* @description 模板方法* @date 2024/3/22 16:43*/
@Slf4j
public abstract class SIPRequestProcessorParent {@Autowired@Qualifier(value="tcpSipProvider")private SipProviderImpl tcpSipProvider;@Autowired@Qualifier(value="udpSipProvider")private SipProviderImpl udpSipProvider;/*** 根据 RequestEvent 获取 ServerTransaction* @param evt* @return*/public ServerTransaction getServerTransaction(RequestEvent evt) {Request request = evt.getRequest();SIPServerTransactionImpl serverTransaction = (SIPServerTransactionImpl)evt.getServerTransaction();// 判断TCP还是UDPboolean isTcp = transportTypeIsTcp(request);if (serverTransaction != null && serverTransaction.getOriginalRequest() == null) {serverTransaction.setOriginalRequest((SIPRequest) evt.getRequest());}if (serverTransaction == null) {try {if (isTcp) {SipStackImpl stack = (SipStackImpl)tcpSipProvider.getSipStack();serverTransaction = (SIPServerTransactionImpl) stack.findTransaction((SIPRequest)request, true);if (serverTransaction == null) {serverTransaction = (SIPServerTransactionImpl)tcpSipProvider.getNewServerTransaction(request);}} else {SipStackImpl stack = (SipStackImpl)udpSipProvider.getSipStack();serverTransaction = (SIPServerTransactionImpl) stack.findTransaction((SIPRequest)request, true);if (serverTransaction == null) {serverTransaction = (SIPServerTransactionImpl)udpSipProvider.getNewServerTransaction(request);}}} catch (TransactionAlreadyExistsException e) {log.error(e.getMessage());} catch (TransactionUnavailableException e) {log.error(e.getMessage());}}return serverTransaction;}/*** 判断通讯的方式是TCP吗* @param request* @return*/private boolean transportTypeIsTcp(Request request){ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);String transport = reqViaHeader.getTransport();log.info("通讯方式是:{}", transport);return transport.equalsIgnoreCase(TransportTypeEnum.TCP.getValue());}//FIXME 在SipService中不是有一个这个对象吗?public MessageFactory getMessageFactory() {try {return SipFactory.getInstance().createMessageFactory();} catch (PeerUnavailableException e) {e.printStackTrace();}return null;}}
package org.ougnuhs.gb.adapter;import gov.nist.javax.sip.RequestEventExt;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import gov.nist.javax.sip.clientauthutils.DigestServerAuthenticationHelper;
import lombok.extern.slf4j.Slf4j;
import org.ougnuhs.gb.config.SipConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.header.AuthorizationHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;/*** @author by Guoshun* @version 1.0.0* @description 提供注册事件的处理器* TODO 返回Response; 以及错误信息返回需要统一,不能随便写返回的错误!* @date 2024/3/22 14:17*/
@Slf4j
@Component
public class SIPRegisterEventHandler extends SIPRequestProcessorParent implements ISIPEventHandler {@Autowiredprivate SipConfig sipConfig;private static final String KEY = "REGISTER";private Response response;@Overridepublic void afterPropertiesSet() throws Exception {SIPFactory.register(KEY, this);}@Overridepublic void process(RequestEvent requestEvent) {RequestEventExt requestEventExt = (RequestEventExt) requestEvent;String ipAddress = requestEventExt.getRemoteIpAddress() + ":" + requestEventExt.getRemotePort();log.info("ipAddress:{}", ipAddress);//取出request对象Request request = requestEventExt.getRequest();//FromHeaderfromHeader(request);//AuthorizationHeaderauthorizationHeader(request);//ExpiresHeaderexpiresHeader(request);//ViaHeaderviaHeader(request);//TODO 假设一切都ok。我们直接进行回复成功try {response = getMessageFactory().createResponse(Response.OK, request);sendResponse(requestEvent, response);}catch (ParseException parseException){parseException.printStackTrace();log.error("SIPRegisterEventHandler createResponse fail");}}/*** 注册参数-主要是为了拿到SIP用户名,这个用户不能重复,如果平台需要级联多个摄像头,该SIP必须唯一* deviceId 对应的就是SIP用户名* @param request*/private void fromHeader(Request request){FromHeader fromHeader =(FromHeader) request.getHeader(FromHeader.NAME);AddressImpl addressImpl = (AddressImpl) fromHeader.getAddress();SipUri sipUri = (SipUri)addressImpl.getURI();String deviceId = sipUri.getUser();log.info("fromHeader:{} \t addressImpl:{} \t sipUrl:{} \t deviceId:{}",fromHeader, addressImpl, sipUri, deviceId);}/*** 携带参数* @param request*/private void expiresHeader(Request request){ExpiresHeader expiresHeader =(ExpiresHeader) request.getHeader(ExpiresHeader.NAME);if(ObjectUtils.isEmpty(expiresHeader)){log.error("[注册请求] {}", Response.BAD_REQUEST);return;}if(expiresHeader.getExpires() == 0){log.error("[注册请求] 用户申请注销!");return;}else{log.info("[注册请求] 用户申请注册!");//TODO 放入数据库}log.info("expiresHeader:{}", expiresHeader);}/*** 口令密码等信息* @param request*/private void authorizationHeader(Request request) {AuthorizationHeader authorizationHeader =(AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);if (ObjectUtils.isEmpty(authorizationHeader) && ObjectUtils.isEmpty(sipConfig.getPassword())){log.error("[注册请求] 未携带授权");return;}try{boolean passwordCorrect = ObjectUtils.isEmpty(sipConfig.getPassword()) ||new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, sipConfig.getPassword());if(!passwordCorrect){log.error("[注册请求] 密码/SIP服务器ID错误, 回复403");return;}}catch (NoSuchAlgorithmException e){log.error("[注册请求] 验证授权发生错误!");return;}log.info("authorizationHeader:{}", authorizationHeader.toString());}/*** 主要用来查看是UDP还是TCP传输* @param request*/private void viaHeader(Request request){ViaHeader viaHeader =(ViaHeader) request.getHeader(ViaHeader.NAME);String transport = viaHeader.getTransport();log.info("viaHeader:{} \t transport:{}", viaHeader, transport);}/*** 响应回复* @param requestEvent* @param response* @throws InvalidArgumentException* @throws SipException*/private void sendResponse(RequestEvent requestEvent, Response response){ServerTransaction serverTransaction = getServerTransaction(requestEvent);if (serverTransaction == null) {log.warn("[回复失败]:{}", response);return;}try {serverTransaction.sendResponse(response);log.info("SIPRegisterEventHandler sendResponse success");}catch (InvalidArgumentException | SipException exception){exception.printStackTrace();log.error("[回复发生异常]:{}", response);}finally {if (serverTransaction.getDialog() != null) {serverTransaction.getDialog().delete();}}}}

2.5、在listener准备如下类

import javax.sip.SipListener;/*** @author by Guoshun* @version 1.0.0* @description MySipService 继承 SipListener* @date 2024/3/22 11:14*/
public interface MySipListener extends SipListener {
}
import lombok.extern.slf4j.Slf4j;
import org.ougnuhs.gb.adapter.SIPFactory;
import org.springframework.stereotype.Service;import javax.sip.*;/*** @author by Guoshun* @version 1.0.0* @description IMySipService 实现 MySipService* @date 2024/3/22 11:16*/
@Slf4j
@Service
public class MySipListenerImpl implements MySipListener{/*** 摄像头上报事件* @param requestEvent*/@Overridepublic void processRequest(RequestEvent requestEvent) {String method = requestEvent.getRequest().getMethod();try {SIPFactory.getInvokeStrategy(method).process(requestEvent);}catch (Exception e){log.error("processRequest error", e);}}@Overridepublic void processResponse(ResponseEvent responseEvent) {log.info("processResponse");}@Overridepublic void processTimeout(TimeoutEvent timeoutEvent) {log.info("processTimeout");}@Overridepublic void processIOException(IOExceptionEvent exceptionEvent) {log.info("processIOException");}@Overridepublic void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {log.info("processTransactionTerminated");}@Overridepublic void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {log.info("processDialogTerminated");}
}

2.7、准备基础的枚举类(enums目录下)

/*** @author by Guoshun* @version 1.0.0* @description 传输方式类型* @date 2024/3/27 9:52*/
public enum TransportTypeEnum implements BaseEnum {TCP("TCP"),UDP("UDP");private String value;TransportTypeEnum(String value) {this.value = value;}public String getValue() {return value;}@Overridepublic String getName() {return null;}public void setValue(String value) {this.value = value;}
}
/*** @author by Guoshun* @version 1.0.0* @description 枚举基类 TODO 没有增加反序列化* @date 2024/3/27 9:54*/
public interface BaseEnum {Object getValue();default String getText() {return null;}String getName();/*** 根据枚举value生成枚举* @author liyuanxi* @date 2019/4/17 11:47*/static <E extends Enum<E> & BaseEnum> E valueOf(Object value, Class<E> clazz) {E em;E[] enums = clazz.getEnumConstants();String enumName = null;for (BaseEnum e : enums) {if (e.getValue().equals(value)) {enumName = e.getName();}}if (null != enumName) {em = Enum.valueOf(clazz, enumName);} else {throw new RuntimeException(value + "未匹配上对应的枚举");}return em;}/*** 根据枚举name生成枚举类型* @author liyuanxi* @date 2019/4/17 11:47*/static <E extends Enum<E> & BaseEnum> E nameOf(String name, Class<E> clazz) {return Enum.valueOf(clazz, name);}
}

以上全部cv走。

3、按照项目配置摄像头的SIP

请按照这个配置
需要说明的是多个摄像头的话,SIP用户名请保证唯一

4、启动项目

  启动项目后,设备会自动注册上来,我方会告知他注册成功。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/776031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go通道机制与应用详解

目录 一、概述二、Go通道基础通道&#xff08;Channel&#xff09;简介创建和初始化通道通道与协程&#xff08;Goroutine&#xff09;的关联nil通道的特性 三、通道类型与操作通道类型1. 无缓冲通道 (Unbuffered Channels)2. 有缓冲通道 (Buffered Channels) 通道操作1. 发送操…

【技巧】PyTorch限制GPU显存的可使用上限

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 从 PyTorch 1.4 版本开始&#xff0c;引入了一个新的功能 torch.cuda.set_per_process_memory_fraction(fraction, device)&#xff0c;这个功能允许用户为特定的 GPU 设备设置进程可使用的显存上限比例。 测试代…

验证码demo(简单实现)

前言 我们注意到我们登录网站的时候经常会用到网络验证码,今天我们就简单实现一个验证码的前后端交互问题,做一个小demo 准备 我们这里并不需要依靠原生的java来实现,而是只需要引入一个maven依赖,使用现成的封装好的即可,这是我使用的是hutool工具包 网址:Hutool&#x1f36c;…

【前端学习——js篇】6.事件模型

具体见&#xff1a;https://github.com/febobo/web-interview 6.事件模型 ①事件与事件流 事件(Events) 事件是指页面中发生的交互行为&#xff0c;比如用户点击按钮、键盘输入、鼠标移动等。在js中&#xff0c;可以通过事件来触发相应的操作&#xff0c;例如执行函数、改变…

dump文件分析OOM及线程堆栈

OutOfMemoryError (OOM) 如果项目报错&#xff1a; OutOfMemoryError: Java heap space&#xff0c;说明堆内存空间&#xff08;Heap Space&#xff09;中没有足够的空间来分配对象了。 一旦发生 OOM&#xff0c;系统有可能不可用&#xff0c;或者频繁重启。属于非常严重的问题…

基于springboot实现校园管理系统项目【项目源码+论文说明】

基于springboot实现校园管理系统演示 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;校园管理系统当然也不能排除在外。校园管理系统是以实际运用为开发背景&#xff0c…

修改 RabbitMQ 默认超时时间

MQ客户端正常运行&#xff0c;突然就报连接错误&#xff0c; 错误信息写的很明确&#xff0c;是客户端连接超时。 不过很疑虑&#xff0c;为什么会出现连接超时呢&#xff1f;代码没动过&#xff0c;网络也ok&#xff0c;也设置了心跳和重连机制。 最终在官网中找到了答案&am…

windows-MySQL5.7安装

1.安装包下载 https://downloads.mysql.com/archives/community/&#xff08;社区版下载链接&#xff09; 选择Archives可以下载历史包&#xff0c;此处使用5.7.43 2.解压文件 解压文件到你指定安装的目录&#xff1a;解压完成后在mysql-5.7.43-winx64下新建文件my.ini和d…

企业引入“四力平衡”理念,激励员工工作积极性

—— 如何激励业务人员的工作积极性&#xff1f;【所属行业】生产制造业【问题类型】业务人员绩效考核【客户背景】J公司成立于1985年&#xff0c;目前主要从事机床、工具及相关产品的进出口贸易和国内营销业务&#xff0c;自1990年以来&#xff0c;一直属于全国最大的500家外贸…

如何备考2024年AMC10:吃透2000-2023年1250道真题(限时免费送)

有家长朋友问&#xff0c;有没有适合初中学生参加的奥数类比赛&#xff1f;我推荐AMC10美国数学竞赛&#xff0c;在国内可以方便地参加&#xff0c;而且每年全国各省市参加的初中生越来越多。关于AMC10详细的介绍和常见问题解答&#xff0c;可以联系我获得。 那么如何在AMC10竞…

正大国际:黄金投资稳定与保值的避险之选

黄金作为备受投资者追捧的贵金属&#xff0c;在金融市场中扮演着重要的角色。黄金作为一种避险资产具有稳定性和保值特性&#xff0c;能够在市场动荡时提供投资者的资金保护&#xff0c; 正大召煮4/26/12 xiaoccsw 避险需求:当股票市场、货币市场或其他资产类别表现不佳时&a…

浅谈交直流混合微电网能量管理系统关键技术研究综述

摘要&#xff1a;为了提升交直流混合微电网健康有效发展&#xff0c;提高直流互联微电网中分布式电源的能源使用效率&#xff0c;提升区域微电网稳定发展&#xff0c;对交直流混合微电网能量管理系统关键技术进行分析和研究很有必要。文章主要从交直流混合微电网能量管理系统架…

LEETCODE 44. 反转字符串

class Solution { public:void swap(int l,int r,vector<char>& s){char tmps[l];s[l]s[r];s[r]tmp;}void reverseString(vector<char>& s) {int left0;int rights.size()-1;while(left<right){swap(left,right,s);left1;right-1;}} };

印度尼西亚国家出口发展局局长一行莅临锐捷网络,共话数字经济未来

第四届中国跨境电商交易会举办期间,印度尼西亚国家出口发展局局长迪迪苏梅迪一行莅临锐捷网络参观交流,宣传推介印度尼西亚市场资源,挖掘中印尼双方企业合作机遇。福州市商务局副局长潘文等领导共同参与活动。锐捷网络副总裁、数据中心事业部总经理林东豪接待。 印度尼西亚国家…

cesium加载.tif格式文件

最近项目中有需要直接加载三方给的后缀名tif格式的文件 <script src"https://cdn.jsdelivr.net/npm/geotiff"></script> 或者 yarn add geotiff npm install geotiff 新建tifs.js import GeoTIFF, { fromBlob, fromUrl, fromArrayBuffer } from geotif…

HBase的Python API(happybase)操作

一、Windows下安装Python库&#xff1a;happybase pip install happybase -i https://pypi.tuna.tsinghua.edu.cn/simple 二、 开启HBase的Thrift服务 想要使用Python API连接HBase&#xff0c;需要开启HBase的Thrift服务。所以&#xff0c;在Linux服务器上&#xff0c;执行如…

香港高才通计划abc类的申请材料各不同,附官方续签攻略!

香港高才通计划abc类的申请材料各不同&#xff0c;附官方续签攻略&#xff01; 作为香港“史上最快获批签证”&#xff0c;高才通计划受到内地精英的热烈欢迎&#xff0c;香港高才通于2022年12月28日开放申请&#xff0c;截至2023年12月31日&#xff0c;香港高才通计划已接获62…

android 11 SystemUI 状态栏打开之后的界面层级关系说明之一

比如WiFi 图标的父layout为&#xff1a; Class Name: ButtonRelativeLayout Class Name: QSTileView Class Name: TilePage Class Name: PagedTileLayout Class Name: QSPanel Class Name: NonInterceptingScrollView Class Name: QSContainerImpl Class Name: FrameLayout Cl…

37.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-解码器细化类的实现

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;36.数据解码器的…

Docker进阶:Docker-compose 实现服务弹性伸缩

Docker进阶&#xff1a;Docker-compose 实现服务弹性伸缩 一、Docker Compose基础概念1.1 Docker Compose简介1.2 Docker Compose文件结构 二、弹性伸缩的原理和实现步骤2.1 弹性伸缩原理2.2 实现步骤 三、技术实践案例3.1 场景描述3.2 配置Docker Compose文件3.3 使用 docker-…