基于grpc从零开始搭建一个准生产分布式应用(3) - GRPC实现

news2024/11/26 20:01:05

本章开始会进入GRPC子专题,先实现前面章节中提到的例子。然后就使用的知识点展开全面的描述。本章代码任务:1、实现一个简单的GRPC服务;2、实现GRPC拦截器。

本章的代码承接上一章的代码进行迭代。因模块间存在相互依赖关系,读者一定先按笔者讲述的顺序操作,否则最后程序可能由于依赖问题导致不能运行;

一、准备工作

因为本专题定位于准生产环境,所以我们在代码上也会按规范严格要求一下,本章涉及的准备工作就是在common模块优先定义一些辅助工具类。因代码比较多,详细可查看:

  • ​​基于grpc从零开始搭建一个准生产分布式应用(8) - 01 - 附:GRPC公共库源码​​
  • ​​基于grpc从零开始搭建一个准生产分布式应用(7) - 01 - 附:GRPC拦截器源码​​

二、API接口定义

修改【base-grpc-framework-api】模块,我们用proto方式来实现,首先要修改pom.xml文件引入必要的依赖,再定义一个.proto文件。proto的使用在下一章节会详细介绍,本章了解下必要的知识点即可。

2.1、pom.xml文件修改

这块没有需要注意的地方,用下列内容覆盖上一章中的源码即可。源码中的dependency全部用provided来修饰的原因是,在系统运行时会用到编译后的源码,这里的依赖只是用于辅助编译用。

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>base-grpc-framework-parent</artifactId>
        <groupId>com.zd</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>base-grpc-framework-api</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <scope>provided</scope>
        </dependency>

    </dependencies>
    <build>
        <!--取得本地系统信息的插件-->
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>${maven.kr.motd}</version>
            </extension>
        </extensions>

        <plugins>
            <!--grpc插件,用于IDEA集成使用-->
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>${maven.org.xolstice}</version>
                <configuration>
                    <protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
                    <protocArtifact>com.google.protobuf:protoc:${protobuf.java.version}:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${io.grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal><!--对应插件的complie命令-->
                            <goal>compile-custom</goal><!--对应插件的complie-custom命令,需要本地配置插件-->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2.2、systemlog.proto文件定义

文件路径:src/main/proto/sysrecord.proto,一个经验就是,定义入参时要用包装类型方便参数验证,如下面的的CreateSysRecordRequest定义。返回结果用简单类型防止空指针异常,如下面的ListSysRecordResponse定义。

syntax = "proto3";

package com.zd.baseframework.core.api.sysrecord;

import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

option java_package = "com.zd.baseframework.core.api.systemlog";
option java_outer_classname = "SystemLogProto";
option java_multiple_files = true;

service ISystemLogService{

  //创建
  rpc CreateSystemLog (CreateSystemLogRequest) returns (SystemLogOperatorResponse);

  //查询
  rpc ListSystemLogByCondition (ListSystemLogRequest) returns (ListSystemLogResponse);

}
//请求参数
message CreateSystemLogRequest{
  google.protobuf.StringValue biz_id = 1;
  google.protobuf.Int64Value user_id = 2;
  google.protobuf.StringValue code = 4;
  google.protobuf.StringValue custom_code = 5;
}

message ListSystemLogRequest{
  google.protobuf.StringValue biz_id = 1;
  google.protobuf.Int64Value user_id = 2;
  google.protobuf.Int32Value code = 3;
}

//返回结果
message  SystemLogOperatorResponse{
  optional int32 status = 1;
  optional string message = 2;
}

message  ListSystemLogResponse{
  repeated SystemLogDto data = 1;
}

message SystemLogDto {
  int64 id = 1;
  string biz_id = 2;
  int64 user_id = 3;
  string track_uid = 4;
  string code = 5;
  string custom_code = 6;
  int32 state = 7;
  google.protobuf.Timestamp code_name = 8;
  google.protobuf.Timestamp utime = 9;
}

2.3、proto文件编译

把.proto文件编译成java代码,在idea中的操作过程共分为三步:

  1. 在pom.xml中配置proto插件;
  2. 执行protobuf:complie生成接口;
  3. 执行protobuf:complile-custom生成实体类;

先确定已经按2.2节内容正确配置了protobuf-maven-plugin插件后,然后先后双击下图中红框的内容:

最后打开源码的target文件夹,会看到生成的Java源码文件,如下图所示,grpc-java文件夹中存储的是接口定义即proto文件中service标签中定义的内容,java文件中存储的是message标签定义的内容,至此api模块的所有修改就完成了:

三、GPRC实现-服务端

本章我们会传承上一章节的代码,需改动下图中标红的模块。服务端的实现稍复杂一些,同样也要改一些pom配置,本次我们会实现两个接口,同学们可以了解下grpc本地调用的实现方法,同样grpc详细的内容也会在后续章节详细展开。

  • application模块:配置配置参数;
  • core模块:实现一个grpc和一个controler服务,同时暴露两种协议的接口,熟悉grpc的本地调用;

3.1、pom.xml文件修改

修改【base-grpc-framework-core】模块,这里没有太多需要注意的内容,复制即可;下面源码中多了lombok和mapstruft的内容,暂时保留吧,后面也会用到了。

<?xml versinotallow="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>base-grpc-framework-parent</artifactId>
        <groupId>com.zd</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>base-grpc-framework-core</artifactId>

    <properties>
        <lombok.mapstruct.binding.version>0.1.0</lombok.mapstruct.binding.version>
    </properties>

    <dependencies>
        <!--grpc依赖-->
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-server-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
        </dependency>

        <!--gprc依赖实现本地grpc调用-->
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-client-spring-boot-starter</artifactId>
        </dependency>

        <!--项目依赖-->
        <dependency>
            <groupId>com.zd</groupId>
            <artifactId>base-grpc-framework-common</artifactId>
            <version>${project.parent.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.zd</groupId>
            <artifactId>base-grpc-framework-api</artifactId>
            <version>${project.parent.version}</version>
        </dependency>

        <!--nacos相关-->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
        </dependency>


        <!--===========以下全是工具类和工具框架=========================-->

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>compile</scope>
        </dependency>

        <!--hutool工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>

        <!-- 使用log4j2,性能更高 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
    </dependencies>

    <build>

        <plugins>
            <!--处理lombok和mapstruft 加载顺序的问题 防止在生成的实体没有属性-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${mapstruct.version}</version>
                        </path>

                        <!-- additional annotation processor required as of Lombok 1.18.16 -->
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>${lombok.mapstruct.binding.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.2、Gprc服务实现

修改【base-grpc-framework-core】模块,类路径:com.zd.baseframework.core.core.sysrecord.api.impl.ISysRecordServiceApiImpl ,代码实现如下,这里我们只实现一个创建接口,本类创建后还需要在application.yml中进行一些配置,后面一起来讲;

下面源码唯一注意的是一定要标上@GrpcService注解,对于源码中没有找到的类全在common包中,可先按附录方式创建好必要的辅助类。

如果发现找不到API中的类,可点击右侧MAVEN窗口刷新工程。

@GrpcService
@Slf4j
public class SystemLogServiceApiImpl extends ISystemLogServiceGrpc.ISystemLogServiceImplBase {

    @Override
    public void createSystemLog(CreateSystemLogRequest request, StreamObserver<SystemLogOperatorResponse> responseObserver)  {
        String bizId = request.hasBizId()?request.getBizId().getValue():null;
        Long userId  = request.hasUserId()?request.getUserId().getValue():null;
        String code = request.hasCode()?request.getCode().getValue():null;
        String customCode = request.hasCustomCode()?request.getCustomCode().getValue():null;

        String trackLog = LogGenerator.trackLog();

        try{
            //打印原始入参
            log.info(trackLog
                    + " grpcReqParam=" + JsonFormat.printer().omittingInsignificantWhitespace().print(request)
            );

            //入参验证
            if(StrUtil.isEmpty(bizId)
                    || null==userId
                    || StrUtil.isEmpty(code) ){
                throw new AppException("非法参数");
            }

            SysRecordOperatorResponse response  = SysRecordOperatorResponse.newBuilder()
                    .setStatus(ResponseConst.SUCCESS)
                    .setMessage(ResponseConst.Msg.SUCCESS)
                    .build();
            responseObserver.onNext(response);
            responseObserver.onCompleted();
            responseObserver.onCompleted();

        }catch (AppException e) {
            log.error(e.getMessage());
            responseObserver.onError(Status.INVALID_ARGUMENT.withDescription(e.getMessage()).asException());
        }
        catch(Exception e){
            log.error(e.getMessage());
            responseObserver.onError(Status.INTERNAL.withDescription(e.getMessage()).asException());
        }
    }

    @Override
    public void listSystemLogByCondition(ListSystemLogRequest request, StreamObserver<ListSystemLogResponse> responseObserver) {

        String trackLog = LogGenerator.trackLog();

        try{
            //打印原始入参
            log.info(trackLog
                    + " grpcReqParam=" + JsonFormat.printer().omittingInsignificantWhitespace().print(request)
            );


            ListSystemLogResponse response = ListSystemLogResponse.newBuilder().build();
            responseObserver.onNext(response);
            responseObserver.onCompleted();

        }catch (AppException e) {
            log.error(e.getMessage());
            responseObserver.onError(Status.INVALID_ARGUMENT.withDescription(e.getMessage()).asException());
        }
        catch(Exception e){
            log.error(e.getMessage());
            responseObserver.onError(Status.INTERNAL.withDescription(e.getMessage()).asException());
        }
    }
}

3.3、Controller接口实现

修改【base-grpc-framework-core】模块,实现本地grpc调用,本类创建后还需要在application.yml中进行一些配置,后面一起来讲;类路径:com.zd.baseframework.core.controller.core.SystemLogController.java。代码如下:

注意@GrpcClient("inProcess")和@RestController注解不要忘记。

@Slf4j
@RestController
@RequestMapping("/systemlog")
public class SystemLogController {

    @GrpcClient("inProcess")
    private ISystemLogServiceGrpc.ISystemLogServiceBlockingStub iSysRecordServiceBlockingStub;

    @GetMapping("/v1/create_systemlog")
    public BaseResponse createSystemLog(
            @RequestParam(value="biz_id") String bizId,
            @RequestParam(value="user_id") Long userId,
            @RequestParam(value="code") String code,
            @RequestParam(value="custom_code", required=false) String customCode){
        try{
            //构建请求参数
            CreateSystemLogRequest createSysRecordRequest  = CreateSystemLogRequest.newBuilder()
                    .setBizId(StringValue.of(bizId))
                    .setUserId(Int64Value.of(userId))
                    .setCode(StringValue.of(code))
                    .setCustomCode(StringValue.of(customCode))
                    .build();

            //正常此处需要判断response返回的state值
            SystemLogOperatorResponse response = iSysRecordServiceBlockingStub.createSystemLog(createSysRecordRequest);

            return BaseResponse.success(null);
        }catch(StatusRuntimeException e){
            log.error("ErrorCode : " + e.getStatus().getCode());
            return BaseResponse.error(e.getMessage());
        }catch(Exception e){
            e.printStackTrace();
            return BaseResponse.error(e.getMessage());
        }
    }
    
    @PostMapping("/v1/list_systemlog")
    public BaseResponse listSystemLog(@RequestBody SystemLogQueryRequest systemLogRequest){
        try{
            //构建查询参数
            ListSystemLogResponse listSystemLogResponse = iSysRecordServiceBlockingStub.listSystemLogByCondition(null);
            return BaseResponse.success(vos);

        }catch(StatusRuntimeException e){
            log.error("ErrorCode : " + e.getStatus().getCode());
            return BaseResponse.error(e.getMessage());
        }catch(Exception e){
            e.printStackTrace();
            return BaseResponse.error(e.getMessage());
        }
    }

}

3.4、服务端配置

修改【base-grpc-framework-application】模块,在这个专题中,与应用相关的配置全在base-grpc-framework-application模块的application.yml中配置,因为是本地运行,所以这里我们只修改application-dev.yml。修改后的源码如下:

# http配置
server:
  compression:
    enabled: true
    mime-types: application/json,application/octet-stream

# spring配置
spring:
  application:
    name: GrpcFramework-Server-APP

# grpc Server配置
grpc:
  server:
    port: 9898   #发布远程访问地址
    in-process-name: native  #发布本地访问地址
  client:
    inProcess:
      address: in-process:native #配置内部访问服务名称

上面配置注意grpc.server.in-process-name和grpc.client.inprocess.adderss一定要一样,而且要与controller中的@GrpcClient("inProcess")配置一样,其中grpc.client.inprocess.adderss后面内容in-process:native中的in-process:是固定的写法,不能更改。

3.5、GRPC服务端测试

启动BaseFrameworkApplication.java,启动时不要忘记配置环境变量为dev,配置方式可参考笔者的上一章文章​​https://blog.51cto.com/arch/5378945​​。

3.5.1、grpc测试

可先安装grpcurl工具,笔者使用的是mac系统,安装方式如下,其它系统可网上查询:

brew install grpcui  #安装
grpcui -plaintext 127.0.0.1:9898  #运行

执行上面运行命令后,会自动打开浏览器,显示如下图所示,测试方式可自行操作下:

3.5.2、controller测试

在浏览器中输入 ​​http://localhost:8080/swagger-ui.html​​  ,下图中红框外的两个controller是笔者测试用的,可忽略。红框内的内容就是上面小节写的controller。展开后就可进行测试了:

四、GRPC服务端拦截器实现

这个拦截器主要是实现了日志打印功能,通用track的方式来跟踪每一次访问,详细设计思路可参考笔者写的另一篇文章的描述 ​​https://blog.51cto.com/arch/5295170​​。

完整的类源码如下所下图所示,源码可以查看:​​基于grpc从零开始搭建一个准生产分布式应用(0) - 07 - 附:GRPC拦截器源码​​。

五、GRPC实现-客户端

修改【base-grpc-framework-client】模块。client端不是太重点,这里只是为了说明一下调用和配置方式,笔者的代码没有配置启动类,感兴趣的同学可按第3章的内容自行配置springboot来启动。也可跳过此章,了解下内容即可。完整代码如下图所示:

5.1、修改pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>base-grpc-framework-parent</artifactId>
        <groupId>com.zd</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>base-grpc-framework-client</artifactId>

    <properties>
        <lombok.mapstruct.binding.version>0.1.0</lombok.mapstruct.binding.version>
    </properties>

    <dependencies>
        <!--grpc依赖-->
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-client-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
        </dependency>

        <!--项目依赖-->
        <dependency>
            <groupId>com.zd</groupId>
            <artifactId>base-grpc-framework-common</artifactId>
            <version>${project.parent.version}</version>
        </dependency>
        <dependency>
            <groupId>com.zd</groupId>
            <artifactId>base-grpc-framework-api</artifactId>
            <version>${project.parent.version}</version>
        </dependency>

        <!--===========以下全是工具类和工具框架=========================-->
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>compile</scope>
        </dependency>

        <!--hutool工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>

        <!-- 使用log4j2,性能更高 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
    </dependencies>

</project>

5.2、Controller实现

同3.3节的实现一样,只是@GrpcClient("local-grpc-server")中的内容不一样,可参考5.3节的配置。

@Slf4j
@RestController
@RequestMapping("/systemlog")
public class SystemLogController {

    @GrpcClient("local-grpc-server")
    private ISystemLogServiceGrpc.ISystemLogServiceBlockingStub iSysRecordServiceBlockingStub;

    @GetMapping("/v1/create_systemlog")
    public BaseResponse listWorkFlowByStatus(
            @RequestParam(value="biz_id") String bizId,
            @RequestParam(value="user_id") Long userId,
            @RequestParam(value="code") String code,
            @RequestParam(value="custom_code", required=false) String customCode){
        try{
            //构建查询参数
            CreateSystemLogRequest createSysRecordRequest  = CreateSystemLogRequest.newBuilder()
                    .setBizId(StringValue.of(bizId))
                    .setUserId(Int64Value.of(userId))
                    .setCode(StringValue.of(code))
                    .setCustomCode(StringValue.of(customCode))
                    .build();

            SystemLogOperatorResponse response = iSysRecordServiceBlockingStub.createSystemLog(createSysRecordRequest);

            return BaseResponse.success(null);
        }catch(StatusRuntimeException e){
            log.error("ErrorCode : " + e.getStatus().getCode());
            return BaseResponse.error(e.getMessage());
        }catch(Exception e){
            e.printStackTrace();
            return BaseResponse.error(e.getMessage());
        }
    }
}

5.3、客户端配置

在base-grpc-framework-client】新建一个yml文件。

server:
  port: 8089
spring:
  application:
    name: GrpcFramework-Client-APP
grpc:
  client:
    local-grpc-server:
      address: 'static://127.0.0.1:9898'
      enableKeepAlive: true
      keepAliveWithoutCalls: true

下一章节会先讲述proto的内容。

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

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

相关文章

SpringBoot复习:(42)WebServerCustomizer的customize方法是在哪里被调用的?

ServletWebServletAutoConfiguration类定义如下&#xff1a; 可以看到其中通过Import注解导入了其内部类BeanPostProcessorRegister。 BeanPostProcessor中定义的registerBeanDefinition方法会被Spring容器调用。 registerBeanDefinitions方法调用了RegistrySyntheticBeanIf…

【MongoDB】一文带你快速掌握MongoDB数据库和集合基础操作

文章目录 前言一、案例需求二、数据库操作1. 选择和创建数据库2. 数据库的删除 三、集合操作1. 集合的显式创建&#xff08;了解&#xff09;2. 集合的隐式创建3. 集合的删除 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便…

pycorrector一键式文本纠错工具,整合了BERT、MacBERT、ELECTRA、ERNIE等多种模型,让您立即享受纠错的便利和效果

pycorrector&#xff1a;一键式文本纠错工具&#xff0c;整合了Kenlm、ConvSeq2Seq、BERT、MacBERT、ELECTRA、ERNIE、Transformer、T5等多种模型&#xff0c;让您立即享受纠错的便利和效果 pycorrector: 中文文本纠错工具。支持中文音似、形似、语法错误纠正&#xff0c;pytho…

激活函数总结(七):激活函数补充(Softsign、Threshold、Sinc)

激活函数总结&#xff08;七&#xff09;&#xff1a;激活函数补充 1 引言2 激活函数2.1 Softsign激活函数2.2 Threshold (Unit step activation function) 激活函数2.3 Sinc激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函数 (Sigmoid、Tanh、ReLU、Lea…

Java-运算符和控制语句(下)(基于c语言的补充)

输出到控制台 System.out.println(msg); // 输出一个字符串, 带换行 System.out.print(msg); // 输出一个字符串, 不带换行 System.out.printf(format, msg); // 格式化输出 从键盘输入 使用 Scanner 读取字符串/整数/浮点数 首先需要导入util包 自动导入util包 这里把回车看…

21-因子个数

题目 一个正整数可以分解成一个或多个数组的积。例如362*2*3*3&#xff0c;即包含2和3两个因子。NowCoder最近在研究因子个数的分布规律&#xff0c;现在给出一系列正整数&#xff0c;他希望你开发一个程序输出每个正整数的因子个数。 输入描述: 输入包括多组数据。 每组数…

Ubuntu22开机后正上方弹出“Printer addded(已添加打印)”等提示框

一、问题描述 Ubuntu22开机后正上方弹出“Printer addded&#xff08;已添加打印&#xff09;”等提示框。如下 二、问题分析 1、列出当前所有开机启动服务 service --status-all msmoshui:~$ service --status-all[ - ] alsa-utils[ - ] anacron[ ] apparmor[ ] app…

预测算法|改进粒子群算法优化极限学习机IDM-PSO-ELM

回归拟合&#xff1a; 分类 本文是作者的预测算法系列的第四篇&#xff0c;前面的文章中介绍了BP、SVM、RF及其优化&#xff0c;感兴趣的读者可以在作者往期文章中了解&#xff0c;这一篇将介绍——极限学习机 过去的几十年里基于梯度的学习方法被广泛用于训练神经网络&am…

全网最详细,Pytest自动化测试框架-Fixture固件实战,你要的都有...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 什么是固件 Fixt…

SpringBoot整合Redis完整篇

SpringBoot整合Redis完整篇 1、在springboot项目的pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schem…

用HARU-Net增强核分割:一种基于混合注意的残差u块网络

文章目录 Enhancing Nucleus Segmentation with HARU-Net: A Hybrid Attention Based Residual U-Blocks Network摘要本文方法损失函数后处理消融实验 Enhancing Nucleus Segmentation with HARU-Net: A Hybrid Attention Based Residual U-Blocks Network 摘要 核图像分割是…

B3716 分解质因子 3

#include <bitset> #include <vector> #include <iostream> #include <algorithm>const int maxn 100000008;std::vector<int> prm, pre; // pre is the min-factor array. bool np[maxn];void getPrime(const int N 100000000) {//线性筛&am…

Fast SAM与YOLOV8检测模型一起使用实现实例分割以及指定物体分割(有代码)

Fast SAM与YOLOV8检测模型一起使用 VX 搜索”晓理紫“ 关注并回复yolov8fastsam获取核心代码 晓理紫 1 使用场景 实例分割数据集的获取要比检测数据的获取更加困难&#xff0c;在已有检测模型不想从新标注分割数据进行训练但是又想获取相关物体的mask信息以便从像素级别对物体进…

Redis原理简述

Redis原理简述 Redis 有哪些特性 1. 特性 key-value 型内存数据库单线程——原子化操作支持lua脚本发布与订阅可持久化逐出与过期……2. 持久化 RDB:经过压缩的二进制文件;fork子进程进行操作AOF:保存所有写命令;先写缓存再同步至AOF文件;文件过大时会触发AOF重写3. 过期…

4. 发布确认

4.1. 发布确认原理 生产者将信道设置成 confirm 模式&#xff0c;一旦信道进入 confirm 模式&#xff0c;所有在该信道上面发布的 消息都将会被指派一个唯一的 ID(从 1 开始)&#xff0c;一旦消息被投递到所有匹配的队列之后&#xff0c;broker 就会发送一个确认给生产者(包含消…

[python]RuntimeError: Can‘t decrement id ref count (unable to close file...

使用spectralspatial模型进行EEG分类时&#xff0c;出现以下错误 RuntimeError: Cant decrement id ref count (unable to close file, errno 5, error message Input/output error) Segmentation fault (core dumped) 猜测是因为存储的model太大了导致的&#xff0c;找到了…

QGIS3.28的二次开发八:显示shp的属性表

这里实现两个基本的 GIS 软件需求&#xff1a;矢量图层的属性表显示&#xff0c;以及根据属性筛选要素。 具体需求如下&#xff1a; 加载一个矢量图层并打开其属性表&#xff1b;输入筛选条件确认无误后&#xff0c;画布上和属性表中均只显示筛选后的要素。 QGIS 提供了若干…

V3s uboot 通过env 修改LCD 参数信息

实际项目中我们可能使用各种参数的LCD 显示器&#xff0c;有7吋&#xff0c;4.3 寸等等&#xff0c;我这里使用的uboot 版本是U-Boot 2017.01-rc2 &#xff0c;在make menuconfig 时候会填入lcd 配置信息&#xff0c;如下&#xff1a; 所以这里使用起来很不方便&#xff0c;查看…

Vulnhub: DriftingBlues: 3靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.192 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.192 查看robots.txt得到提示 访问eventadmins提示littlequeenofspades.html 查看littlequeenofspades.html源码 base64解密…

掌握Python的X篇_35_用Python为美女打码_图像库Pillow

本篇将会介绍python中的一个图像库Pillow。 文章目录 1. Pillow与PIL的关系2. 调整大小3. 加滤镜4. 剪裁5. 生成验证码 1. Pillow与PIL的关系 我们在网上搜python的图像库的话&#xff0c;可能搜到的时PIL。实际上之前python发展的时候就是PIL&#xff0c;这个库比较好用&…