Commit 795ebdd6 authored by liuyan's avatar liuyan

add:增加测试grpc代码和项目结构说明

parent 5a40de11
File added
...@@ -42,6 +42,11 @@ ...@@ -42,6 +42,11 @@
<groupId>mysql</groupId> <groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>net.devh</groupId>-->
<!-- <artifactId>grpc-spring-boot-starter</artifactId>-->
<!-- <version>2.15.0.RELEASE</version>-->
<!-- </dependency>-->
<!-- 核心模块--> <!-- 核心模块-->
<dependency> <dependency>
...@@ -61,10 +66,60 @@ ...@@ -61,10 +66,60 @@
<artifactId>ruoyi-generator</artifactId> <artifactId>ruoyi-generator</artifactId>
</dependency> </dependency>
<!-- gRPC 核心库 -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.56.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.56.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.56.1</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<extensions>
<!-- 引入 os-maven-plugin 插件 -->
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.1</version>
</extension>
</extensions>
<plugins> <plugins>
<!--protoc-gen-grpc-java 是一个用于 Protocol Buffers(Protobuf)的代码生成插件-->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<!-- 指定 protoc 编译器的依赖 -->
<protocArtifact>com.google.protobuf:protoc:3.21.12:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<!-- 指定 protoc-gen-grpc-java 插件的依赖 -->
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.56.1:exe:${os.detected.classifier}</pluginArtifact>
<protoSourceRoot>src/main/proto</protoSourceRoot>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
...@@ -93,4 +148,4 @@ ...@@ -93,4 +148,4 @@
<finalName>${project.artifactId}</finalName> <finalName>${project.artifactId}</finalName>
</build> </build>
</project> </project>
\ No newline at end of file
package com.ruoyi;
import com.ruoyi.client.server.GrpcFileServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @return
* @Version: v1.0
* @Author: LiuYan
* @Date 2025-4-12 15:35
*
* 服务启动以后需要回调启动grpc服务
*
**/
@Component
@Order(1) // 多个 Runner 时定义执行顺序(值越小优先级越高)
public class MyCommandLineRunner implements CommandLineRunner {
@Autowired
GrpcFileServer grpcFileServer;
@Override
public void run(String... args) {
grpcFileServer.initServer();
}
}
package com.ruoyi.client.server;
import com.ruoyi.client.service.FileServiceImpl;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
//自己实现的grpc服务类
@Component
public class GrpcFileServer {
@Autowired
private FileServiceImpl fileServiceImpl;
public void initServer(){
try {
// 创建服务实例
Server server = ServerBuilder.forPort(50051)
.addService(fileServiceImpl) // 关键控制器注册
.build();
server.start();
System.out.println("Server started on port 50051");
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
//当JVM关闭时回调钩子,关闭grpc服务
server.shutdown();
System.out.println("Server stopped");
}));
//保持主进程不退出持续监控
server.awaitTermination();
}catch (Exception e){
e.printStackTrace();
}
}
}
package com.ruoyi.client.service;
import com.google.protobuf.ByteString;
import com.ruoyi.grpc.file.*;
import io.grpc.stub.StreamObserver;
import org.springframework.stereotype.Service;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@Service
public class FileServiceImpl extends FileServiceGrpc.FileServiceImplBase {
@Override
public StreamObserver<FileUploadRequest> uploadFile(StreamObserver<FileUploadResponse> responseObserver) {
return new StreamObserver<FileUploadRequest>() {
private String filename;
private FileOutputStream fos;
private long totalSize = 0;
@Override
public void onNext(FileUploadRequest request) {
if (request.hasFilename()) {
filename = request.getFilename();
try {
fos = new FileOutputStream("server_files/" + filename);
} catch (IOException e) {
responseObserver.onError(e);
}
} else {
try {
byte[] chunk = request.getChunk().toByteArray();
totalSize += chunk.length;
fos.write(chunk);
} catch (IOException e) {
responseObserver.onError(e);
}
}
}
@Override
public void onError(Throwable t) {
System.err.println("Upload failed: " + t.getMessage());
}
@Override
public void onCompleted() {
try {
fos.close();
responseObserver.onNext(FileUploadResponse.newBuilder()
.setStatus("Success")
.setSize(totalSize)
.build());
responseObserver.onCompleted();
} catch (IOException e) {
responseObserver.onError(e);
}
}
};
}
@Override
public void downloadFile(FileDownloadRequest request,
StreamObserver<FileDownloadResponse> responseObserver) {
try {
java.io.File file = new java.io.File("server_files/" + request.getFilename());
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[64 * 1024]; // 64KB chunks
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
responseObserver.onNext(FileDownloadResponse.newBuilder()
.setChunk(ByteString.copyFrom(buffer, 0, bytesRead))
.build());
}
fis.close();
responseObserver.onCompleted();
} catch (IOException e) {
responseObserver.onError(e);
}
}
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: file.proto
package com.ruoyi.grpc.file;
public final class File {
private File() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
static final com.google.protobuf.Descriptors.Descriptor
internal_static_FileUploadRequest_descriptor;
static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_FileUploadRequest_fieldAccessorTable;
static final com.google.protobuf.Descriptors.Descriptor
internal_static_FileUploadResponse_descriptor;
static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_FileUploadResponse_fieldAccessorTable;
static final com.google.protobuf.Descriptors.Descriptor
internal_static_FileDownloadRequest_descriptor;
static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_FileDownloadRequest_fieldAccessorTable;
static final com.google.protobuf.Descriptors.Descriptor
internal_static_FileDownloadResponse_descriptor;
static final
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internal_static_FileDownloadResponse_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
String[] descriptorData = {
"\n\nfile.proto\"@\n\021FileUploadRequest\022\022\n\010fil" +
"ename\030\001 \001(\tH\000\022\017\n\005chunk\030\002 \001(\014H\000B\006\n\004data\"2" +
"\n\022FileUploadResponse\022\016\n\006status\030\001 \001(\t\022\014\n\004" +
"size\030\002 \001(\003\"\'\n\023FileDownloadRequest\022\020\n\010fil" +
"ename\030\001 \001(\t\"%\n\024FileDownloadResponse\022\r\n\005c" +
"hunk\030\001 \001(\0142\205\001\n\013FileService\0227\n\nUploadFile" +
"\022\022.FileUploadRequest\032\023.FileUploadRespons" +
"e(\001\022=\n\014DownloadFile\022\024.FileDownloadReques" +
"t\032\025.FileDownloadResponse0\001B\035\n\023com.ruoyi." +
"grpc.fileP\001Z\004./pbb\006proto3"
};
descriptor = com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
});
internal_static_FileUploadRequest_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_FileUploadRequest_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_FileUploadRequest_descriptor,
new String[] { "Filename", "Chunk", "Data", });
internal_static_FileUploadResponse_descriptor =
getDescriptor().getMessageTypes().get(1);
internal_static_FileUploadResponse_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_FileUploadResponse_descriptor,
new String[] { "Status", "Size", });
internal_static_FileDownloadRequest_descriptor =
getDescriptor().getMessageTypes().get(2);
internal_static_FileDownloadRequest_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_FileDownloadRequest_descriptor,
new String[] { "Filename", });
internal_static_FileDownloadResponse_descriptor =
getDescriptor().getMessageTypes().get(3);
internal_static_FileDownloadResponse_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_FileDownloadResponse_descriptor,
new String[] { "Chunk", });
}
// @@protoc_insertion_point(outer_class_scope)
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: file.proto
package com.ruoyi.grpc.file;
public interface FileDownloadRequestOrBuilder extends
// @@protoc_insertion_point(interface_extends:FileDownloadRequest)
com.google.protobuf.MessageOrBuilder {
/**
* <code>string filename = 1;</code>
* @return The filename.
*/
String getFilename();
/**
* <code>string filename = 1;</code>
* @return The bytes for filename.
*/
com.google.protobuf.ByteString
getFilenameBytes();
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: file.proto
package com.ruoyi.grpc.file;
public interface FileDownloadResponseOrBuilder extends
// @@protoc_insertion_point(interface_extends:FileDownloadResponse)
com.google.protobuf.MessageOrBuilder {
/**
* <code>bytes chunk = 1;</code>
* @return The chunk.
*/
com.google.protobuf.ByteString getChunk();
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: file.proto
package com.ruoyi.grpc.file;
public interface FileUploadRequestOrBuilder extends
// @@protoc_insertion_point(interface_extends:FileUploadRequest)
com.google.protobuf.MessageOrBuilder {
/**
* <code>string filename = 1;</code>
* @return Whether the filename field is set.
*/
boolean hasFilename();
/**
* <code>string filename = 1;</code>
* @return The filename.
*/
String getFilename();
/**
* <code>string filename = 1;</code>
* @return The bytes for filename.
*/
com.google.protobuf.ByteString
getFilenameBytes();
/**
* <code>bytes chunk = 2;</code>
* @return Whether the chunk field is set.
*/
boolean hasChunk();
/**
* <code>bytes chunk = 2;</code>
* @return The chunk.
*/
com.google.protobuf.ByteString getChunk();
public FileUploadRequest.DataCase getDataCase();
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: file.proto
package com.ruoyi.grpc.file;
public interface FileUploadResponseOrBuilder extends
// @@protoc_insertion_point(interface_extends:FileUploadResponse)
com.google.protobuf.MessageOrBuilder {
/**
* <code>string status = 1;</code>
* @return The status.
*/
String getStatus();
/**
* <code>string status = 1;</code>
* @return The bytes for status.
*/
com.google.protobuf.ByteString
getStatusBytes();
/**
* <code>int64 size = 2;</code>
* @return The size.
*/
long getSize();
}
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.ruoyi.grpc.file";
option go_package = "./pb";
message FileUploadRequest {
//表示这两个字段只能有一个被设置值,要么是文件名称要么是文件块
oneof data {
string filename = 1;
bytes chunk = 2;
}
}
message FileUploadResponse {
string status = 1;
int64 size = 2;
}
message FileDownloadRequest {
string filename = 1;
}
message FileDownloadResponse {
bytes chunk = 1;
}
service FileService {
rpc UploadFile(stream FileUploadRequest) returns (FileUploadResponse);
rpc DownloadFile(FileDownloadRequest) returns (stream FileDownloadResponse);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment