集成grpc,普通对象与grpc对象转换

集成grpc,普通对象与grpc对象转换

分布式开发涉及到远程过程调用即RPC。需要集成grpc。但如果想无缝集成,则涉及到普通的请求对象转换为grpc请求对象。
由于null不能序列化,所以grpc的对象属性都会有默认值,这在开发中,很难区分,到底请求传的是默认值还是请求本身携带的值。所以使用protocol buffers 的oneof关键字,用于规避默认值。
新建员工类

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Set;



public class EmpOne {
    private Long empIdOne;

    private String empNameOne;

    private Boolean empSexOne;

    private Long totalAssetOne;

    private List<String> skills;

    private Set<Integer> lucks;

    private Map<String, String> relations;

    private Date bornDate;

    private Timestamp createTime;

    private BigDecimal salary;
    
    private DeptOne dept;

    // ... 省略 get set
}

新建部门类

public class DeptOne {

    private Long deptIdOne;

    private String deptNameOne;

    private Byte deptTypeOne;
    // 省略 get set 
}

proto文件

syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.lyf.grpc";
option java_outer_classname = "EmpProto";

message EmpOne {
    oneof oneof_empId {
        int64 empIdOne = 4;
    }
    oneof oneof_totalAssetOne {
        int64 totalAssetOne = 8;
    }
    oneof oneof_empName {
        string empNameOne = 5;
    }
    oneof oneof_empSex {
        bool empSexOne = 6;
    }
    DeptOne dept = 7;
    repeated string skills = 9;
    repeated int32 lucks = 10;
    map<string, string> relations = 11;
    oneof oneof_bornDate {
        string bornDate = 12;
    }
    oneof oneof_createTime {
        string createTime = 13;
    }
    oneof oneof_salary {
        string salary = 14;
    }
}

message DeptOne {
    oneof oneof_deptId {
        int32 deptIdOne = 4;
    }
    oneof oneof_deptName {
        string deptNameOne = 5;
    }
    oneof oneof_deptType {
        int32 deptTypeOne = 6;
    }
}

单元测试代码

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.protobuf.util.JsonFormat;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author 
 * @Date 2019/8/12 0012 上午 11:40
 */
public class EmpOneTest {

    /**
     * oneof  普通请求转grpc请求,再转普通请求
     * @throws IOException
     */
    @Test
    public void testOneCommonRequestTransformToGrpcRequest() throws IOException {
        oneCommonRequestTransformToGrpcRequest();
    }

    public static void oneCommonRequestTransformToGrpcRequest() throws IOException {
        DeptOne dept = new DeptOne();
        dept.setDeptIdOne(0L);
        dept.setDeptNameOne(StringUtils.EMPTY);
        dept.setDeptTypeOne((byte)0);

        List<String> skills = new ArrayList<>();
        skills.add("EDVSD");

        Set<Integer> lucks = new HashSet<>();

        EmpOne emp = new EmpOne();
        emp.setEmpIdOne(0L);
        emp.setEmpNameOne(StringUtils.EMPTY);
        emp.setEmpSexOne(false);
        emp.setDept(dept);

        emp.setSkills(skills);
        emp.setLucks(lucks);
        emp.setBornDate(new java.sql.Date(System.currentTimeMillis()));
        emp.setCreateTime(new java.sql.Timestamp(System.currentTimeMillis()));
        emp.setSalary(new BigDecimal("22.33"));

        Gson gson = new GsonBuilder().serializeNulls()
                .setPrettyPrinting()
                .registerTypeAdapter(java.sql.Timestamp.class, new TimeStampGSON())
                .registerTypeAdapter(java.sql.Date.class, new SqlDateGSON())
                .create();
        String empJson = gson.toJson(emp);
        System.out.println("普通对象json==============");
        System.out.println(empJson);

        EmpOne.Builder builder = EmpOne.newBuilder();

        JsonFormat.parser().merge(empJson, builder);
        EmpOne empOneGrpc = builder.build();

        StringBuilder sb = new StringBuilder();
        JsonFormat.printer()
                .includingDefaultValueFields() // 设置采用默认值,当集合为空的时候会使用[]表示,map为空的时候采用{},这样可能有效防止直接使用而遇到的空指针
                .appendTo(empOneGrpc, sb);
        System.out.println("grpc对象Json==============");
        // 可以观察到普通对象json与grpcJson的区别,grpcJson对象字段为null的字段不显示,集合或map为空,则使用以上规则处理了
        System.out.println(sb);

        Gson gson2 = new GsonBuilder()
                .setPrettyPrinting()
                .serializeNulls()
                .registerTypeAdapter(java.sql.Timestamp.class, new TimeStampGSON())
                .registerTypeAdapter(java.sql.Date.class, new SqlDateGSON())
                .create();
        EmpOne vo = gson2.fromJson(sb.toString(), EmpOne.class);

        System.out.println("普通对象json==============");
        System.out.println(gson2.toJson(vo));
    }
}

自定义TypeAdapter,需要实现JsonSerializer<T>, JsonDeserializer<T>两个接口

import com.google.gson.*;

import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TimeStampGSON implements JsonSerializer<Timestamp>, JsonDeserializer<Timestamp> {
    private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public JsonElement serialize(Timestamp timestamp, Type type, JsonSerializationContext jsonSerializationContext) {
        String dfString = format.format(new Date(timestamp.getTime()));
        return new JsonPrimitive(dfString);
    }

    @Override
    public Timestamp deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        if (!(jsonElement instanceof JsonPrimitive)) {
            throw new JsonParseException("The date should be a string value");
        }

        try {
            Date date = format.parse(jsonElement.getAsString());
            return new Timestamp(date.getTime());
        } catch (ParseException e) {
            throw new JsonParseException(e);
        }
    }
}


import com.google.gson.*;

import java.lang.reflect.Type;
import java.sql.Date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class SqlDateGSON implements JsonSerializer<Date>, JsonDeserializer<Date> {
    private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    @Override
    public Date deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        if (!(jsonElement instanceof JsonPrimitive)) {
            throw new JsonParseException("The date should be a string value");
        }
        System.out.println(jsonElement.getAsString());
        java.util.Date date = null;
        Date date1 = null;
        try {
            date = format.parse(jsonElement.getAsString());
            date1 = new Date(date.getTime());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date1;
    }

    @Override
    public JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) {
        String dateFormatAsString = format.format(new Date(date.getTime()));
        return new JsonPrimitive(dateFormatAsString);
    }
}

测试结果

普通对象json==============
{
  "empIdOne": 0,
  "empNameOne": "",
  "empSexOne": false,
  "totalAssetOne": null,
  "skills": [
    "EDVSD"
  ],
  "lucks": [],
  "relations": null,
  "bornDate": "2019-08-12",
  "createTime": "2019-08-12 13:39:14",
  "salary": 22.33,
  "dept": {
    "deptIdOne": 0,
    "deptNameOne": "",
    "deptTypeOne": 0
  }
}
grpc对象Json==============
{
  "empIdOne": "0",
  "empNameOne": "",
  "empSexOne": false,
  "dept": {
    "deptIdOne": 0,
    "deptNameOne": "",
    "deptTypeOne": 0
  },
  "skills": ["EDVSD"],
  "lucks": [],
  "relations": {
  },
  "bornDate": "2019-08-12",
  "createTime": "2019-08-12 13:39:14",
  "salary": "22.33"
}
普通对象json==============
{
  "empIdOne": 0,
  "empNameOne": "",
  "empSexOne": false,
  "totalAssetOne": null,
  "skills": [
    "EDVSD"
  ],
  "lucks": [],
  "relations": {},
  "bornDate": "2019-08-12",
  "createTime": "2019-08-12 13:39:14",
  "salary": 22.33,
  "dept": {
    "deptIdOne": 0,
    "deptNameOne": "",
    "deptTypeOne": 0
  }
}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java + gRPC + grpc-gateway 的实践主要分为以下几个步骤: 1. 定义 proto 文件 在 proto 文件中定义需要调用的服务以及方法,同时指定请求和响应的数据类型。例如: ``` syntax = "proto3"; package example; service ExampleService { rpc ExampleMethod (ExampleRequest) returns (ExampleResponse) {} } message ExampleRequest { string example_field = 1; } message ExampleResponse { string example_field = 1; } ``` 2. 使用 protoc 编译 proto 文件 使用 protoc 编译 proto 文件,生成 Java 代码。例如: ``` protoc --java_out=./src/main/java ./example.proto ``` 3. 实现 gRPC 服务 在 Java 代码中实现定义的 gRPC 服务,例如: ``` public class ExampleServiceImpl extends ExampleServiceGrpc.ExampleServiceImplBase { @Override public void exampleMethod(ExampleRequest request, StreamObserver<ExampleResponse> responseObserver) { // 实现具体逻辑 ExampleResponse response = ExampleResponse.newBuilder().setExampleField("example").build(); responseObserver.onNext(response); responseObserver.onCompleted(); } } ``` 4. 启动 gRPC 服务器 使用 gRPC 提供的 ServerBuilder 构建 gRPC 服务器,并启动服务器。例如: ``` Server server = ServerBuilder.forPort(8080).addService(new ExampleServiceImpl()).build(); server.start(); ``` 5. 集成 grpc-gateway 使用 grpc-gateway 可以将 gRPC 服务转换为 HTTP/JSON API。在 proto 文件中添加以下内容: ``` import "google/api/annotations.proto"; service ExampleService { rpc ExampleMethod (ExampleRequest) returns (ExampleResponse) { option (google.api.http) = { post: "/example" body: "*" }; } } ``` 在 Java 代码中添加以下内容: ``` Server httpServer = ServerBuilder.forPort(8081).addService(new ExampleServiceImpl()).build(); httpServer.start(); String grpcServerUrl = "localhost:8080"; String httpServerUrl = "localhost:8081"; ProxyServerConfig proxyConfig = new ProxyServerConfig(grpcServerUrl, httpServerUrl, "/example"); HttpProxyServer httpProxyServer = new HttpProxyServer(proxyConfig); httpProxyServer.start(); ``` 6. 测试 使用 HTTP/JSON API 调用 gRPC 服务,例如: ``` POST http://localhost:8081/example Content-Type: application/json { "example_field": "example" } ``` 以上就是 Java + gRPC + grpc-gateway 的实践步骤。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值