DEV Community

HyperRedStart
HyperRedStart

Posted on

Java Spring VS Go gRPC

Spring boot

Client Side

以下 Entity 會以自動產生的方式給予 PR
EntityController 則是底層功能
Entity Model

@Entity  
@Table(name = "CAR")  
public class Car extends EntityContoller {  
    @Id  
    @Column(name = "ID")  
    @SerializedName("ID")  
    private Integer id;  

    @Column(name = "MODEL")  
    @SerializedName("MODEL")  
    private String model;  

    @Column(name = "MAKE")  
    @SerializedName("MAKE")  
    private String make;  

    @Column(name = "PREVIEW")  
    @SerializedName("PREVIEW")  
    private String preview;  

    @Column(name = "DESCRIPTION")  
    @SerializedName("DESCRIPTION")  
    private String description;  

    @Column(name = "PRICE")  
    @SerializedName("PRICE")  
    private Integer price;  

    public Car() {  
        super();  
    }  

    public Car(Integer id, String model, String make, String description, String preview, Integer price) {  
        super();  
        this.id = id;  
        this.model = model;  
        this.make = make;  
        this.preview = preview;  
        this.description = description;  
        this.price = price;  
    }  

    public Integer getId() {  
        return id;  
    }  

    public void setId(Integer id) {  
        this.id = id;  
    }  

    public String getMake() {  
        return make;  
    }  

    public void setMake(String make) {  
        this.make = make;  
    }  

    public String getPreview() {  
        return preview;  
    }  

    public void setPreview(String preview) {  
        this.preview = preview;  
    }  

    public String getDescription() {  
        return description;  
    }  

    public void setDescription(String description) {  
        this.description = description;  
    }  

    public Integer getPrice() {  
        return price;  
    }  

    public void setPrice(Integer price) {  
        this.price = price;  
    }  

    public String getModel() {  
        return model;  
    }  

    public void setModel(String model) {  
        this.model = model;  
    }  
}
Enter fullscreen mode Exit fullscreen mode
@Entity  
@Table(name = "CAR_INFO")  
public class CarInfo extends EntityContoller {  

    @Id  
    @SerializedName("ID")  
    @Column(name = "ID")  
    private Integer id;  

    @Id  
    @SerializedName("CAR_OWNER")  
    @Column(name = "CAR_OWNER")  
    private String carOwner;  

    @Column(name = "CAR_TYPE")  
    @SerializedName("CAR_TYPE")  
    private String carType;  

    @Temporal(TemporalType.TIMESTAMP)  
    @Column(name = "DRIVE_DATE")  
    @SerializedName("DRIVE_DATE")  
    private Date driveDate;  

    @Column(name = "KM")  
    @SerializedName("KM")  
    private String km;  

    @Column(name = "TEST")  
    @SerializedName("TEST")  
    private String test;  

    @ManyToOne  
    @SerializedName("*CAR")  
    @JoinColumn(name = "ID", referencedColumnName = "ID", insertable = false, updatable = false)  
    private Car car = new Car();  

    public CarInfo() {  
        super();  
    }  

    public CarInfo(Integer id, String carOwner, String carType, Date driveDate, String km, String test, Car car) {  
        super();
        this.id = id;
        this.carOwner = carOwner;
        this.carType = carType;
        this.driveDate = driveDate;
        this.km = km;
        this.test = test;
        this.car = car;
    }  

    public Integer getId() {  
        return id;  
    }  
    public void setId(Integer value) {  
        id = value;  
    }  

    public String getCarOwner() {  
        return carOwner;  
    }  
    public void setCarOwner(String value) {  
        carOwner = value;  
    }  

    public Date getDriveDate() {  
        return driveDate;  
    }  
    public void setDriveDate(Date value) {  
        driveDate = value;  
    }  

    public String getKm() {  
        return km;  
    }  
    public void setKm(String value) {  
        km = value;  
    }  

    public String getTest() {  
        return test;  
    }  
    public void setTest(String value) {  
        test = value;  
    }  

    public String getCarType() {  
        return carType;  
    }  
    public void setCarType(String value) {  
        carType = value;  
    }  

    public Car getCar() {  
        return car;  
    }  
    public void setCar(Car value) {  
        car = value;  
    }  
}
Enter fullscreen mode Exit fullscreen mode

ViewModel

public class CarInfoViewModel extends ServiceImpl {  

    private String keyword;  
    private List<CarInfo> list;  
    private CarInfo selectedCarInfo;  

    private CarService carService = new CarServiceImpl();  
    public CarInfoViewModel() {
        super(new CarInfo());  
    }

    public List<CarInfo> getList(){  
        return list;  
    }  

    public void setSelectedCarInfo(CarInfo selectedCarInfo) {  
        this.selectedCarInfo = selectedCarInfo;  
    }  

    public CarInfo getSelectedCarInfo() {  
        return selectedCarInfo;  
    }  

    @Command  
    @NotifyChange("list")  
    public void search(){  
        list = carService.search(keyword);  
    }  
    public List<CarInfo> get {
        RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), gson.toJson(new CarInfo()));  
        retrofit2.Call<ResponseBody> call = entityServices.getNativeCarInfo(body);
        Type type = new TypeToken<List<CarInfo>>() {}.getType();  

        call.enqueue(new Callback<ResponseBody>() {  

            @Override  
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {  
                try {  
                    list = gson.fromJson(response.body().string(), type);  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  

            @Override  
            public void onFailure(Call<ResponseBody> call, Throwable t) {  
                System.out.println("Connection Failed");  
            }  
        });
    }

}
Enter fullscreen mode Exit fullscreen mode

View

<window title="Search" width="600px" border="normal" apply="org.zkoss.bind.BindComposer"
        viewModel="@id('vm') @init('demo.getting_started.mvvm.SearchViewModel')">
    <hbox align="center">
        Keyword:
        <textbox value="@bind(vm.keyword)" />
        <button label="Search" iconSclass="z-icon-search" onClick="@command('search')" />
    </hbox>
    <listbox height="160px" model="@bind(vm.carInfoList)" emptyMessage="No car found in the result"
             selectedItem="@bind(vm.selectedCarInfo)" style="margin-top:10px">
        <listhead>
            <listheader label="ID" />
            <listheader label="Car Owner" />
            <listheader label="Car Type" />
            <listheader label="Drive Date" />
            <listheader label="KM" />
        </listhead>
        <template name="model">
            <listitem>
                <listcell label="@bind(each.id)"></listcell>
                <listcell label="@bind(each.carOwner)"></listcell>
                <listcell label="@bind(each.carType)"></listcell>
                <listcell label="@bind(each.driveDate) @converter('formatedDate',format='yyyy/MM/dd')"></listcell>
                <listcell label="@bind(each.km)"></listcell>
            </listitem>
        </template>
    </listbox>
    <hbox style="margin-top:20px" visible="@bind(not empty vm.selectedCarInfo)">
        <image src="@bind(vm.selectedCarInfo.car.preview)" style="padding:10px" />
        <vbox>
            <hlayout>
                Model : <label value="@bind(vm.selectedCarInfo.car.model)" style="font-weight:bold"/>
            </hlayout>
            <hlayout>
                Make : <label value="@bind(vm.selectedCarInfo.car.make)" style="font-weight:bold"/>
            </hlayout>
            <hlayout>
                Price :
                <span>$<label value="@bind(vm.selectedCarInfo.car.price)" style="font-weight:bold"/></span>
            </hlayout>
            <label value="@bind(vm.selectedCarInfo.car.description)" />
        </vbox>
    </hbox>
</window>

Enter fullscreen mode Exit fullscreen mode

Server Side

PR 如需複雜方式必須去 Spring Boot 新增,並將 Entity Model 放入Spring Boot

CarInfoContoller

@RestController  
@RequestMapping("/carinfo")  
public class CarInfoContoller {  

    @Autowired  
    private CarInfoRepository carInfoRepository;  

    @Autowired  
    CarInfoService CarInfoService;  

    @GetMapping("/paging") // native sql  
    public List<CarInfo> getCarInfoByNativeSQL(@PageableDefault(size = 10) Pageable pageable) {  
        Page<CarInfo> contacts = this.carInfoRepository.findAllUsersWithPaginationByNativeSQL(pageable);  
        return contacts.getContent();  
    }
}
Enter fullscreen mode Exit fullscreen mode
@Repository  
public interface CarInfoRepository extends JpaRepository<CarInfo, Long> {
    @Query(value = "SELECT * FROM CarInfo ORDERBY CAR_OWNER", countQuery = "SELECT count(*) FROM CarInfo", nativeQuery = true)  
    Page<CarInfo> findAllUsersWithPaginationByNativeSQL(Pageable pageable);
}

Enter fullscreen mode Exit fullscreen mode

JpaRepository 支援關鍵字方法語法

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Between findByStartDateBetween … where x.startDate between 1? and ?2
LessThan findByAgeLessThan … where x.age < ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(


Collection<Age> ages

)|… where x.age in ?1 |
| NotIn| findByAgeNotIn(

Collection<Age> age

)|… where x.age not in ?1 |
| True| findByActiveTrue()|… where x.active = true |
| False| findByActiveFalse()|… where x.active = false |

gRPC

#透過 protoc tool 產生code
$ protoc -I car_info/ car_info/car_info.proto --go_out=plugins=grpc:car_info
#透過 maven plugin  產生code 
$ mvn protobuf:compile
Enter fullscreen mode Exit fullscreen mode

Golang Service Side

syntax = "proto3";
// 生成的程式在 Golang 中將會屬於 `pb` 套件。
option java_multiple_files = true;
option java_package = "io.grpc.examples.car_info";
option java_outer_classname = "CarInfoProto";
option objc_class_prefix = "CARINFO";

package  car_info;
// CarInfo 定義了一個服務。
service  CarInfoService {
// GetList 會接收 CarInfoGetListRequest 資料,最終會回傳 CarInfoGetListResponse
rpc  GetList (CarInfoGetListRequest) returns (CarInfoGetListResponse) {}
rpc  InsertList (CarInfoInsertListRequest) returns (CarInfoInsertListResponse) {}
}

message  CarInfo {
    string  CarOwner = 1;
    string  CarType = 2;
    string  DriveDate = 3;
    string  km = 4;
    string  test = 5;
}

// Car Info Get List 需求 list
message  CarInfoGetListRequest { }
// Car Info Get List 回應 list
message  CarInfoGetListResponse {
    repeated  CarInfo  cars = 1;
}

// Car Info Get List 需求list
message  CarInfoInsertListRequest {
    repeated  CarInfo  cars = 1;
}
// Car Info Get List 回應 list
message  CarInfoInsertListResponse {
    repeated  CarInfo  cars = 1;
}
Enter fullscreen mode Exit fullscreen mode

透過工具產生 code go 版本

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: car_info.proto
package car_info

