Grpc项目集成到java方式调用实践

背景:由于项目要对接到grcp 的框架,然后需要对接老外的东西,还有签名和证书刚开始没有接触其实有点懵逼。

gRPC 是由 Google 开发的高性能、开源的远程过程调用(RPC)框架。它建立在 HTTP/2 协议之上,使用 Protocol Buffers 作为其接口定义语言(IDL)。gRPC 被设计为可跨多种环境(包括客户端、服务器和各种语言)使用,支持多种编程语言,如 C、C++、Java、Go、Python、Ruby、Node.js 等。

gRPC 具有以下特点:

  1. 性能高效:gRPC 使用基于 HTTP/2 的传输协议,能够复用连接、多路复用请求、支持头部压缩等特性,从而提高了性能。

  2. 跨语言支持:gRPC 支持多种编程语言,使得客户端和服务器可以使用不同的编程语言实现,并且它们之间的通信依然高效。

  3. IDL 和自动代码生成:gRPC 使用 Protocol Buffers 作为接口定义语言(IDL),定义服务接口和消息格式,并提供了自动生成客户端和服务器代码的工具。

  4. 多种调用方式:gRPC 支持四种调用方式,包括简单 RPC、服务器流式 RPC、客户端流式 RPC 和双向流式 RPC,可以根据业务需求选择合适的调用方式。

  5. 安全性:gRPC 支持 TLS/SSL 加密传输,保障通信的安全性。

  6. 插件机制:gRPC 提供了插件机制,可以扩展其功能,例如添加认证、日志、监控等功能。

总的来说,gRPC 是一个强大的远程过程调用框架,适用于构建分布式系统中的各种服务,并且在性能、跨语言支持和安全性方面具有很多优势。

一,开发工具集成:

安装指定插件,网上说还要Protobuf buffer 安装,但是我用的idea2018的版本搜索不到,这个不是必须的,可以不用。

二 protobuf编译器一定要安装配置一个: Releases · protocolbuffers/protobuf · GitHub

三,安装好插件后就可以看的了这俩个就是生产java代码的。

四,grpc 的文件格式:

syntax = "proto3";package c3_vanilla_app;option java_package = "com.test.conncar.c3vanillaapp";
option java_outer_classname = "C3VanillaAppProtos";import "google/protobuf/empty.proto";message ExampleRequestMessage {string id = 1;int64 timestamp = 2;string message = 3;
}message ExampleResponseMessage {string message = 1;
}service ExampleService {rpc PostExampleMessages(ExampleRequestMessage) returns (ExampleResponseMessage) {}
}

生成出来的代码就是:

可以用命令生成,然后也可以用maven自动生成

pom加上这个插件就可以生产代码了:

 <plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin>

完整的pom文件:

 <properties><protoc.version>3.25.2</protoc.version><grpc.version>1.61.1</grpc.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-core</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.25.2</version> <!-- 或者与你的 protoc.version 相匹配的版本 --></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-netty</artifactId><version>${grpc.version}</version></dependency><dependency><!-- necessary for Java 9+ --><groupId>org.apache.tomcat</groupId><artifactId>annotations-api</artifactId><version>6.0.53</version></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.2</version></extension></extensions><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.10.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.jfrog.buildinfo</groupId><artifactId>artifactory-maven-plugin</artifactId><version>3.3.0</version><inherited>false</inherited><executions><execution><id>build-info</id><goals><goal>publish</goal></goals><configuration><artifactory><includeEnvVars>false</includeEnvVars><timeoutSec>60</timeoutSec><propertiesFile>publish.properties</propertiesFile></artifactory><publisher><contextUrl>${env.ARTIFACTORY_HOST_POM}</contextUrl><username>${env.ARTIFACTORY_CCAR_USER}</username><password>${env.ARTIFACTORY_CCAR_APIKEY}</password><excludePatterns>*-tests.jar</excludePatterns><repoKey>${CI_PROJECT_NAMESPACE}</repoKey><snapshotRepoKey>${CI_PROJECT_NAMESPACE}</snapshotRepoKey></publisher><buildInfo><buildName>${CI_PROJECT_NAME}</buildName><buildNumber>${CI_PIPELINE_ID}</buildNumber><buildUrl>${CI_PROJECT_URL}</buildUrl></buildInfo></configuration></execution></executions></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

生成的代码路径:

生成的代码,记得install的时候注释掉插件,然后进行install

然后本地写个client和sever就行了:

server:

package com.grpc.mistra.server;import com.grpc.mistra.generate.MistraRequest;
import com.grpc.mistra.generate.MistraResponse;
import com.grpc.mistra.generate.MistraServiceGrpc;
import io.grpc.BindableService;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;import java.io.IOException;/*** Time: 14:46* Description:*/
public class MistraServer {private int port = 8001;private Server server;private void start() throws IOException {server = ServerBuilder.forPort(port).addService((BindableService) new MistraHelloWorldImpl()).build().start();System.out.println("------------------- 服务端服务已开启,等待客户端访问 -------------------");Runtime.getRuntime().addShutdownHook(new Thread() {@Overridepublic void run() {System.err.println("*** shutting down gRPC server since JVM is shutting down");MistraServer.this.stop();System.err.println("*** server shut down");}});}private void stop() {if (server != null) {server.shutdown();}}private void blockUntilShutdown() throws InterruptedException {if (server != null) {server.awaitTermination();}}public static void main(String[] args) throws IOException, InterruptedException {final MistraServer server = new MistraServer();//启动服务server.start();//服务一直在线,不关闭server.blockUntilShutdown();}// 定义一个实现服务接口的类private class MistraHelloWorldImpl extends MistraServiceGrpc.MistraServiceImplBase {@Overridepublic void sayHello(MistraRequest mistraRequest, StreamObserver<MistraResponse> responseObserver) {// 具体其他丰富的业务实现代码System.err.println("server:" + mistraRequest.getName());MistraResponse reply = MistraResponse.newBuilder().setMessage(("响应信息: " + mistraRequest.getName())).build();responseObserver.onNext(reply);responseObserver.onCompleted();}}
}

client:

package com.grpc.mistra.client;import com.grpc.mistra.generate.MistraRequest;
import com.grpc.mistra.generate.MistraResponse;
import com.grpc.mistra.generate.MistraServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;import java.util.concurrent.TimeUnit;/*** Time: 14:46* Description:*/
public class MistraClient {private final ManagedChannel channel;private final MistraServiceGrpc.MistraServiceBlockingStub blockingStub;public MistraClient(String host, int port) {channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();blockingStub = MistraServiceGrpc.newBlockingStub(channel);}public void shutdown() throws InterruptedException {channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);}public void greet(String name) {MistraRequest request = MistraRequest.newBuilder().setName(name).build();MistraResponse response = blockingStub.sayHello(request);System.out.println(response.getMessage());}public static void main(String[] args) throws InterruptedException {MistraClient client = new MistraClient("127.0.0.1", 8001);System.out.println("-------------------客户端开始访问请求-------------------");for (int i = 0; i < 10; i++) {client.greet("你若想生存,绝处也能缝生: " + i);}}
}

效果图:

grpc的调用类:

package com.grpc.mistra.generate;import static io.grpc.MethodDescriptor.generateFullMethodName;
import static io.grpc.stub.ClientCalls.asyncUnaryCall;
import static io.grpc.stub.ClientCalls.blockingUnaryCall;
import static io.grpc.stub.ClientCalls.futureUnaryCall;
import static io.grpc.stub.ServerCalls.asyncUnaryCall;
import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;/*** <pre>* 声明一个服务名称* </pre>*/
@javax.annotation.Generated(value = "by gRPC proto compiler (version 1.11.0)",comments = "Source: helloworld.proto")
public final class MistraServiceGrpc {private MistraServiceGrpc() {}public static final String SERVICE_NAME = "mistra.MistraService";// Static method descriptors that strictly reflect the proto.@io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")@Deprecated // Use {@link #getSayHelloMethod()} instead.public static final io.grpc.MethodDescriptor<MistraRequest,MistraResponse> METHOD_SAY_HELLO = getSayHelloMethodHelper();private static volatile io.grpc.MethodDescriptor<MistraRequest,MistraResponse> getSayHelloMethod;@io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")public static io.grpc.MethodDescriptor<MistraRequest,MistraResponse> getSayHelloMethod() {return getSayHelloMethodHelper();}private static io.grpc.MethodDescriptor<MistraRequest,MistraResponse> getSayHelloMethodHelper() {io.grpc.MethodDescriptor<MistraRequest, MistraResponse> getSayHelloMethod;if ((getSayHelloMethod = MistraServiceGrpc.getSayHelloMethod) == null) {synchronized (MistraServiceGrpc.class) {if ((getSayHelloMethod = MistraServiceGrpc.getSayHelloMethod) == null) {MistraServiceGrpc.getSayHelloMethod = getSayHelloMethod =io.grpc.MethodDescriptor.<MistraRequest, MistraResponse>newBuilder().setType(io.grpc.MethodDescriptor.MethodType.UNARY).setFullMethodName(generateFullMethodName("mistra.MistraService", "SayHello")).setSampledToLocalTracing(true).setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(MistraRequest.getDefaultInstance())).setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(MistraResponse.getDefaultInstance())).setSchemaDescriptor(new MistraServiceMethodDescriptorSupplier("SayHello")).build();}}}return getSayHelloMethod;}/*** Creates a new async stub that supports all call types for the service*/public static MistraServiceStub newStub(io.grpc.Channel channel) {return new MistraServiceStub(channel);}/*** Creates a new blocking-style stub that supports unary and streaming output calls on the service*/public static MistraServiceBlockingStub newBlockingStub(io.grpc.Channel channel) {return new MistraServiceBlockingStub(channel);}/*** Creates a new ListenableFuture-style stub that supports unary calls on the service*/public static MistraServiceFutureStub newFutureStub(io.grpc.Channel channel) {return new MistraServiceFutureStub(channel);}/*** <pre>* 声明一个服务名称* </pre>*/public static abstract class MistraServiceImplBase implements io.grpc.BindableService {/*** <pre>* 请求参数MistraRequest   响应参数MistraResponse* </pre>*/public void sayHello(MistraRequest request,io.grpc.stub.StreamObserver<MistraResponse> responseObserver) {asyncUnimplementedUnaryCall(getSayHelloMethodHelper(), responseObserver);}@Overridepublic final io.grpc.ServerServiceDefinition bindService() {return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()).addMethod(getSayHelloMethodHelper(),asyncUnaryCall(new MethodHandlers<MistraRequest,MistraResponse>(this, METHODID_SAY_HELLO))).build();}}/*** <pre>* 声明一个服务名称* </pre>*/public static final class MistraServiceStub extends io.grpc.stub.AbstractStub<MistraServiceStub> {private MistraServiceStub(io.grpc.Channel channel) {super(channel);}private MistraServiceStub(io.grpc.Channel channel,io.grpc.CallOptions callOptions) {super(channel, callOptions);}@Overrideprotected MistraServiceStub build(io.grpc.Channel channel,io.grpc.CallOptions callOptions) {return new MistraServiceStub(channel, callOptions);}/*** <pre>* 请求参数MistraRequest   响应参数MistraResponse* </pre>*/public void sayHello(MistraRequest request,io.grpc.stub.StreamObserver<MistraResponse> responseObserver) {asyncUnaryCall(getChannel().newCall(getSayHelloMethodHelper(), getCallOptions()), request, responseObserver);}}/*** <pre>* 声明一个服务名称* </pre>*/public static final class MistraServiceBlockingStub extends io.grpc.stub.AbstractStub<MistraServiceBlockingStub> {private MistraServiceBlockingStub(io.grpc.Channel channel) {super(channel);}private MistraServiceBlockingStub(io.grpc.Channel channel,io.grpc.CallOptions callOptions) {super(channel, callOptions);}@Overrideprotected MistraServiceBlockingStub build(io.grpc.Channel channel,io.grpc.CallOptions callOptions) {return new MistraServiceBlockingStub(channel, callOptions);}/*** <pre>* 请求参数MistraRequest   响应参数MistraResponse* </pre>*/public MistraResponse sayHello(MistraRequest request) {return blockingUnaryCall(getChannel(), getSayHelloMethodHelper(), getCallOptions(), request);}}/*** <pre>* 声明一个服务名称* </pre>*/public static final class MistraServiceFutureStub extends io.grpc.stub.AbstractStub<MistraServiceFutureStub> {private MistraServiceFutureStub(io.grpc.Channel channel) {super(channel);}private MistraServiceFutureStub(io.grpc.Channel channel,io.grpc.CallOptions callOptions) {super(channel, callOptions);}@Overrideprotected MistraServiceFutureStub build(io.grpc.Channel channel,io.grpc.CallOptions callOptions) {return new MistraServiceFutureStub(channel, callOptions);}/*** <pre>* 请求参数MistraRequest   响应参数MistraResponse* </pre>*/public com.google.common.util.concurrent.ListenableFuture<MistraResponse> sayHello(MistraRequest request) {return futureUnaryCall(getChannel().newCall(getSayHelloMethodHelper(), getCallOptions()), request);}}private static final int METHODID_SAY_HELLO = 0;private static final class MethodHandlers<Req, Resp> implementsio.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {private final MistraServiceImplBase serviceImpl;private final int methodId;MethodHandlers(MistraServiceImplBase serviceImpl, int methodId) {this.serviceImpl = serviceImpl;this.methodId = methodId;}@Override@SuppressWarnings("unchecked")public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {switch (methodId) {case METHODID_SAY_HELLO:serviceImpl.sayHello((MistraRequest) request,(io.grpc.stub.StreamObserver<MistraResponse>) responseObserver);break;default:throw new AssertionError();}}@Override@SuppressWarnings("unchecked")public io.grpc.stub.StreamObserver<Req> invoke(io.grpc.stub.StreamObserver<Resp> responseObserver) {switch (methodId) {default:throw new AssertionError();}}}private static abstract class MistraServiceBaseDescriptorSupplierimplements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier {MistraServiceBaseDescriptorSupplier() {}@Overridepublic com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() {return MistraProto.getDescriptor();}@Overridepublic com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() {return getFileDescriptor().findServiceByName("MistraService");}}private static final class MistraServiceFileDescriptorSupplierextends MistraServiceBaseDescriptorSupplier {MistraServiceFileDescriptorSupplier() {}}private static final class MistraServiceMethodDescriptorSupplierextends MistraServiceBaseDescriptorSupplierimplements io.grpc.protobuf.ProtoMethodDescriptorSupplier {private final String methodName;MistraServiceMethodDescriptorSupplier(String methodName) {this.methodName = methodName;}@Overridepublic com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() {return getServiceDescriptor().findMethodByName(methodName);}}private static volatile io.grpc.ServiceDescriptor serviceDescriptor;public static io.grpc.ServiceDescriptor getServiceDescriptor() {io.grpc.ServiceDescriptor result = serviceDescriptor;if (result == null) {synchronized (MistraServiceGrpc.class) {result = serviceDescriptor;if (result == null) {serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME).setSchemaDescriptor(new MistraServiceFileDescriptorSupplier()).addMethod(getSayHelloMethodHelper()).build();}}}return result;}
}

