当前位置: 首页 > news >正文

Spring boot 整合grpc 运用

文章目录

    • GRPC基础概念:
    • Protocol Buffers:
      • proto 基础语法:
        • 调用类型:
    • Spring boot 整合 grpc
      • 项目结构:
      • 整合代码:
        • 父 pom
        • proto 模块
        • 服务端:
        • 客户端:
        • 实际调用:
      • 原生集成

GRPC基础概念:

  • GRPC是google开源的一个高性能、跨语言的RPC框架,基于HTTP2协议,基于protobuf 3.x,基于Netty 4.x.

Protocol Buffers:

  • 一个跨语言、跨平台的具有可扩展机制的序列化数据工具。也就是说,我在ubuntu下用python语言序列化一个对象,并使用http协议传输到使用java语言的android客户端,java使用对用的代码工具进行反序列化,也可以得到对应的对象
    1

proto 基础语法:

//指定proto3语法
syntax = "proto3";
//指定作用域
package xxx;
//java_multiple_files = true; 表示在生成Java代码时,每个`.proto`文件都会生成一个独立的Java文件
//声明 rpc 服务接口
//关键字: service 声明需要生成的服务接口"类"
service Greeter {// 关键字: rpc 声明服务方法,包括方法名、请求消息(请求体)、相应消息(响应体)rpc SayHello(HelloRequest) returns (HelloResponse);
}
//声明请求、响应消息
//关键字: message 声明请求体和响应体
message HelloRequest {//标识号 1//编号的范围为1 ~ 536,870,911(2^29-1),其中19000~19999不可用。因为Protobuf协议的实现过程中对预留了这些编号string name = 1;//表示一个人有多个号码repeated string phone = 3;
}message HelloResponse {string message = 1;
}
调用类型:
  • Unary RPC 一元RPC调用,也叫简单RPC调用

    rpc SayHello(HelloRequest) returns (HelloResponse);
    
  • 【服务端 Server Stream RPC】流式RPC. 客户端向服务端发送单个请求,服务端以流的方式返回一系列消息。客户端从流中读取消息,直到没有更多的消息。当然,返回的消息当然不是乱序的,gRPC保证单个请求中的消息顺序

    rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
    
  • 【客户端 Client Stream RPC】流式RPC调用。客户端向服务端请求一系列的消息,一旦客户端完成消息写入,就会等待服务端读取所有消息并处理它们。gRPC同样会保证单个请求中消息的顺序性

    rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
    
  • 【双向流式调用 Bidirectional Streaming RPC】就是客户端和服务端均以流的方式进行读写消息。这两个流式完全独立的,因此,服务端和客户端可以按照他们喜欢的方式写入和读取流。比如:服务端可以在等待所有的客户端消息发送到后,再处理;也可以交替读取请求、写入响应信息等。当然,每个流中的消息顺序是可以保证的。

    rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
    

    Channels通道

    gRPC通道提供了一条链接到指定主机和端口号的服务端的链接。他在创建客户端stub的时候使用。客户端可以指定通道参数来修改gRPC的默认行为,例如:打开或者关闭消息压缩。一个通道是有连接和空闲两个状态的

mvn 插件整合,proto编译,生成代码

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin><!-- 生成插件 --><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.5.1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.11.0:exe:${os.detected.classifier}</pluginArtifact><protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot><!--设置grpc生成代码到指定路径--><outputDirectory>${project.basedir}/src/main/java</outputDirectory><!--生成代码前是否清空目录--><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.2</version></extension></extensions></build>

在这里插入图片描述

Spring boot 整合 grpc

大致流程:
1

项目结构:

在这里插入图片描述

整合代码:

父 pom
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.17</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.xiaoshu</groupId><artifactId>grpc-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><name>grpc-demo</name><modules><module>grpc-server</module><module>grpc-client</module><module>grpc-proto</module></modules><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><grpc.version>2.15.0.RELEASE</grpc.version></properties><!-- 通用依赖 --><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>net.devh</groupId><artifactId>grpc-spring-boot-starter</artifactId><version>${grpc.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>${grpc.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>${grpc.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
proto 模块
syntax = "proto3";package com.ht.meta;
// 生成类的包名
option java_multiple_files = true;
// 生成代码位置
option java_package = "com.meta";
// 定义的所有消息、枚举和服务生成对应的多个类文件,而不是以内部类的形式出现
option java_outer_classname = "HtMetaInfoSyncProto";service HtMetaInfoSyncService {rpc syncMeta (HtMetaSyncRequest) returns (HtMetaSyncResponse) {}
}//同步类型
enum SyncType {ADD  = 0; // 新增DEL  = 1; // 删除EDIT = 2; // 修改
}//同步Request
message HtMetaSyncRequest {//json内容string syncJson = 1;//同步类型SyncType syncType = 2;
}//响应Response
message HtMetaSyncResponse {//响应码string code = 1;//提示string msg = 2;
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.xiaoshu</groupId><artifactId>grpc-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>grpc-proto</artifactId><packaging>jar</packaging><name>grpc-proto</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>net.devh</groupId><artifactId>grpc-spring-boot-starter</artifactId><version>${grpc.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin><!-- 生成插件 --><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.5.1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.11.0:exe:${os.detected.classifier}</pluginArtifact><protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot><!--设置grpc生成代码到指定路径--><outputDirectory>${project.basedir}/src/main/java</outputDirectory><!--生成代码前是否清空目录--><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.2</version></extension></extensions></build></project>
服务端:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.xiaoshu</groupId><artifactId>grpc-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>grpc-server</artifactId><packaging>jar</packaging><name>grpc-server</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>com.xiaoshu</groupId><artifactId>grpc-proto</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency></dependencies></project>
server:port: 8080spring:application:name: spring-boot-grpc-server# gRPC有关的配置,这里只需要配置服务端口号
grpc:server:port: 9898

服务端代码:

import com.meta.HtMetaInfoSyncServiceGrpc;
import com.meta.HtMetaSyncRequest;
import com.meta.HtMetaSyncResponse;
import com.meta.SyncType;
import com.util.JsonUtil;
import com.vo.HtMetaClusterInfoVo;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import java.util.List;/*** @author 何永豪* @className HtMetaSyncService* @description TODO* @date 2023/11/6 15:25*/
@Slf4j
@GrpcService
public class HtMetaSyncService extends HtMetaInfoSyncServiceGrpc.HtMetaInfoSyncServiceImplBase {@Overridepublic void syncMeta(HtMetaSyncRequest request, StreamObserver<HtMetaSyncResponse> responseObserver) {String syncJson = request.getSyncJson();log.info("接收到json:{}",syncJson);List<HtMetaClusterInfoVo> list = JsonUtil.toList(syncJson, HtMetaClusterInfoVo.class);SyncType syncType = request.getSyncType();int number = syncType.getNumber();log.info("同步类型:{}",number);HtMetaSyncResponse syncResponse = HtMetaSyncResponse.newBuilder().setCode("1000").setMsg("同步成功").build();responseObserver.onNext(syncResponse);responseObserver.onCompleted();}}
客户端:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.xiaoshu</groupId><artifactId>grpc-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>grpc-client</artifactId><packaging>jar</packaging><name>grpc-client</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>com.xiaoshu</groupId><artifactId>grpc-proto</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>${grpc.version}</version></dependency></dependencies></project>

yml

server:port: 8088spring:application:name: local-clientgrpc:client:# gRPC配置的名字,GrpcClient注解会用到local-grpc-server:# gRPC服务端地址address: 'static://127.0.0.1:9898'enableKeepAlive: truekeepAliveWithoutCalls: true#认证类型,无加密negotiationType: plaintext

客户端stub

import com.meta.HtMetaInfoSyncServiceGrpc;
import com.meta.HtMetaSyncRequest;
import com.meta.HtMetaSyncResponse;
import com.meta.SyncType;
import io.grpc.StatusRuntimeException;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Service;/*** @author xiaoshu*/
@Service
public class HtMetaInfoSyncClient {@GrpcClient("local-grpc-server")private HtMetaInfoSyncServiceGrpc.HtMetaInfoSyncServiceBlockingStub stub;public String syncMeta(final String json,final SyncType syncType) {try {HtMetaSyncResponse htMetaSyncResponse = stub.syncMeta((HtMetaSyncRequest.newBuilder().setSyncJson(json).setSyncType(syncType).build()));String code = htMetaSyncResponse.getCode();String msg = htMetaSyncResponse.getMsg();return code+":"+msg;} catch (final StatusRuntimeException e) {return "FAILED with " + e.getStatus().getCode().name();}}}
实际调用:
@Autowired
private HtMetaInfoSyncClient htMetaInfoSyncClient;@RequestMapping("/htMetaSync")
public String htMetaSync() {String json="";return htMetaInfoSyncClient.syncMeta(json, SyncType.ADD);
}

原生集成

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.14</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.xiaoshuzxc</groupId><artifactId>grpc-native-api</artifactId><packaging>jar</packaging><name>grpc-native-api</name><description>grpc原生api整合方式</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><grpc.version>1.29.0</grpc.version><proto.version>3.12.0</proto.version><netty.tcnative.version>2.0.30.Final</netty.tcnative.version></properties><dependencyManagement><dependencies><dependency><groupId>io.grpc</groupId><artifactId>grpc-bom</artifactId><version>${grpc.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.xiaoshu</groupId><artifactId>grpc-proto</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-netty</artifactId></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-tcnative-boringssl-static</artifactId><version>${netty.tcnative.version}</version><scope>runtime</scope></dependency></dependencies>
</project>
import org.springframework.stereotype.Service;
import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface GrpcService {}

启动grpc服务监听:

import com.annotation.GrpcService;
import io.grpc.BindableService;
import io.grpc.Server;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyServerBuilder;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.SslContextBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.stream.Stream;/*** @author 何永豪* @className GrpcServer* @description TODO* @date 2023/11/7 15:56*/
@Slf4j
public class GrpcServer implements CommandLineRunner, DisposableBean {private Server server;@Resourceprivate AbstractApplicationContext applicationContext;@Resourceprivate GrpcProperties grpcProperties;@Overridepublic void destroy() {stop();}@Overridepublic void run(String... args) throws Exception {start();}private SslContextBuilder getSslContextBuilder(){SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(new File(grpcProperties.getServerCertPath()), new File(grpcProperties.getServerPrivateKeyPath()));sslContextBuilder.trustManager(new File(grpcProperties.getServerTrustCertPath()));sslContextBuilder.clientAuth(ClientAuth.REQUIRE);return GrpcSslContexts.configure(sslContextBuilder);}private void start() throws IOException {NettyServerBuilder nettyServerBuilder = NettyServerBuilder.forPort(grpcProperties.getPort());
//                .sslContext(getSslContextBuilder().build()
//                        );scanBeanWithAnnotation(GrpcService.class, BindableService.class).forEach(e->{BindableService bindableService = applicationContext.getBeanFactory().getBean(e, BindableService.class);nettyServerBuilder.addService(bindableService.bindService());});server = nettyServerBuilder.build().start();log.info("grpc start listen {}",grpcProperties.getPort());Thread thread = new Thread(() -> {try {GrpcServer.this.blockUntilShutdown();} catch (InterruptedException e) {log.error("grpc server stopped");throw new RuntimeException(e);}});thread.setDaemon(false);thread.start();}private void stop(){if (server !=null){server.shutdown();}}private void blockUntilShutdown() throws InterruptedException {if (server !=null ){server.awaitTermination();}}private <T> Stream<String> scanBeanWithAnnotation(Class<? extends Annotation> annotionType,Class<T> beanType){String[] beanNamesForType = applicationContext.getBeanNamesForType(beanType);return Stream.of(beanNamesForType).filter(e->{BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(e);Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(annotionType);if (beansWithAnnotation.containsKey(e)){return true;}else if (beanDefinition.getSource() instanceof AnnotatedTypeMetadata){return AnnotatedTypeMetadata.class.cast(beanDefinition.getSource()).isAnnotated(annotionType.getName());}return false;});}}

服务端:

@Slf4j
@GrpcService
public class HtMetaSyncService extends HtMetaInfoSyncServiceGrpc.HtMetaInfoSyncServiceImplBase {@Overridepublic void syncMeta(HtMetaSyncRequest request, StreamObserver<HtMetaSyncResponse> responseObserver) {String syncJson = request.getSyncJson();log.info("接收到json:{}",syncJson);SyncType syncType = request.getSyncType();int number = syncType.getNumber();log.info("同步类型:{}",number);HtMetaSyncResponse syncResponse = HtMetaSyncResponse.newBuilder().setCode("1000").setMsg("同步成功").build();responseObserver.onNext(syncResponse);responseObserver.onCompleted();}}

客户端

import com.config.GrpcProperties;
import com.meta.HtMetaInfoSyncServiceGrpc;
import com.meta.HtMetaSyncRequest;
import com.meta.HtMetaSyncResponse;
import com.meta.SyncType;
import io.grpc.ManagedChannel;
import io.grpc.StatusRuntimeException;
import io.grpc.netty.NettyChannelBuilder;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Objects;/*** @author xiaoshu*/
@Component
public class HtMetaInfoSyncClient {@Resourceprivate GrpcProperties grpcProperties;@SneakyThrowspublic String syncMeta(final String json,final SyncType syncType) {ManagedChannel channel = null;try {channel=NettyChannelBuilder.forAddress(grpcProperties.getServerIp(),grpcProperties.getPort())//非加密连接.usePlaintext()//加密//.sslContext(grpcProperties.buildClentSslContext()).build();HtMetaInfoSyncServiceGrpc.HtMetaInfoSyncServiceBlockingStub stub = HtMetaInfoSyncServiceGrpc.newBlockingStub(channel);HtMetaSyncResponse htMetaSyncResponse = stub.syncMeta((HtMetaSyncRequest.newBuilder().setSyncJson(json).setSyncType(syncType).build()));String code = htMetaSyncResponse.getCode();String msg = htMetaSyncResponse.getMsg();return code+":"+msg;} catch (final StatusRuntimeException e) {return "FAILED with " + e.getStatus().getCode().name();}finally {if (Objects.nonNull(channel)){channel.shutdown();}}}
}
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author 何永豪* @className GrpcConfig* @description TODO* @date 2023/11/7 16:58*/
@Configuration
public class GrpcConfig {@Bean@ConditionalOnProperty(value = "grpc.enable",havingValue = "true",matchIfMissing = true)public GrpcServer grpcServer(){return new GrpcServer();}}
@Component
@ConfigurationProperties(prefix = "grpc")
@Data
public class GrpcProperties {private Integer port;private String  serverIp;private String serverCertPath;private String serverPrivateKeyPath;private String serverTrustCertPath;private String clientCertPath;private String clientCertChainPath;private String clientPrivateKeyPath;/*public SslContext buildClentSslContext() throws SSLException {SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient();sslContextBuilder.trustManager(new File(clientCertPath));sslContextBuilder.keyManager(new File(clientCertChainPath),new File(clientPrivateKeyPath));return sslContextBuilder.build();}*/}
server:port: 8077spring:application:name: grpc-apigrpc:#监听端口port: 6100#目标IPserver-ip: 127.0.0.1#ssl配置server-cert-path: /ca/server/server.crtserver-private-key-path: /ca/server/server.pemserver-trust-cert-path: /ca/server/ca.crt

相关文章:

Spring boot 整合grpc 运用

文章目录 GRPC基础概念&#xff1a;Protocol Buffers&#xff1a;proto 基础语法&#xff1a;调用类型&#xff1a; Spring boot 整合 grpc项目结构&#xff1a;整合代码&#xff1a;父 pomproto 模块服务端&#xff1a;客户端&#xff1a;实际调用&#xff1a; 原生集成 GRPC基…...

C++ 模板保姆级详解——template<class T>(什么是模板?模板分哪几类?模板如何应用?)

目录 一、前言 二、 什么是C模板 &#x1f4a6;泛型编程的思想 &#x1f4a6;C模板的分类 三、函数模板 &#x1f4a6;函数模板概念 &#x1f4a6;函数模板格式 &#x1f4a6;函数模板的原理 &#x1f4a6;函数模板的实例化 &#x1f34e;隐式实例化 &#x1f349;显式实…...

uni.getLocation() 微信小程序 线上获取失败

开发版,体验版,用此方法都可以正确获取定位,但是在小程序的线上,总是获取失败 参考:uni-app微信小程序uni.getLocation获取位置&#xff1b;authorize scope.userLocation需要在app.json中声明permission&#xff1b;小程序用户拒绝授权后重新授权-CSDN博客 uniapp 中的 uni.…...

Pytorch损失函数、反向传播和优化器、Sequential使用

Pytorch_Sequential使用、损失函数、反向传播和优化器 文章目录 nn.Sequential搭建小实战损失函数与反向传播优化器 nn.Sequential nn.Sequential是一个有序的容器&#xff0c;用于搭建神经网络的模块被按照被传入构造器的顺序添加到nn.Sequential()容器中。 import torch.nn …...

css:两个行内块元素和图片垂直居中对齐

目录 两个行内块元素垂直居中对齐图片垂直居中问题图片和文字垂直居中对齐参考文章 两个行内块元素垂直居中对齐 先看一段代码&#xff1a; <style> .box {width: 200px;height: 200px;line-height: 200px;font-size: 20px;text-align: center;display: inline-block;b…...

从0开始python学习-34.pytest常用插件

目录 1. pytest-html&#xff1a;生成HTML测试报告 2.pytest-xdist&#xff1a;并发执行用例 3. pytest-order&#xff1a;自定义用例的执行顺序 4. pytest-rerunfailures&#xff1a;用例失败时自动重试 5. pytest-result-log:用例执行结果记录到日志文件 1. pytest-html…...

初始MySQL(二)(表的增删查改)

目录 修改表 CRUD(增删改查) insert语句(表中增加数据) update语句(修改表中的数据) delete删除语句 select语句 修改表 添加列 ALTER TABLE tablename ADD (column datatype [DEFAULT expr] [, column datatype] ...); 修改列 ALTER TABLE tablename MODIFY (column …...

SLAM从入门到精通(SLAM落地的难点)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在所有的slam算法中&#xff0c;基于反光柱的激光slam和基于二维码的视觉slam是落地最彻底的两种slam方法。和磁条、色带等传统导航方式相比较&…...

通过内网穿透快速搭建公网可访问的Spring Boot接口调试环境

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…...

职业迷茫,我该如何做好职业规划

案例25岁男&#xff0c;入职2月&#xff0c;感觉自己在混日子&#xff0c;怕能力没有提升&#xff0c;怕以后薪资也提不起来。完全不知道应该往哪个方向进修&#xff0c;感觉也没有自己特别喜欢的。感觉自己特别容易多想&#xff0c;想多年的以后一事无成的样子。 我觉得这个案…...

数据结构----顺序栈的操作

1.顺序栈的存储结构 typedef int SElemType; typedef int Status; typedef struct{SElemType *top,*base;//定义栈顶和栈底指针int stacksize;//定义栈的容量 }SqStack; 2.初始化栈 Status InitStack(SqStack &S){//初始化一个空栈S.basenew SElemType[MAXSIZE];//为顺序…...

web3 React Dapp书写订单 买入/取消操作

好 上文web3 前端dapp从redux过滤出 (我创建与别人创建&#xff09;正在执行的订单 并展示在Table上中 我们过滤出了 我创建的 与 别人创建的 且 未完成 未取消的订单数据 这边 我们起一下 ganache 环境 ganache -d然后 我们项目 发布一下智能合约 truffle migrate --reset然…...

C++学习---信号处理机制、中断、异步环境

文章目录 前言信号处理signal()函数关于异步环境 信号处理函数示例raise()函数 前言 信号处理 关于信号&#xff0c;信号是一种进程间通信的机制&#xff0c;用于在程序执行过程中通知进程发生了一些事件。在Unix和类Unix系统中&#xff0c;信号是一种异步通知机制&#xff0c…...

机器学习——奇异值分解案例(图片压缩-代码简洁版)

本想大迈步进入前馈神经网络 但是…唉…瞅了几眼&#xff0c;头晕 然后想到之前梳理的奇异值分解、主成分分析、CBOW都没有实战 如果没有实际操作&#xff0c;会有一种浮在云端的虚无感 但是如果要实际操作&#xff0c;我又不想直接调用库包 可是…如果不直接调包&#xff0c;感…...

【Go入门】面向对象

【Go入门】面向对象 前面两章我们介绍了函数和struct&#xff0c;那你是否想过函数当作struct的字段一样来处理呢&#xff1f;今天我们就讲解一下函数的另一种形态&#xff0c;带有接收者的函数&#xff0c;我们称为method method 现在假设有这么一个场景&#xff0c;你定义…...

Asp.Net Core 中使用配置文件

本文参考微软文档&#xff1a;ASP.NET Core 中的配置 ASP.NET Core 中的应用程序配置是使用一个或多个配置程序提供程序执行的。 配置提供程序使用各种配置源从键值对读取配置数据&#xff1a; 设置文件&#xff0c;例如 appsettings.json环境变量Azure Key VaultAzure 应用配…...

深入理解JVM虚拟机第二十四篇:详解JVM当中的动态链接和常量池的作用

大神链接&#xff1a;作者有幸结识技术大神孙哥为好友&#xff0c;获益匪浅。现在把孙哥视频分享给大家。 孙哥链接&#xff1a;孙哥个人主页 作者简介&#xff1a;一个颜值99分&#xff0c;只比孙哥差一点的程序员 本专栏简介&#xff1a;话不多说&#xff0c;让我们一起干翻J…...

QGridLayout

QGridLayout QGridLayout 是 Qt 框架中的一个布局管理器类&#xff0c;用于在窗口或其他容器中创建基于网格的布局。 QGridLayout 将窗口或容器划分为行和列的网格&#xff0c;并将小部件放置在相应的单元格中。可以通过调整行、列和单元格的大小来控制布局的样式和结构。 以…...

万能在线预约小程序系统源码 适合任何行业在线预约小程序+预约到店模式 带完整的搭建教程

大家好啊&#xff0c;源码小编又来给大家分享啦&#xff01;随着互联网的发展和普及&#xff0c;越来越多的服务行业开始使用在线预约系统以方便客户和服务管理。例如&#xff0c;美发店、健身房、餐厅等都可以通过在线预约系统提高服务效率&#xff0c;减少等待时间&#xff0…...

Leetcode 2935. Maximum Strong Pair XOR II

Leetcode 2935. Maximum Strong Pair XOR II 1. 解题思路2. 代码实现 题目链接&#xff1a;2935. Maximum Strong Pair XOR II 1. 解题思路 这一题又是一个限制条件下找“最大值”的问题&#xff0c;不过这里的最大值是XOR之后的最大值。 而要求XOR之后结果的最大值&#x…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景

Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知&#xff0c;帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量&#xff0c;能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度&#xff0c;还为机器人、医疗设备和制造业的智…...