import (
    context "context"
    fmt "fmt"
    math "math"

    proto "github.com/golang/protobuf/proto"
    grpc "google.golang.org/grpc"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

type CarInfo struct {
    CarOwner             string   `protobuf:"bytes,1,opt,name=CarOwner,proto3" json:"CarOwner,omitempty"`
    CarType              string   `protobuf:"bytes,2,opt,name=CarType,proto3" json:"CarType,omitempty"`
    DriveDate            string   `protobuf:"bytes,3,opt,name=DriveDate,proto3" json:"DriveDate,omitempty"`
    Km                   string   `protobuf:"bytes,4,opt,name=km,proto3" json:"km,omitempty"`
    Test                 string   `protobuf:"bytes,5,opt,name=test,proto3" json:"test,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

func (m *CarInfo) Reset()         { *m = CarInfo{} }
func (m *CarInfo) String() string { return proto.CompactTextString(m) }
func (*CarInfo) ProtoMessage()    {}
func (*CarInfo) Descriptor() ([]byte, []int) {
    return fileDescriptor_6109e1b82e86989a, []int{0}
}

func (m *CarInfo) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_CarInfo.Unmarshal(m, b)
}
func (m *CarInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_CarInfo.Marshal(b, m, deterministic)
}
func (m *CarInfo) XXX_Merge(src proto.Message) {
    xxx_messageInfo_CarInfo.Merge(m, src)
}
func (m *CarInfo) XXX_Size() int {
    return xxx_messageInfo_CarInfo.Size(m)
}
func (m *CarInfo) XXX_DiscardUnknown() {
    xxx_messageInfo_CarInfo.DiscardUnknown(m)
}

var xxx_messageInfo_CarInfo proto.InternalMessageInfo

func (m *CarInfo) GetCarOwner() string {
    if m != nil {
        return m.CarOwner
    }
    return ""
}

func (m *CarInfo) GetCarType() string {
    if m != nil {
        return m.CarType
    }
    return ""
}

func (m *CarInfo) GetDriveDate() string {
    if m != nil {
        return m.DriveDate
    }
    return ""
}

func (m *CarInfo) GetKm() string {
    if m != nil {
        return m.Km
    }
    return ""
}

func (m *CarInfo) GetTest() string {
    if m != nil {
        return m.Test
    }
    return ""
}

// Car Info Get List 需求 list
type CarInfoGetListRequest struct {
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

func (m *CarInfoGetListRequest) Reset()         { *m = CarInfoGetListRequest{} }
func (m *CarInfoGetListRequest) String() string { return proto.CompactTextString(m) }
func (*CarInfoGetListRequest) ProtoMessage()    {}
func (*CarInfoGetListRequest) Descriptor() ([]byte, []int) {
    return fileDescriptor_6109e1b82e86989a, []int{1}
}

func (m *CarInfoGetListRequest) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_CarInfoGetListRequest.Unmarshal(m, b)
}
func (m *CarInfoGetListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_CarInfoGetListRequest.Marshal(b, m, deterministic)
}
func (m *CarInfoGetListRequest) XXX_Merge(src proto.Message) {
    xxx_messageInfo_CarInfoGetListRequest.Merge(m, src)
}
func (m *CarInfoGetListRequest) XXX_Size() int {
    return xxx_messageInfo_CarInfoGetListRequest.Size(m)
}
func (m *CarInfoGetListRequest) XXX_DiscardUnknown() {
    xxx_messageInfo_CarInfoGetListRequest.DiscardUnknown(m)
}

var xxx_messageInfo_CarInfoGetListRequest proto.InternalMessageInfo

// Car Info Get List 回應 list
type CarInfoGetListResponse struct {
    Cars                 []*CarInfo `protobuf:"bytes,1,rep,name=cars,proto3" json:"cars,omitempty"`
    XXX_NoUnkeyedLiteral struct{}   `json:"-"`
    XXX_unrecognized     []byte     `json:"-"`
    XXX_sizecache        int32      `json:"-"`
}

func (m *CarInfoGetListResponse) Reset()         { *m = CarInfoGetListResponse{} }
func (m *CarInfoGetListResponse) String() string { return proto.CompactTextString(m) }
func (*CarInfoGetListResponse) ProtoMessage()    {}
func (*CarInfoGetListResponse) Descriptor() ([]byte, []int) {
    return fileDescriptor_6109e1b82e86989a, []int{2}
}

func (m *CarInfoGetListResponse) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_CarInfoGetListResponse.Unmarshal(m, b)
}
func (m *CarInfoGetListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_CarInfoGetListResponse.Marshal(b, m, deterministic)
}
func (m *CarInfoGetListResponse) XXX_Merge(src proto.Message) {
    xxx_messageInfo_CarInfoGetListResponse.Merge(m, src)
}
func (m *CarInfoGetListResponse) XXX_Size() int {
    return xxx_messageInfo_CarInfoGetListResponse.Size(m)
}
func (m *CarInfoGetListResponse) XXX_DiscardUnknown() {
    xxx_messageInfo_CarInfoGetListResponse.DiscardUnknown(m)
}

var xxx_messageInfo_CarInfoGetListResponse proto.InternalMessageInfo

func (m *CarInfoGetListResponse) GetCars() []*CarInfo {
    if m != nil {
        return m.Cars
    }
    return nil
}

type CarInfoInsertListRequest struct {
    Cars                 []*CarInfo `protobuf:"bytes,1,rep,name=cars,proto3" json:"cars,omitempty"`
    XXX_NoUnkeyedLiteral struct{}   `json:"-"`
    XXX_unrecognized     []byte     `json:"-"`
    XXX_sizecache        int32      `json:"-"`
}

func (m *CarInfoInsertListRequest) Reset()         { *m = CarInfoInsertListRequest{} }
func (m *CarInfoInsertListRequest) String() string { return proto.CompactTextString(m) }
func (*CarInfoInsertListRequest) ProtoMessage()    {}
func (*CarInfoInsertListRequest) Descriptor() ([]byte, []int) {
    return fileDescriptor_6109e1b82e86989a, []int{3}
}

func (m *CarInfoInsertListRequest) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_CarInfoInsertListRequest.Unmarshal(m, b)
}
func (m *CarInfoInsertListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_CarInfoInsertListRequest.Marshal(b, m, deterministic)
}
func (m *CarInfoInsertListRequest) XXX_Merge(src proto.Message) {
    xxx_messageInfo_CarInfoInsertListRequest.Merge(m, src)
}
func (m *CarInfoInsertListRequest) XXX_Size() int {
    return xxx_messageInfo_CarInfoInsertListRequest.Size(m)
}
func (m *CarInfoInsertListRequest) XXX_DiscardUnknown() {
    xxx_messageInfo_CarInfoInsertListRequest.DiscardUnknown(m)
}

var xxx_messageInfo_CarInfoInsertListRequest proto.InternalMessageInfo

func (m *CarInfoInsertListRequest) GetCars() []*CarInfo {
    if m != nil {
        return m.Cars
    }
    return nil
}

// Car Info Get List 回應 list
type CarInfoInsertListResponse struct {
    Cars                 []*CarInfo `protobuf:"bytes,1,rep,name=cars,proto3" json:"cars,omitempty"`
    XXX_NoUnkeyedLiteral struct{}   `json:"-"`
    XXX_unrecognized     []byte     `json:"-"`
    XXX_sizecache        int32      `json:"-"`
}

func (m *CarInfoInsertListResponse) Reset()         { *m = CarInfoInsertListResponse{} }
func (m *CarInfoInsertListResponse) String() string { return proto.CompactTextString(m) }
func (*CarInfoInsertListResponse) ProtoMessage()    {}
func (*CarInfoInsertListResponse) Descriptor() ([]byte, []int) {
    return fileDescriptor_6109e1b82e86989a, []int{4}
}

func (m *CarInfoInsertListResponse) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_CarInfoInsertListResponse.Unmarshal(m, b)
}
func (m *CarInfoInsertListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_CarInfoInsertListResponse.Marshal(b, m, deterministic)
}
func (m *CarInfoInsertListResponse) XXX_Merge(src proto.Message) {
    xxx_messageInfo_CarInfoInsertListResponse.Merge(m, src)
}
func (m *CarInfoInsertListResponse) XXX_Size() int {
    return xxx_messageInfo_CarInfoInsertListResponse.Size(m)
}
func (m *CarInfoInsertListResponse) XXX_DiscardUnknown() {
    xxx_messageInfo_CarInfoInsertListResponse.DiscardUnknown(m)
}

var xxx_messageInfo_CarInfoInsertListResponse proto.InternalMessageInfo

func (m *CarInfoInsertListResponse) GetCars() []*CarInfo {
    if m != nil {
        return m.Cars
    }
    return nil
}

func init() {
    proto.RegisterType((*CarInfo)(nil), "car_info.CarInfo")
    proto.RegisterType((*CarInfoGetListRequest)(nil), "car_info.CarInfoGetListRequest")
    proto.RegisterType((*CarInfoGetListResponse)(nil), "car_info.CarInfoGetListResponse")
    proto.RegisterType((*CarInfoInsertListRequest)(nil), "car_info.CarInfoInsertListRequest")
    proto.RegisterType((*CarInfoInsertListResponse)(nil), "car_info.CarInfoInsertListResponse")
}

func init() { proto.RegisterFile("car_info.proto", fileDescriptor_6109e1b82e86989a) }

var fileDescriptor_6109e1b82e86989a = []byte{
    // 309 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x52, 0xdd, 0x4a, 0x02, 0x41,
    0x14, 0x6e, 0x56, 0x4b, 0x3d, 0x85, 0xd0, 0x81, 0x6a, 0x94, 0x20, 0xd9, 0x08, 0xbc, 0xda, 0x0b,
    0xa3, 0xeb, 0xf0, 0x87, 0x42, 0x08, 0x95, 0x2d, 0xe8, 0x32, 0xa6, 0xe5, 0x18, 0x8b, 0xb9, 0xb3,
    0xcd, 0x4c, 0x56, 0x97, 0xbd, 0x4a, 0x6f, 0xd1, 0xdb, 0x85, 0xd3, 0xb8, 0x56, 0x5b, 0x51, 0x77,
    0x73, 0xbe, 0x3f, 0xbe, 0x33, 0x1c, 0xa8, 0x46, 0x42, 0x5d, 0xc5, 0xc9, 0x58, 0x06, 0xa9, 0x92,
    0x46, 0x62, 0x79, 0x31, 0xfb, 0xcf, 0x0c, 0x4a, 0x5d, 0xa1, 0xfa, 0xc9, 0x58, 0x62, 0x1d, 0xca,
    0x5d, 0xa1, 0x86, 0x0f, 0x09, 0x29, 0xce, 0x1a, 0xac, 0x59, 0x09, 0xb3, 0x19, 0xb9, 0x95, 0x5d,
    0x3c, 0xa5, 0xc4, 0x3d, 0x4b, 0x2d, 0x46, 0xdc, 0x85, 0x4a, 0x4f, 0xc5, 0x33, 0xea, 0x09, 0x43,
    0xbc, 0x60, 0xb9, 0x25, 0x80, 0x55, 0xf0, 0x26, 0x53, 0x5e, 0xb4, 0xb0, 0x37, 0x99, 0x22, 0x42,
    0xd1, 0x90, 0x36, 0x7c, 0xd5, 0x22, 0xf6, 0xed, 0xef, 0xc0, 0x96, 0xab, 0x70, 0x4a, 0xe6, 0x2c,
    0xd6, 0x26, 0xa4, 0xbb, 0xfb, 0x39, 0x71, 0x0c, 0xdb, 0x5f, 0x09, 0x9d, 0xca, 0x44, 0x13, 0x1e,
    0x40, 0x31, 0x12, 0x4a, 0x73, 0xd6, 0x28, 0x34, 0xd7, 0x5b, 0x9b, 0x41, 0xb6, 0x9f, 0xd3, 0x87,
    0x96, 0xf6, 0xdb, 0xc0, 0x1d, 0xd0, 0x4f, 0x34, 0xa9, 0x8f, 0xe1, 0x7f, 0x8d, 0xe8, 0x40, 0xed,
    0x9b, 0x88, 0x7f, 0xd5, 0x68, 0xbd, 0x32, 0xa8, 0x3a, 0xe4, 0x9c, 0xd4, 0x2c, 0x8e, 0x08, 0x07,
    0x50, 0x72, 0x3b, 0xe1, 0x5e, 0xce, 0xf6, 0xf9, 0x1b, 0xea, 0x8d, 0x9f, 0x05, 0xef, 0x3d, 0xfc,
    0x15, 0xbc, 0x04, 0x58, 0xf6, 0x43, 0x3f, 0xe7, 0xc8, 0xed, 0x5f, 0xdf, 0xff, 0x55, 0xb3, 0x08,
    0xee, 0x1c, 0x41, 0x2d, 0x96, 0xc1, 0x8d, 0x4a, 0xa3, 0x80, 0x1e, 0xc5, 0x34, 0xbd, 0x25, 0x9d,
    0x19, 0x3b, 0x1b, 0xce, 0x39, 0x9a, 0x5f, 0xd5, 0x88, 0xbd, 0x78, 0xa5, 0x6e, 0x3b, 0xec, 0x0f,
    0x4e, 0x86, 0xd7, 0x6b, 0xf6, 0xd0, 0x0e, 0xdf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x22, 0xe2, 0x10,
    0xb0, 0x7a, 0x02, 0x00, 0x00,
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4

// CarInfoServiceClient is the client API for CarInfoService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type CarInfoServiceClient interface {
    // GetList 會接收 CarInfoGetListRequest 資料,最終會回傳 CarInfoGetListResponse
    GetList(ctx context.Context, in *CarInfoGetListRequest, opts ...grpc.CallOption) (*CarInfoGetListResponse, error)
    // rpc GetList (CarInfoGetListRequest) returns (stream CarInfo) {}
    InsertList(ctx context.Context, in *CarInfoInsertListRequest, opts ...grpc.CallOption) (*CarInfoInsertListResponse, error)
}

type carInfoServiceClient struct {
    cc *grpc.ClientConn
}

func NewCarInfoServiceClient(cc *grpc.ClientConn) CarInfoServiceClient {
    return &carInfoServiceClient{cc}
}

func (c *carInfoServiceClient) GetList(ctx context.Context, in *CarInfoGetListRequest, opts ...grpc.CallOption) (*CarInfoGetListResponse, error) {
    out := new(CarInfoGetListResponse)
    err := c.cc.Invoke(ctx, "/car_info.CarInfoService/GetList", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

func (c *carInfoServiceClient) InsertList(ctx context.Context, in *CarInfoInsertListRequest, opts ...grpc.CallOption) (*CarInfoInsertListResponse, error) {
    out := new(CarInfoInsertListResponse)
    err := c.cc.Invoke(ctx, "/car_info.CarInfoService/InsertList", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

// CarInfoServiceServer is the server API for CarInfoService service.
type CarInfoServiceServer interface {
    // GetList 會接收 CarInfoGetListRequest 資料,最終會回傳 CarInfoGetListResponse
    GetList(context.Context, *CarInfoGetListRequest) (*CarInfoGetListResponse, error)
    // rpc GetList (CarInfoGetListRequest) returns (stream CarInfo) {}
    InsertList(context.Context, *CarInfoInsertListRequest) (*CarInfoInsertListResponse, error)
}

func RegisterCarInfoServiceServer(s *grpc.Server, srv CarInfoServiceServer) {
    s.RegisterService(&_CarInfoService_serviceDesc, srv)
}

func _CarInfoService_GetList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(CarInfoGetListRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(CarInfoServiceServer).GetList(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/car_info.CarInfoService/GetList",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(CarInfoServiceServer).GetList(ctx, req.(*CarInfoGetListRequest))
    }
    return interceptor(ctx, in, info, handler)
}

func _CarInfoService_InsertList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(CarInfoInsertListRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(CarInfoServiceServer).InsertList(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/car_info.CarInfoService/InsertList",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(CarInfoServiceServer).InsertList(ctx, req.(*CarInfoInsertListRequest))
    }
    return interceptor(ctx, in, info, handler)
}

var _CarInfoService_serviceDesc = grpc.ServiceDesc{
    ServiceName: "car_info.CarInfoService",
    HandlerType: (*CarInfoServiceServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "GetList",
            Handler:    _CarInfoService_GetList_Handler,
        },
        {
            MethodName: "InsertList",
            Handler:    _CarInfoService_InsertList_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "car_info.proto",
}
Enter fullscreen mode Exit fullscreen mode

Entity 結構

type  CarInfo  struct {
    CarOwner string
    CarType string
    DriveDate time.Time
    Km string
    Test string
}
Enter fullscreen mode Exit fullscreen mode

取得清單方法

func (s *server) GetList(ctx context.Context, in *car_info.CarInfoGetListRequest) (*car_info.CarInfoGetListResponse, error) {
    var list []CarInfo
    car_list := []*car_info.CarInfo{}

    engine.Limit(1000, 0).Find(&list)
    orm, _ := json.Marshal(list)
    json.Unmarshal(orm, &car_list)

    return &car_info.CarInfoGetListResponse{Cars: car_list}, nil
}
Enter fullscreen mode Exit fullscreen mode

批次新增

func (s *server) InsertList(ctx context.Context, in *car_info.CarInfoInsertListRequest) (*car_info.CarInfoInsertListResponse, error) {
    var list []CarInfo

    orm, _ := json.Marshal(in.Cars)
    json.Unmarshal(orm, &list)
    for _, car := range list {
        engine.Insert(&car)
    }

    return &car_info.CarInfoInsertListResponse{Cars: in.Cars}, nil
}
Enter fullscreen mode Exit fullscreen mode

Java Client Side

public class CarInfoClient {
    private static final Logger logger = Logger.getLogger(CarInfoClient.class.getName());

    private final ManagedChannel channel;
    private final ServiceGrpc.ServiceBlockingStub blockingStub;

    public CarInfoClient(String host, int port) {
        this(ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build());
    }

    CarInfoClient(ManagedChannel channel) {
        this.channel = channel;
        blockingStub = ServiceGrpc.newBlockingStub(channel);
    }

    public void getList() {
        CarInfoGetListRequest request = CarInfoGetListRequest.newBuilder().build();
        CarInfoGetListResponse response;
        try {
            response = blockingStub.getList(request);
        } catch (StatusRuntimeException e) {
            logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
            return;
        }
        logger.info("CarList: " + response.getCarsList());
    }


    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    public static void main(String[] args) throws Exception {
        CarInfoClient client = new CarInfoClient("localhost", 50051);
        try {
            client.getList();
        } finally {
            client.shutdown();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Golang Client Side

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("連線失敗:_%v", err)
    }
    defer conn.Close()
    car_service := car_info.NewCarInfoServiceClient(conn)

    // insert
    var list []*car_info.CarInfo
    for i := 1; i <= 10; i++ {
        list = append(list, &car_info.CarInfo{CarOwner: strconv.Itoa(counter) + ":" + strconv.Itoa(i), CarType: "n"})
    }
    car_service.InsertList(context.Background(), &car_info.CarInfoInsertListRequest{Cars: list})
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)