上一篇讲了关于go基本的安装、环境搭建、项目搭建和运行,这一篇继续深入;
上一篇参考:使用 vsCode创建GO项目
1.1 go 的传参方式
我们通常使用gin 框架绑定函数创建接口,接口的参数都封装在了gin.Context对象中,通常使用 header用于参数的传递:
const NAME string = "name"
const USER_ID string = "user_id"
func GetParam(c *gin.Context) {
userId := c.GetHeader(USER_ID)
fmt.Println(userId)
name := c.GetHeader(NAME)
fmt.Println(name)
name3, ok := c.GetPostFormArray(NAME)
fmt.Println(name3)
fmt.Println(ok)
}
1.2 go 连接 mysql
连接首先需要配置application.yaml
# database config
database:
driver: ${DATABASE_DRIVER:mysql} #mysql
table-prefix: mydb
mysql-dsn: ${DATABASE_USER:root}:${DATABASE_PASSWORD:password}@tcp(${DATABASE_HOST:localhost}:${DATABASE_PORT:3306})/${DATABASE_NAME:mydb}?charset=utf8mb4&parseTime=True&loc=Local
max-idle-conns: ${DATABASE_MAX_IDLE_CONNS:10}
max-open-conns: ${DATABASE_MAX_OPEN_CONNS:100}
driver/mysql-dsn 用于gorm创建数据库的连接,
gorm 是一个 Go 语言编写的 ORM(Object Relational Mapping,即对象关系映射)库,它使得在 Go 中操作数据库变得更加方便和高效。gorm 提供了简洁的 API 来进行数据库操作,包括创建表、插入数据、查询数据、更新数据和删除数据等。
连接代码如下:
import (
"chapter-1/utils/config"
"github.com/jinzhu/gorm"
)
var gdb *gorm.DB
func CreateDB() (*gorm.DB, error) {
if gdb == nil {
driver := config.GetString("database.driver")
dsn := dsn = config.GetString("database.mysql-dsn")
db, err := gorm.Open(driver, dsn)
if err != nil {
return nil, err
}
db.DB().SetMaxIdleConns(config.GetInt("database.max-idle-conns"))
db.DB().SetMaxOpenConns(config.GetInt("database.max-open-conns"))
db.LogMode(config.GetBool("application.debug"))
gdb = db
}
return gdb, nil
}
1.3 gorm
通过gorm 连接到数据库之后,就可以使用gorm 提供的简洁的 API 来进行数据库操作,
实例service代码:
package service
import (
"chapter-1/moddel"
"chapter-1/utils/orm"
"errors"
"github.com/sirupsen/logrus"
)
func Add(userProject moddel.TestModel) error {
db, err := orm.CreateDB()
if err != nil {
logrus.Errorf("projectList service, orm.CreateDB error on row 17 :%v\n", err.Error())
return errors.New("数据库连接异常")
}
errrr := userProject.Add(db)
return errrr
}
func Update(userProject moddel.TestModel) error {
db, err := orm.CreateDB()
if err != nil {
logrus.Errorf("projectList service, orm.CreateDB error on row 17 :%v\n", err.Error())
return errors.New("数据库连接异常")
}
errrr := userProject.Update(db)
return errrr
}
func Detelete(userId string) error {
db, err := orm.CreateDB()
if err != nil {
logrus.Errorf("projectList service, orm.CreateDB error on row 17 :%v\n", err.Error())
return errors.New("数据库连接异常")
}
userProject := moddel.TestModel{ID: userId}
errrr := userProject.Delete(db)
return errrr
}
func GetById(userId string) ([]moddel.TestModel, error) {
db, err := orm.CreateDB()
if err != nil {
logrus.Errorf("projectList service, orm.CreateDB error on row 17 :%v\n", err.Error())
return nil, errors.New("数据库连接异常")
}
userProject := moddel.TestModel{ID: userId}
ups, err := userProject.RawByUserId(db)
if err != nil {
logrus.Errorf("projectList service, userProject.FindByUserId error on row 24:%v\n", err.Error())
return nil, errors.New("数据库查询异常")
}
if len(ups) == 0 {
return nil, nil
}
return ups, err
}
实例 gorm 代码:
package moddel
import (
"strings"
"github.com/jinzhu/gorm"
)
type TestModel struct {
ID string `json:"id"`
Name string `json:"name"`
}
// 直接使用 gorm 的方法,默认使用gorm创建的表 mydb_test_models
func (this *TestModel) Add(db *gorm.DB) (err error) {
return db.Create(this).Error
}
func (this *TestModel) Update(db *gorm.DB) (err error) {
return db.Save(this).Error
}
func (this *TestModel) Delete(db *gorm.DB) (err error) {
return db.Delete(this).Error
}
func (this *TestModel) FindByUserId(db *gorm.DB) (userProjects []TestModel, err error) {
db = db.Find(&userProjects, "id = ?", this.ID)
return userProjects, db.Error
}
// 这种使用方式,不会使用gorm 默认的表,这里使用 test_1
func (this *TestModel) RawByUserId(db *gorm.DB) (userProjects []TestModel, err error) {
var sql = " select * from test_1 where id=${id} "
sql = strings.Replace(sql, "${id}", this.ID, -1)
db = db.Raw(sql)
db = db.Scan(&userProjects)
return userProjects, db.Error
}
参考:gorm官网连接
2.1 测试文件名称 _test.go 结尾
2.2 测试方法名称 Test 开始
2.3 测试方法参数 t *testing.T
主要有以下几个方面的原因:
高效的编译:Go 语言的编译器非常高效,能够生成高效的机器码。它采用了一些优化技术,如静态单赋值(SSA)形式、寄存器分配优化等,以提高代码的运行效率。
垃圾回收:Go 语言具有内置的垃圾回收机制,可以自动管理内存分配和释放。垃圾回收器的设计目标是在减少内存占用和提高性能之间取得平衡。
并发支持:Go 语言原生支持并发编程,通过轻量级的线程(goroutine)和通道(channel)来实现。这使得并发编程变得简单而高效,可以充分利用多核 CPU 的优势。
内存管理:Go 语言的内存管理相对简单,不需要手动管理内存。它采用了内存池和垃圾回收的方式来优化内存使用。
网络和 I/O 性能:Go 语言在网络和 I/O 操作方面具有很高的性能。它的网络库和文件 I/O 库经过了精心设计和优化,能够高效地处理大规模的网络通信和文件读写。
实例代码:
func TestRoutine(t *testing.T) {
go fmt.Println("Hello from goroutine")
fmt.Println("Main thread")
// 等待一段时间,以便 goroutine 有足够的时间执行
time.Sleep(2 * time.Second)
}
在 Go 语言中,通过channel可以实现并发控制。channel是 Go 语言中的一种通信机制,用于在不同的协程之间进行数据交换和同步。
实例代码:
func TestChannel(t *testing.T) {
// 创建一个 int 类型的 channel
ch := make(chan int)
// 启动三个 worker
for i := 1; i <= 3; i++ {
go worker(i, ch)
}
// 发送数据到 channel
for i := 1; i <= 10; i++ {
ch <- i
}
// 关闭 channel
close(ch)
fmt.Println("All workers have finished")
}
func worker(id int, ch chan int) {
// 使用 range 遍历 channel
for value := range ch {
fmt.Printf("Worker %d received value: %d\n", id, value)
println("sss", "dddddd")
}
}
首先将所有对象都标记为白色,
然后从根对象开始遍历内存中的对象,把直接引用的对象标记为灰色,
再判断灰色集合中的对象是否存在 子引用,不存在则放入黑色集合,
如果存在,就把子引用对象放入到灰色集合,
不断重复这个步骤,直到灰色集合中所有的对象变黑后,本轮标记完成,
最后还处于白色标记的对象就是不可达对象,可以直接被回收。
type TestModel struct {
ID string `json:"id"`
Name string `json:"name"`
father EmbedModel
others []EmbedModel
}
type EmbedModel struct {
ID string `json:"id"`
Name string `json:"name"`
}
go 没有现成的事务管理组件,需要手动处理,实例:
func TestTransaction(t *testing.T) {
db, err := sql.Open("mysql", "username:password@tcp(localhost:3306)/mydb")
if err != nil {
log.Fatal(err)
}
// 延迟关闭数据库连接
defer db.Close()
// 开始执行事务
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
// 执行一些数据库操作
_, err = tx.Exec("INSERT INTO test_1 (id, name) VALUES (3, 'John')")
if err != nil {
log.Fatal(err)
}
_, err = tx.Exec("INSERT INTO test_1 (id, name) VALUES (4, 'Jane')")
if err != nil {
// 如果出现错误,回滚事务
tx.Rollback()
log.Fatal(err)
}
// 提交事务
err = tx.Commit()
if err != nil {
log.Fatal(err)
}
fmt.Println("事务成功执行")
}
go 没有内置的切面(AOP)功能。只能通过方法复用的方式实现。
go 使用gin框架的中间件实现拦截器的功能,实例如下:
制作中间价:
func ErrorHandler() gin.HandlerFunc {
return func(c *gin.Context) {
// 执行处理逻辑
fmt.Println("Error:THIS IS A INTERCEPTOR")
r := c.Request
fmt.Println("Request:", r.URL.Path)
c.Next()
}
}
绑定中间件:
func main() {
// 1. 创建路由
route := gin.Default()
// 2. 绑定中间件
route.Use(middleware.ErrorHandler())
// 3. 监听端口
route.Run(port)
系统权限控制这里采用的是 中间件的方式,实例代码:
func Authorize() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("token")
if token == "" {
c.Abort()
c.JSON(http.StatusUnauthorized, response.NewBaseResponse(response.ResponseCodeUnauthorized))
return
}
userID := c.GetHeader("user_id")
if userID == "" {
c.Abort()
c.JSON(http.StatusBadRequest, response.NewBaseResponse(response.ResponseCodeBadRequest))
return
}
localUser, err := redis.Store.GetString("token:" + token)
if err != nil || localUser != userID {
c.Abort()
c.JSON(http.StatusForbidden, response.NewBaseResponse(response.ResponseCodeForbidden))
return
}
c.Next()
}
}
Protocol Buffers(协议缓冲区,简称 protobuf)是一种用于序列化和反序列化结构化数据的跨平台、跨语言的二进制格式。它由 Google 开发,并广泛应用于各种应用程序和系统中。
以下是 Protocol Buffers 的一些特点和优势:
Protocol Buffers 采用二进制格式进行数据序列化和反序列化,相对于文本格式(如 JSON),它具有更小的体积和更高的解析效率,能够有效地减少网络传输带宽和提高数据处理速度。
Protocol Buffers 支持定义自定义的数据类型和字段,可以根据需求灵活地扩展和修改消息结构,而不影响现有代码。
Protocol Buffers 提供了多种编程语言的 API 和生成代码工具,支持 C++、Java、Python、Go 等常见编程语言,可以方便地在不同语言之间进行数据交换。
Protocol Buffers 通过字段编号和标记来表示字段的存在和类型,使得在不同版本的协议之间进行数据解析时能够保持向后兼容性。
Protocol Buffers 可以进行一些性能优化,如字段排序、字段压缩等,以提高数据的存储和传输效率。
在使用 Protocol Buffers 时,通常需要先定义消息类型(使用 .proto 文件),然后使用相应的编程语言生成代码,用于序列化和反序列化数据。Protocol Buffers 常用于网络通信、数据存储、RPC( Remote Procedure Call )等场景,它提供了一种高效、灵活和标准化的方式来处理结构化数据。
如果你对 Protocol Buffers 感兴趣,可以查阅相关文档和教程,了解更多关于它的使用方法和应用场景。
ProtoBuf(Protocol Buffers)与Service Mesh没有直接的关系,它是一种独立的序列化和反序列化框架,用于高效地处理结构化数据在不同编程语言之间的传输。
而Service Mesh是一种用于管理微服务之间通信和控制的基础设施层,它将服务间通讯以及与此相关的管理控制功能从业务程序中下移到一个基础设施层,从而彻底隔离了业务逻辑和服务通讯两个关注点。
参考:
官网
知乎
Service Mesh(服务网格)是一种用于管理和监控微服务架构中服务之间通信的基础设施。它提供了一个可编程的、统一的方式来处理服务之间的通信、路由、流量控制、安全性和可观测性等方面的问题。
Service Mesh 的主要目标是解决在复杂的微服务环境中,服务之间的通信变得复杂且难以管理的问题。它通过在服务之间插入一个中间层(称为 Sidecar 代理)来实现对服务通信的控制和管理。
以下是 Service Mesh 的一些关键功能:
entity.proto
syntax = "proto3";
option java_package = "cc.iooc.common.rpc.snowflake.proto";
option java_multiple_files = true;
import "string.proto";
package proto;
// imc/entity/client/entity_rpc.go文件中方法对应的定义
service Entity {
// SaveForm()方法 保存表单定义
rpc SaveForm (EntitySaveFormRequest) returns (EntitySaveFormResponse) {
}
}
// SaveForm() Request
// tenant, formID string, major, minor int, form string
message EntitySaveFormRequest {
string tenant = 1;
string formID = 2;
int64 major = 3;
int64 minor = 4;
string form = 5;
}
// SaveForm() Response
// method []model.SystemMethod, err error
message EntitySaveFormResponse {
repeated SystemMethod systemMethod = 1;
}
entity.pb.go(这个文件是通过命令生成)
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: entity.proto
package proto
import (
context "context"
fmt "fmt"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math"
)
// 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
// SaveForm() Request
// tenant, formID string, major, minor int, form string
type EntitySaveFormRequest struct {
Tenant string `protobuf:"bytes,1,opt,name=tenant,proto3" json:"tenant,omitempty"`
FormID string `protobuf:"bytes,2,opt,name=formID,proto3" json:"formID,omitempty"`
Major int64 `protobuf:"varint,3,opt,name=major,proto3" json:"major,omitempty"`
Minor int64 `protobuf:"varint,4,opt,name=minor,proto3" json:"minor,omitempty"`
Form string `protobuf:"bytes,5,opt,name=form,proto3" json:"form,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EntitySaveFormRequest) Reset() { *m = EntitySaveFormRequest{} }
func (m *EntitySaveFormRequest) String() string { return proto.CompactTextString(m) }
func (*EntitySaveFormRequest) ProtoMessage() {}
func (*EntitySaveFormRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_cf50d946d740d100, []int{0}
}
func (m *EntitySaveFormRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EntitySaveFormRequest.Unmarshal(m, b)
}
func (m *EntitySaveFormRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EntitySaveFormRequest.Marshal(b, m, deterministic)
}
func (m *EntitySaveFormRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_EntitySaveFormRequest.Merge(m, src)
}
func (m *EntitySaveFormRequest) XXX_Size() int {
return xxx_messageInfo_EntitySaveFormRequest.Size(m)
}
func (m *EntitySaveFormRequest) XXX_DiscardUnknown() {
xxx_messageInfo_EntitySaveFormRequest.DiscardUnknown(m)
}
var xxx_messageInfo_EntitySaveFormRequest proto.InternalMessageInfo
func (m *EntitySaveFormRequest) GetTenant() string {
if m != nil {
return m.Tenant
}
return ""
}
func (m *EntitySaveFormRequest) GetFormID() string {
if m != nil {
return m.FormID
}
return ""
}
func (m *EntitySaveFormRequest) GetMajor() int64 {
if m != nil {
return m.Major
}
return 0
}
func (m *EntitySaveFormRequest) GetMinor() int64 {
if m != nil {
return m.Minor
}
return 0
}
func (m *EntitySaveFormRequest) GetForm() string {
if m != nil {
return m.Form
}
return ""
}
// SaveForm() Response
// method []model.SystemMethod, err error
type EntitySaveFormResponse struct {
SystemMethod []*SystemMethod `protobuf:"bytes,1,rep,name=systemMethod,proto3" json:"systemMethod,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EntitySaveFormResponse) Reset() { *m = EntitySaveFormResponse{} }
func (m *EntitySaveFormResponse) String() string { return proto.CompactTextString(m) }
func (*EntitySaveFormResponse) ProtoMessage() {}
func (*EntitySaveFormResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_cf50d946d740d100, []int{1}
}
func (m *EntitySaveFormResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EntitySaveFormResponse.Unmarshal(m, b)
}
func (m *EntitySaveFormResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EntitySaveFormResponse.Marshal(b, m, deterministic)
}
func (m *EntitySaveFormResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_EntitySaveFormResponse.Merge(m, src)
}
func (m *EntitySaveFormResponse) XXX_Size() int {
return xxx_messageInfo_EntitySaveFormResponse.Size(m)
}
func (m *EntitySaveFormResponse) XXX_DiscardUnknown() {
xxx_messageInfo_EntitySaveFormResponse.DiscardUnknown(m)
}
var xxx_messageInfo_EntitySaveFormResponse proto.InternalMessageInfo
func (m *EntitySaveFormResponse) GetSystemMethod() []*SystemMethod {
if m != nil {
return m.SystemMethod
}
return nil
}
func init() {
proto.RegisterType((*EntitySaveFormRequest)(nil), "proto.EntitySaveFormRequest")
proto.RegisterType((*EntitySaveFormResponse)(nil), "proto.EntitySaveFormResponse")
}
func init() {
proto.RegisterFile("entity.proto", fileDescriptor_cf50d946d740d100)
}
var fileDescriptor_cf50d946d740d100 = []byte{
// 457 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0x4d, 0x6f, 0xd4, 0x30,
0x10, 0x6d, 0x9a, 0x6e, 0xd4, 0x1d, 0xf6, 0x50, 0xb9, 0xa5, 0x44, 0xa1, 0x54, 0x2b, 0x1f, 0xd0,
0x9e, 0x72, 0x28, 0x07, 0x84, 0xb8, 0x20, 0x68, 0x2b, 0x56, 0x62, 0x25, 0x48, 0x25, 0xee, 0x26,
0x9d, 0x85, 0xd0, 0xc4, 0x0e, 0xb6, 0x03, 0xda, 0x5f, 0xc0, 0x9f, 0xe1, 0x47, 0xa2, 0xf8, 0x63,
0x89, 0x43, 0xab, 0x4a, 0x3d, 0xd9, 0xf3, 0x66, 0xfc, 0xe6, 0xbd, 0x19, 0xc3, 0x0c, 0xb9, 0xae,
0xf4, 0x26, 0x6f, 0xa5, 0xd0, 0x82, 0x4c, 0xcc, 0x91, 0xcd, 0x94, 0x96, 0x15, 0xff, 0x6a, 0x41,
0xfa, 0x3b, 0x82, 0xc7, 0x17, 0xa6, 0xea, 0x8a, 0xfd, 0xc4, 0x4b, 0x21, 0x9b, 0x02, 0x7f, 0x74,
0xa8, 0x34, 0x39, 0x86, 0x44, 0x23, 0x67, 0x5c, 0xa7, 0xd1, 0x3c, 0x5a, 0x4c, 0x0b, 0x17, 0xf5,
0xf8, 0x5a, 0xc8, 0x66, 0x79, 0x9e, 0xee, 0x5a, 0xdc, 0x46, 0xe4, 0x08, 0x26, 0x0d, 0xfb, 0x2e,
0x64, 0x1a, 0xcf, 0xa3, 0x45, 0x5c, 0xd8, 0xc0, 0xa0, 0x15, 0x17, 0x32, 0xdd, 0x73, 0x68, 0x1f,
0x10, 0x02, 0x7b, 0xfd, 0xab, 0x74, 0x62, 0x18, 0xcc, 0x9d, 0x7e, 0x82, 0xe3, 0xb1, 0x10, 0xd5,
0x0a, 0xae, 0x90, 0xbc, 0x84, 0x99, 0xda, 0x28, 0x8d, 0xcd, 0x0a, 0xf5, 0x37, 0x71, 0x9d, 0x46,
0xf3, 0x78, 0xf1, 0xe8, 0xec, 0xd0, 0x3a, 0xc8, 0xaf, 0x06, 0xa9, 0x22, 0x28, 0xa4, 0x0c, 0x0e,
0x2d, 0xe5, 0x07, 0xb6, 0x11, 0x9d, 0xbe, 0xcf, 0x59, 0x06, 0xfb, 0x6d, 0xcd, 0xb4, 0x51, 0x66,
0xbd, 0x6d, 0xe3, 0x81, 0xeb, 0x78, 0xe8, 0x9a, 0x7e, 0x86, 0xa3, 0xb0, 0x85, 0xd3, 0x3c, 0xe4,
0x8a, 0x46, 0x5c, 0x14, 0x66, 0xb5, 0xa9, 0x3e, 0xc7, 0x75, 0xc5, 0xd1, 0xf5, 0x0a, 0x30, 0x7a,
0xe1, 0xa5, 0x5f, 0x56, 0x58, 0x5f, 0xab, 0x07, 0x2e, 0x85, 0xbe, 0xf1, 0xf2, 0x3c, 0x8d, 0x93,
0xb7, 0x80, 0x44, 0xa2, 0xea, 0x6a, 0xed, 0x86, 0x79, 0xe0, 0x86, 0xb9, 0x62, 0x6d, 0x61, 0xf0,
0xc2, 0xe5, 0xe9, 0x6b, 0x98, 0x6e, 0x41, 0x72, 0x00, 0xf1, 0x0d, 0x6e, 0x5c, 0xef, 0xfe, 0x4a,
0x4e, 0x60, 0x5a, 0x71, 0x8d, 0x72, 0xcd, 0x4a, 0x6f, 0xe4, 0x1f, 0x40, 0xdf, 0xfb, 0x9d, 0x2e,
0x79, 0xdb, 0xe9, 0xa2, 0xab, 0xf1, 0xa1, 0x46, 0x5e, 0xc1, 0x93, 0xff, 0x98, 0x9c, 0x97, 0x53,
0x80, 0xca, 0x83, 0xca, 0xd1, 0x0d, 0x90, 0xb3, 0x3f, 0xbb, 0x90, 0xd8, 0xb7, 0x64, 0x09, 0xfb,
0xfe, 0x77, 0x91, 0x13, 0x67, 0xf9, 0xd6, 0xdf, 0x9f, 0x3d, 0xbb, 0x23, 0x6b, 0x7b, 0xd2, 0x1d,
0xf2, 0x0e, 0x12, 0xbb, 0x72, 0x92, 0x05, 0xa5, 0xc1, 0x57, 0xcb, 0x9e, 0xde, 0x9a, 0x1b, 0x92,
0xd8, 0xc5, 0x8c, 0x48, 0x82, 0xa5, 0x8f, 0x48, 0xc2, 0x4d, 0xd2, 0x1d, 0xb2, 0x02, 0xd8, 0x0e,
0x45, 0x91, 0x50, 0xf8, 0x78, 0xee, 0xd9, 0xe9, 0x5d, 0x69, 0x4f, 0xf7, 0xf6, 0x39, 0xd0, 0xb2,
0xcc, 0x2b, 0x21, 0xca, 0xbc, 0x14, 0x4d, 0x23, 0x78, 0x2e, 0xdb, 0x32, 0x57, 0x5c, 0xfc, 0x5a,
0xd7, 0xec, 0x06, 0xed, 0xfb, 0x8f, 0xd1, 0x97, 0xc4, 0x5c, 0x5e, 0xfc, 0x0d, 0x00, 0x00, 0xff,
0xff, 0xba, 0x17, 0x45, 0x3a, 0x65, 0x04, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface
// 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.SupportPackageIsVersion6
// EntityClient is the client API for Entity service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type EntityClient interface {
// SaveForm()方法 保存表单定义
SaveForm(ctx context.Context, in *EntitySaveFormRequest, opts ...grpc.CallOption) (*EntitySaveFormResponse, error)
}
type entityClient struct {
cc grpc.ClientConnInterface
}
func NewEntityClient(cc grpc.ClientConnInterface) EntityClient {
return &entityClient{cc}
}
func (c *entityClient) SaveForm(ctx context.Context, in *EntitySaveFormRequest, opts ...grpc.CallOption) (*EntitySaveFormResponse, error) {
out := new(EntitySaveFormResponse)
err := c.cc.Invoke(ctx, "/proto.Entity/SaveForm", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// EntityServer is the server API for Entity service.
type EntityServer interface {
// SaveForm()方法 保存表单定义
SaveForm(context.Context, *EntitySaveFormRequest) (*EntitySaveFormResponse, error)
}
// UnimplementedEntityServer can be embedded to have forward compatible implementations.
type UnimplementedEntityServer struct {
}
func (*UnimplementedEntityServer) SaveForm(ctx context.Context, req *EntitySaveFormRequest) (*EntitySaveFormResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SaveForm not implemented")
}
func RegisterEntityServer(s *grpc.Server, srv EntityServer) {
s.RegisterService(&_Entity_serviceDesc, srv)
}
func _Entity_SaveForm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(EntitySaveFormRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityServer).SaveForm(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/proto.Entity/SaveForm",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityServer).SaveForm(ctx, req.(*EntitySaveFormRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Entity_serviceDesc = grpc.ServiceDesc{
ServiceName: "proto.Entity",
HandlerType: (*EntityServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "SaveForm",
Handler: _Entity_SaveForm_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "entity.proto",
}
server
package server
import (
"context"
"fmt"
"imcs/common/errors"
"imcs/common/log"
imcsResponse "imcs/common/response"
"imcs/entity/service"
"imcs/proto"
)
type EntityGRPCServer struct {
}
// @author []
// 这一系列仍然需要定义entity.proto文件之后编码
func (egs *EntityGRPCServer) SaveForm(ctx context.Context, request *proto.EntitySaveFormRequest) (response *proto.EntitySaveFormResponse, err error) {
tenantId := request.Tenant
formId := request.Form
minor := request.Minor
major := request.Major
form := request.Form
if tenantId == "" || formId == "" || minor <= 0 || major <= 0 {
return nil, errors.New(20003, "参数不合法")
}
method, err := service.SaveForm(tenantId, formId, int(major), int(minor), form)
response = new(proto.EntitySaveFormResponse)
response.SystemMethod = method
return response, err
}
service+DB
package service
import (
"encoding/json"
"github.com/satori/go.uuid"
"github.com/sirupsen/logrus"
"imcs/common/errors"
"imcs/common/orm"
baseModel "imcs/common/orm/model"
"imcs/entity/model"
fieldStringClient "imcs/field_string/client"
formModel "imcs/form/client/model"
"imcs/proto"
)
// 保存表单定义
func SaveForm(tenantId, formId string, major, minor int, form string) (method []*proto.SystemMethod, err error) {
var formMap map[string]interface{}
err = json.Unmarshal([]byte(form), &formMap)
if err != nil {
logrus.Errorf("entity.service.SaveForm form转换json出错 :%v\n", err.Error())
return nil, errors.New(errors.JsonUnMarshallError, "form转换json出错")
}
db, err := orm.WriteDB()
if err != nil {
logrus.Errorf("entity.service.SaveForm 数据库连接异常 :%v\n", err.Error())
return nil, errors.New(errors.DataBaseConnError, "数据库连接异常")
}
// 其他实现逻辑+数据库操作
}
client 方法
package client
import (
"context"
"google.golang.org/grpc"
"imcs/common/config"
"imcs/common/errors"
"imcs/common/log"
"imcs/common/rpc"
"imcs/form/client/model"
"imcs/proto"
)
type EntityGRPCClient struct {
Address string
}
func NewEntityGRPCClient() *EntityGRPCClient {
return &EntityGRPCClient{Address: config.GetString("grpc.client.entity.address")}
}
//保存表单定义
//tenant 企业ID
//formID 表单ID
//major 表单主版本号
//minor 表单子版本号
//form 表单JSON字符串
//method 字段ID、版本及system方法切片的切片
func (e *EntityGRPCClient) SaveForm(tenant, formID string, major, minor int, form string) (
method []model.SystemMethod, err error) {
//entity应处理应用类型中包含$system{}的方法
// #1.参数校验
if tenant == "" || formID == "" || major == 0 || minor == 0 || form == "" {
return []model.SystemMethod{}, errors.New(errors.BadRequest, "参数校验失败")
}
// #2.获取连接
conn, err := rpc.GetConn(e.Address)
if err != nil {
log.Info(err.Error())
return []model.SystemMethod{}, errors.New(errors.GrpcConnError, "EntityGRPCClient中SaveForm()获取连接失败")
}
defer rpc.Close(e.Address, conn)
// #3...
response, err := func(conn *grpc.ClientConn) (interface{}, error) {
// 调用proto buffers 生成的客户端对象;提供了在.proto文件中我们之前定义的方法,也是我们需要的方法。
client := proto.NewEntityClient(conn)
// 调用grpc生成的接口及其实现方法
// 给proto生成的请求对象的属性设置值
response, err := client.SaveForm(context.Background(), &proto.EntitySaveFormRequest{
Tenant: tenant,
FormID: formID,
Major: int64(major),
Minor: int64(minor),
Form: form,
})
return response, err
}(conn)
if err != nil {
log.Error(err)
return nil, err
}
// 从生成的相应对象中获取属性值作为返回值
var addrArr = response.(*proto.EntitySaveFormResponse).SystemMethod
protoToModel(addrArr, &method)
return method, nil
}
// description: 批量转化不同包的对象
func protoToModel(addrArr []*proto.SystemMethod, method *[]model.SystemMethod) {
for _, addr := range addrArr {
var out = model.SystemMethod{
FieldID: addr.FieldID,
Version: int(addr.Version),
}
for _, single := range addr.Methods {
var inner = model.Method{
Scope: single.Scope,
Name: single.Name,
Params: single.Params,
}
out.Methods = append(out.Methods, inner)
}
*method = append(*method, out)
}
}
测试方法
package client
import (
"fmt"
"github.com/sirupsen/logrus"
"testing"
)
func TestSaveForm(t *testing.T) {
var tenant = "1212"
var formId = "1235555"
var major = 1
var minor = 2
var form = `{"id":"xX","major":1,"minor":1,"tenant":"","name":"表单名称","type":"entity","style":"tree","description":"",
"detail":false,"form_status":["禁用","未付款"],"platform":["app","pc","pad"],"create":["app","pc","pad"],"delete":["app","pc","pad"],
"update":["app","pc","pad"],"suspend":["app","pc","pad"],"print":["app","pc","pad"],"load":["app","pc","pad"],"export":["app","pc","pad"],
"trace":["app","pc","pad"],"custom_header":["app","pc","pad"],"version":true,"input_rule":[{"triggers":[{"field_id":"4672208957060812800","operate":"<=",
"value":"s"},{"field_id":"4672208369858252800","operate":"<=","value":"电脑1"},{"status":"状态","operate":"=","value":"启用"}],"empty_field":["创建记录"],
"readonly":["日期"],"value":[{"field_id":"XXXXX","value":"1235a"}]}],"group_unique":[{"group":["4672208369858252800"],"rule":[{"field_id":"4672208369858252800","value":"12"}]}],
"key":["fieldId",""],"sort":[{"field_id":"asc"}],
"header":{"pc":[{"name":"编号","order":true,"id":"4672208789288652800"},{"name":"产品信息","order":false,"children":[{"name":"名称",
"order":false,"id":"4672208369858252800"},{"name":"数量","order":true,"id":"4672208957060812800"}]}],"app":[{"name":"编号","order":true,
"id":"4672208789288652800"},{"name":"产品信息","order":false,"children":[{"name":"名称","order":false,"id":"4672208369858252800"},
{"name":"数量","order":true,"id":"4672208957060812800"}]}]},"sub_form":["form_id","form_id2"],"brief":"$field_id{get}XXX($field_id{get})",
"fields":[{"field_id":"","type":"string","name":"","format":"","default":"0","multiline":false,"max_length":100,"min_length":10,
"formula":"$field_id1{get}XXX$field_id2{get}$system{now,year}"},{"field_id":"","type":"number","name":"","format":"","default":0,
"decimals":2,"thousand":true,"start_with":"¥","end_with":"元","max":"$1001{get}+min+1000","min":"","formula":"$field_id1{get}+$field_id2{get}"},
{"field_id":"","name":"","type":"select","style":"radio/checkbox/select","data":["部门1","部门2"],"default":0},{"field_id":"","name":"",
"type":"increment","force":true,"length":4,"step":2,"start":1,"group":"$field_id{get}$system{time,\"yyyy\"}","format":"BillXXX$self{group}$self{get}$field_id2{get}"},
{"field_id":"","name":"","type":"date","style":"base/year/month/year-month/month-day","max":"","min":"","format":"MM"},{"field_id":"","name":"",
"type":"quote","init":true,"data":false,"quote_source":[{"form_id":"用户表ID","name":"","condition":[{"field_id":"电话","operate":"=",
"value":"$system{user,员工编号}"}],"source_field_id":""}],"source_field_type":"string"},{"field_id":"","name":"","type":"list","max":10,"min":1,"form_id":""}],
"layout":{"PC":[{"name":"基本信息","type":"common","rows":[[{"id":"4672208789288652800","rate":24,"name":"订单编号"}],[{"id":"4672208369858252800","rate":12,"name":"产品"},
{"id":"4672208957060812800","rate":12,"name":"数量"}]]}]}
,"scene":[]}`
var test = NewEntityGRPCClient()
data, err := test.SaveForm(tenant, formId, major, minor, form)
if err != nil {
logrus.Info(err)
} else {
fmt.Printf("=========>%v", data)
}
}