咋们就完成了grpc接入到java里面调用了本质上其实代码没有区别,小杨看了一下,他就是多了一些设计模式生产的代码,工厂构建等。 

 ————没有与生俱来的天赋,都是后天的努力拼搏(我是小杨,谢谢你的关注和支持)

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

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

相关文章

D7805 正电压稳压电路应用——体积小,成本低,性能好

D7805 构成的 5V 稳压电源为输出电压5V&#xff0c;输出电流 1000mA 的稳压电源它由滤波电容 C1,C3,防止自激电容 C2、C3 和一只固定三端稳压器&#xff08;7805&#xff09;后级加 LC 滤波极为简洁方便地搭成&#xff0c;输入直流电压范围为 7~35V&#xff0c;此直流电压经过D…

yolov8-更换卷积模块-ContextGuidedBlock_Down

源码解读 class ContextGuidedBlock_Down(nn.Module):"""the size of feature map divided 2, (H,W,C)---->(H/2, W/2, 2C)"""def __init__(self, nIn, dilation_rate2, reduction16):"""args:nIn: the channel of input fea…

Hack The Box-Bizness

目录 信息收集 nmap dirsearch WEB Get shell 提权 get user flag get root flag 信息收集 nmap 端口扫描┌──(root㉿ru)-[~/kali/hackthebox] └─# nmap -p- 10.10.11.252 --min-rate 10000 -oA port Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-04 1…

力扣 第 387 场周赛 解题报告 | 珂学家 | 离散化树状数组 + 模拟场

前言 整体评价 手速场模拟场&#xff0c;思路和解法都蛮直接的。 所以搞点活 如果T2&#xff0c;如果不固定左上角&#xff0c;批量查询某个点为左上角&#xff0c;求满足总和 ≤ k \le k ≤k的子矩阵个数 如果T2&#xff0c;如果不固定左上角&#xff0c;求总和 ≤ k \le k…

Spring的Bean的生命周期 | 有图有案例

Spring的Bean的生命周期 Spring的Bean的生命周期整体过程实例化初始化服务销毁循环依赖问题 完整生命周期演示 Spring的Bean的生命周期 Spring Bean的生命周期&#xff1a;从Bean的实例化之后&#xff0c;通过反射创建出对象之后&#xff0c;到Bean称为一个完整的对象&#xf…

快上车:什么是人工智能?人工智能和普通程序的区别

什么是人工智能&#xff1f; 虽然AI历史很悠久&#xff0c;上个世纪50年代就有各种概念&#xff0c;但是发展很慢。第一次对人类的冲击就是1997年IBM深蓝击败国际象棋世界冠军&#xff0c;引起了人们的广泛关注&#xff0c;之后又销声匿迹。突然间2016人工智能alphaGO战胜了围…

具身智能计算系统,机器人时代的 Android | 新程序员

【导读】具身智能作为一种新兴的研究视角和方法论&#xff0c;正在刷新我们对智能本质及其发展的理解&#xff1a;传统的 AI 模型往往将智能视为一种独立于实体存在的抽象能力&#xff0c;而具身智能则主张智能是实体与其环境持续互动的结果。 本文深度剖析了具身智能计算系统…

程序员如何选择职业赛道?

一、自我评估与兴趣探索 程序员选择职业赛道时&#xff0c;可以考虑以下几个关键因素&#xff1a; 1、兴趣与热情&#xff1a;首先要考虑自己的兴趣和热情&#xff0c;选择符合个人喜好和激情的领域&#xff0c;能够激励自己持续学习和进步。 2、技术能力&am…

mysql5.7配置主从

原理&#xff1a; MySQL主从复制的工作原理如下:1. 主服务器产生Binlog日志当主服务器的数据库发生数据修改操作时,如INSERT、UPDATE、DELETE语句执行,主服务器会记录这些操作的日志信息到二进制日志文件中。2. 从服务器读取Binlog日志 从服务器会向主服务器发送请求,主服务器把…

微信小程序开发学习笔记《18》uni-app框架-网络请求与轮播图

微信小程序开发学习笔记《18》uni-app框架-网络请求 博主正在学习微信小程序开发&#xff0c;希望记录自己学习过程同时与广大网友共同学习讨论。建议仔细阅读uni-app对应官方文档 一、下载网络请求包 这个包是以前黑马程序员老师写的一个包&#xff0c;跟着课程学习&#x…

Open3D(C++) 指定点数的体素滤波

目录 一、算法原理1、算法过程2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、算法过程 对于数据量较大的点云,在后期进行配准时会影响计算效率。而体素格网…

LCR 170. 交易逆序对的总数

解题思路&#xff1a; 归并排序&#xff0c;在归并的过程中不断计算逆序对的个数 count mid -i 1&#xff1b;的来源见下图&#xff0c;因为两个数组都是单调递增的&#xff0c;所以如果第一个数组的前一个元素大于第二个数组的对应元素&#xff0c;那么第一个数组的这一元素…

借助Aspose.SVG图像控件,在 C# 中将图像转换为 Base64

Base64 编码是一种二进制到文本的编码方案&#xff0c;可有效地将二进制数据转换为 ASCII 字符&#xff0c;为数据交换提供通用格式。在某些情况下&#xff0c;我们可能需要将JPG或PNG图像转换为 Base64 字符串数据。在这篇博文中&#xff0c;我们将学习如何在 C# 中将图像转换…

分享经典、现代和前沿软件工程课程

随着信息技术的发展&#xff0c;软件已经深入到人类社会生产和生活的各个方面。软件工程是将工程化的方法运用到软件的开发、运行和维护之中&#xff0c;以达到提高软件质量&#xff0c;降低开发成本的目的。软件工程已经成为当今最活跃、最热门的学科之一。 本次软件工程MOOC课…

现在如何才能开通微信公众号留言功能?

为什么公众号没有留言功能&#xff1f;2018年2月12日之后直到现在&#xff0c;新注册公众号的运营者会发现一个问题&#xff1a;无论是个人还是企业的公众号&#xff0c;在后台都找不到留言功能了。这对公众号来说绝对是一个极差的体验&#xff0c;少了一个这么重要的功能&…

万村乐数字乡村系统开源代码:革命性引领,助推乡村振兴新篇章

如今&#xff0c;国际社会普遍认为信息化、数字化已是重大且不可逆转的发展趋势&#xff0c;如何让广大农村地区充分分享到这个发展带来的红利&#xff0c;从而提升农村的经济活力&#xff0c;确保村民生活质量不断优化&#xff0c;已然成为我们需要认真研究并积极解决的重大议…

Window下编写的sh文件在Linux/Docker中无法使用

Window下编写的sh文件在Linux/Docker中无法使用 一、sh文件目的1.1 初始状态1.2 目的 二、过程与异常2.1 首先获取标准ubuntu20.04 - 正常2.2 启动ubuntu20.04容器 - 正常2.3 执行windows下写的preInstall文件 - 报错 三、检查和处理3.1 评估异常3.2 处理异常3.3 调整后运行测试…

uniapp+vue基于Android的图书馆借阅系统qb4y3-nodejs-php-pyton

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 框架支持:springboot/django/php/Ssm/flask/express均支持 前端开发:vue 语言&#xff1a;pythonjavanode.jsphp均支持 运行软件:idea/eclip…

2023天津公租房网上登记流程图,注册到信息填写

2023年天津市公共租赁住房网上登记流程图 小编为大家整理了天津市公共租赁住房网上登记流程&#xff0c;从登记到填写信息。 想要体验的朋友请看一下。 申请天津公共租赁住房时拒绝申报家庭情况会怎样&#xff1f; 天津市住房保障家庭在享受住房保障期间&#xff0c;如在应申…

智慧草莓基地:Java与SpringBoot的技术革新

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…