这是我参与「第五届青训营 」伴学笔记创作活动的第 18 天
实战案例介绍
笔记项目拆解为如下服务:
服务demoapi,主要实现服务介绍,采用的传输协议是HTTP,主要技术栈为Gorm/Kitex/Hertz。
服务demouser,主要实现用户数据管理,采用的传输协议是Protobuf,主要技术栈为Gorm/Kitex。
服务demonote,主要实现笔记数据管理,采用的传输协议是Thrift,主要技术栈为Gorm/Kitex
项目功能
demoapi:主要实现用户登陆,用户注册,用户创建笔记,用户更新笔记,用户删除笔记,用户查询笔记
demouser:实现创建用户,查询用户和校验用户
demonote:创建笔记,更新笔记,删除笔记和查询笔记
功能关系
调用方使用http协议连接demoapi,demoapi访问demouser,通过操作用户数据proto;访问ETCD通过服务发现;访问demonote通过操作笔记数据thrift;而demouser和demonote都需要在ETCD上进行服务注册,都将MySQL作为数据库。
代码说明
message User {
int64 user_id = 1;
string user_name = 2;
string avatar = 3;
}
message CreateUserRequest {
string user_name = 1;
string password = 2;
}
message CreateUserResponse {
BaseResp base_resp = 1;
}
message MGetUserRequest {
repeated int64 user_ids = 1;
}
message MGetUserResponse {
repeated User users = 1;
BaseResp base_resp = 2;
}
message CheckUserRequest{
string user_name = 1;
string password = 2;
}
message CheckUserResponse{
int64 user_id = 1;
BaseResp base_resp = 2;
}
service UserService {
rpc createUser (createUserRequest) returns (createUserResponse){}
rpc MGetUser (MGetUserRequest) returns (MGetUserResponse){}
rpc CheckUser (CheckUserRequest) returns (CheckUserResponse){}
}
struct DeleteNoteResponse {
1:BaseResp base_resp
}
struct UpdateNoteRequest {
1:i64 note_id
2:i64 user_id
3 : optional string title
4: optional string content
}
struct UpdateNoteResponse {
1:BaseResp base_resp
}
struct MGetNoteRequest {
1:list<i64> note_ids
}
struct MGetNoteResponse {
1:list<Note> notes
2: BaseResp base_resp
}
struct QueryNoteRequest {
1:i64 user_id
2 : optional string search_key
3:i64 offset
4:i64 limit
}
struct QueryNoteResponse, {
1:list<Note>notes
2 :i64 total
3 :BaseResp base_resp
}
service NoteService {
CreateNoteResponse CreateNote(1:CreateNoteRequest req)
MGetNoteResponse MGetNote( 1:MGetNoteRequest req)
DeleteNoteResponse DeleteNote( 1:DeleteNoteRequest req)
QueryNoteResponse QueryNote( 1 : QueryNoteRequest req)
UpdateNoteResponse UpdateNote(1: UpdateNoteRequest req)
}
Hertz关键代码详解
// CreateNote create note info
func CreateNote(ctx context.Context, c *app.RequestContext) {
var noteVar NoteParam
if err :c.Bind( ¬eVar);err!=nil{
SendResponse(c, errno.ConvertErr(err), nil)
return
}
if len(noteVar.Title) == 0 len(noteVar.Content) == 0 {
SendResponse(c, errno.ParamErr, nil)
return
}
claims := jwt.ExtractClaims ( ctx,c)
userID := int64(claims[constants.IdentityKey]. (float64))
err := rpc.CreateNote(context.Background( ), ¬edemo.CreateNoteRequest{
UserId: userID,
Content: noteVar.Content,Title: noteVar.Title,
})
if err != nil {
SendResponse(c, errno.ConvertErr(err), nil)
return
}
SendResponse(c, errno.Success, nil)
}
KitexClient关键代码
func initNoteRpc( ) {
r, err := etcd.NewEtcdResolver( []stringiconstants.EtcdAddress})
if err != nil {
panic(err)
}
c, err := noteservice.NewClient(
constants.NoteServiceName,
client.withMiddleware(middleware.CommonMiddleware),
client.withInstanceMw( middleware.clientMiddleware),
client.withMuxConnection(1),//mux
client.withRPCTimeout(3*time.Second),//rpc timeout
client.withConnectTimeout(50*time.Millisecond),//conn timeout
client.withFailureRetry( retry.NewFailurePolicy( )),//retry
client.withSuite(trace.NewDefaultclientSuite()),//tracer
client.withResolver(r),//resolver
)
if err != nil {
panic(err)
}
noteclient = c
// Createlote create note info
func CreateNote(ctx context.Context,req *notedemo.CreateNoteRequest) error {
resp, err := noteclient. CreateNote( ctx, req)
if err != nil {
return err
}
if resp.BaseResp.Statuscode != 0 {
return errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusNessage)
}
return nil
KitexServer关键代码
type CreateNoteService struct {
ctx context.Context
}
// NewCreateNoteService new CreateNoteService
func NewCreateNoteService(ctx context.Context) *CreateNoteService {
return &CreateNoteService{ctx: ctx}
}
// CreateNote create note info
func (s *CreateNoteService)CreataNoto( req *notedemo.CreateNoteRequest) error{
noteModel := &db.Note{
UserID:req.UserId,
Title:req.Title,
Content: req.Content,
}
return db. CreateNote(s.ctx,[]*db.Note{noteModel})
}
Gorm关键代码
type Note struct {
gorm.Model
UserID int64 `json:"user_id"
Title string `"son:"title"`
Content string `json: "content"`
}
func (n *Note) TableName() string {
return constants.NoteTableName
}
/ / CreateNote create note info
func CreateNote(ctx context.Context,notes[]*Note) error {
if err := DB.withContext(ctx).Create(notes).Error; err != nil {
return err
}
return nil
}
// MGetNotes multiple get list of note info
func MGetNotes(ctx context.Context,noteIDs []int64)( []*Note,error) {
var res []*Note
if len(noteIDs) == 0 {
return res, nil
}
if err := DB.withContext(ctx).where("id in ?",noteIDs).Find(&res).Error; err != nil {
return res, err
}
return res, nil
}
// UpdateNote update note info
func UpdateNote(ctx context.Context,noteID,userID int64,title,content *string) error {
params := map[string]interface{}{}
if title != nil {
params [""title"] =*title
}
if content != nil {
params [""content"]=*content
}
return DB.withContext(ctx).Model(&Note{}).where("id = ? and user_id = ?",noteID,userID).
Updates(params).Error
}
// DeleteNote delete note info
func DeleteNote(ctx context.Context,noteID,userID int64) error {
return DB.withContext(ctx).where("id = ? and user_id = ? ", noteID,userID).Delete(&Note{}).Error
}