学网站开发要下载哪些软件有哪些,开一个素材设计网站怎么做的,建站宝盒成品网站演示,微信小程序怎么制作网页go-zero微服务入门教程
本教程主要模拟实现用户注册和用户信息查询两个接口。
准备工作
安装基础环境
安装etcd#xff0c; mysql#xff0c;redis#xff0c;建议采用docker安装。 MySQL安装好之后#xff0c;新建数据库dsms_admin#xff0c;并新建表sys_user#…go-zero微服务入门教程
本教程主要模拟实现用户注册和用户信息查询两个接口。
准备工作
安装基础环境
安装etcd mysqlredis建议采用docker安装。 MySQL安装好之后新建数据库dsms_admin并新建表sys_user建表语句见后文。 安装插件
这里采用GoLand开发工具请自行搜索安装插件Goctl。 创建工程
这里采用开发工具GoLandFile New Project 创建api目录、rpc目录、common目录。
编写API Gateway代码
编写api文件
在api目录下创建新目录doc/sys。 在api/doc/sys下创建user.api。 user.api文件内容如下
syntax v1info(title: 用户相关desc: 用户相关author: 宋发元
)type (UserInfoResp {Code int64 json:codeMessage string json:messageData UserInfoData json:data}UserInfoData {Avatar string json:avatarName string json:nameMenuTree []*ListMenuTree json:menuTreeMenuTreeVue []*ListMenuTreeVue json:menuTreeVueResetPwd bool json:resetPwd,defaultfalse}ListMenuTree {Id int64 json:idPath string json:pathName string json:nameParentId int64 json:parentIdIcon string json:icon}ListMenuTreeVue {Id int64 json:idParentId int64 json:parentIdTitle string json:titlePath string json:pathName string json:nameIcon string json:iconVueRedirent string json:vueRedirentVueComponent string json:vueComponentMeta MenuTreeMeta json:meta}MenuTreeMeta {Title string json:titleIcon string json:icon}AddUserReq {Name string json:nameNickName string json:nickNamePassword string json:password,optionalEmail string json:emailRoleId int64 json:roleIdStatus int64 json:status,default1}AddUserResp {Code int64 json:codeMessage string json:messageData ReceiptUserData json:data}ReceiptUserData {Id int64 json:id}
)server (group : sys/userprefix : /sys/user
)service admin-api{doc(summary : 用户管理-获取当前用户信息)handler UserInfoget /currentUser returns (UserInfoResp)doc(summary : 用户管理-新增用户)handler UserAddpost /add(AddUserReq)returns(AddUserResp)
}用goctl生成API Gateway代码 生成的文件结构如下
api
├── admin.go //main入口定义
├── doc
│ └── sys
│ └── user.api //api定义文件
├── etc
│ └── admin-api.yaml //配置文件
└── internal├── config│ └── config.go //定义配置├── handler│ ├── routes.go //定义路由处理│ └── sys│ └── user│ ├── useraddhandler.go //实现addhandler│ └── userinfohandler.go //实现infohandler├── logic│ └── sys│ └── user│ ├── useraddlogic.go //实现addlogic│ └── userinfologic.go //实现infologic├── svc│ └── servicecontext.go //定义ServiceContext└── types└── types.go //定义请求、返回结构体编写rpc服务
编写sys.proto文件
在rpc下创建新目录sys。
在rpc/sys目录下创建sys.proto文件。 sys.proto文件内容如下
syntax proto3;package sysclient;option go_package ./sysclient;message InfoReq{int64 UserId 1;
}
message InfoResp{string avatar 1;string name 2;repeated MenuListTree menuListTree 3;repeated string backgroundUrls4;bool resetPwd5;
}message MenuListTree{int64 id1;string name2;string icon3;int64 parentId4;string path5;string vuePath6;string vueComponent7;string vueIcon8;string vueRedirect9;string backgroundUrl10;
}message UserAddReq{string name1;string nickName2;string password3;string email4;int64 roleId5;int64 status6;string createBy7;
}message UserAddResp{int64 id1;
}service Sys{rpc UserInfo(InfoReq)returns(InfoResp);rpc UserAdd(UserAddReq)returns(UserAddResp);
}用goctl生成rpc代码 生成的文件结构如下
sys
├── etc
│ └── sys.yaml //yaml配置文件
├── internal
│ ├── config
│ │ └── config.go //yaml配置文件对应的结构体定义
│ ├── logic //业务逻辑
│ │ ├── useraddlogic.go
│ │ └── userinfologic.go
│ ├── server //rpc server
│ │ └── sysserver.go
│ └── svc //资源依赖
│ └── servicecontext.go
├── sys //rpc client call entry
│ └── sys.go
├── sys.go //main函数入口
├── sys.proto //proto源文件
└── sysclient //pb.go├── sys.pb.go└── sys_grpc.pb.go修改API Gateway代码调用rpc服务
admin-api.yaml
修改配置文件admin-api.yaml增加如下内容这里的192.168.2.204为基础环境服务器IP。
Timeout: 60000Mysql:Datasource: root:123456tcp(192.168.2.204:3306)/dsms_admin?charsetutf8mb4parseTimetruelocAsia%2FShanghaiCacheRedis:- Host: 192.168.2.204:6379Pass: qkgxChxNkCwKType: nodeRedis:Address: 192.168.2.204:6379Pass: qkgxChxNkCwKSysRpc:Timeout: 30000Etcd:Hosts:- 192.168.2.204:2379Key: sysa.rpc通过etcd自动去发现可用的rpc服务。
config.go
修改api/internal/config/config.go如下增加rpc服务依赖。 SysRpc zrpc.RpcClientConfCacheRedis cache.ClusterConfRedis struct {Address stringPass string}Mysql struct {Datasource string}servicecontext.go
修改api/internal/svc/servicecontext.go如下
type ServiceContext struct {Config config.ConfigSys sys.SysRedis *redis.Redis
}func NewServiceContext(c config.Config) *ServiceContext {newRedis : redis.New(c.Redis.Address, redisConfig(c))return ServiceContext{Config: c,Sys: sys.NewSys(zrpc.MustNewClient(c.SysRpc, zrpc.WithUnaryClientInterceptor(interceptor))),Redis: newRedis,}
}func redisConfig(c config.Config) redis.Option {return func(r *redis.Redis) {r.Type redis.NodeTyper.Pass c.Redis.Pass}
}func interceptor(ctx context.Context, method string, req any, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {md : metadata.New(map[string]string{x: xx})ctx metadata.NewOutgoingContext(ctx, md)// logx.Debug(调用rpc服务前)err : invoker(ctx, method, req, reply, cc)if err ! nil {return err}// logx.Debug(调用rpc服务后)return nil
}通过ServiceContext在不同业务逻辑之间传递依赖。
useraddlogic.go
修改api/internal/logic/useraddlogic.go里的UserAdd方法如下
func (l *UserAddLogic) UserAdd(req *types.AddUserReq) (resp *types.AddUserResp, err error) {res, err : l.svcCtx.Sys.UserAdd(l.ctx, sysclient.UserAddReq{Name: req.Name,NickName: req.NickName,Password: req.Password,Email: req.Email,RoleId: req.RoleId,Status: req.Status,//CreateBy: l.ctx.Value(cache.JwtFieldUserName).(string),CreateBy: songfayuan,})if err ! nil {reqJson, _ : json.Marshal(req)logx.WithContext(l.ctx).Errorf(添加用户信息失败请求参数%s异常信息%s, reqJson, err.Error())return nil, rpcerror.New(err)}return types.AddUserResp{Code: 200,Message: 添加用户成功,Data: types.ReceiptUserData{Id: res.Id},}, nil
}userinfologic.go
修改api/internal/logic/userinfologic.go里的UserInfo方法如下 func (l *UserInfoLogic) UserInfo() (*types.UserInfoResp, error) {//这里的key和生成jwt token时传入的key一致//userId, _ : l.ctx.Value(cache.JwtFieldUserId).(json.Number).Int64()var userId int64 1resp, err : l.svcCtx.Sys.UserInfo(l.ctx, sysclient.InfoReq{UserId: userId,})if err ! nil {logx.WithContext(l.ctx).Errorf(根据userId%s, 查询用户异常%s, strconv.FormatInt(userId, 10), err.Error())return nil, rpcerror.New(err)}var MenuTree []*types.ListMenuTree//组装ant ui中的菜单for _, item : range resp.MenuListTree {MenuTree append(MenuTree, types.ListMenuTree{Id: item.Id,Path: item.Path,Name: item.Name,ParentId: item.ParentId,Icon: item.Icon,})}if MenuTree nil {MenuTree make([]*types.ListMenuTree, 0)}//组装element ui中的菜单var MenuTreeVue []*types.ListMenuTreeVuefor _, item : range resp.MenuListTree {if len(strings.TrimSpace(item.VuePath)) ! 0 {MenuTreeVue append(MenuTreeVue, types.ListMenuTreeVue{Id: item.Id,ParentId: item.ParentId,Title: item.Name,Path: item.VuePath,Name: item.Name,Icon: item.VueIcon,VueRedirent: item.VueRedirect,VueComponent: item.VueComponent,Meta: types.MenuTreeMeta{Title: item.Name,Icon: item.VueIcon,},})}}if MenuTreeVue nil {MenuTreeVue make([]*types.ListMenuTreeVue, 0)}err l.svcCtx.Redis.Set(strconv.FormatInt(userId, 10), strings.Join(resp.BackgroundUrls, ,))if err ! nil {logx.Errorf(设置用户%s, 权限到Redis异常%v, resp.Name, err)}return types.UserInfoResp{Code: 200,Message: 成功,Data: types.UserInfoData{Avatar: resp.Avatar,Name: resp.Name,MenuTree: MenuTree,MenuTreeVue: MenuTreeVue,ResetPwd: resp.ResetPwd,},}, nil
}定义数据库表结构并生成CRUD代码
在rpc目录下创建model/sysmodel目录在rpc目录下创建doc/sql/sys目录。 创建sys_user.sql
在rpc/doc/sql/sys目录下编写sql文件sys_user.sql如下
-- goctl model mysql ddl -src doc/sql/sys/sys_user.sql -dir ./model/sysmodel-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS sys_user;
CREATE TABLE sys_user
(id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 编号,name varchar(128) NOT NULL DEFAULT COMMENT 账号,nick_name varchar(128) NOT NULL DEFAULT COMMENT 名称,avatar varchar(255) NOT NULL DEFAULT COMMENT 头像,password varchar(128) NOT NULL DEFAULT COMMENT 密码,salt varchar(40) NOT NULL DEFAULT COMMENT 加密盐,email varchar(128) NOT NULL DEFAULT COMMENT 邮箱,mobile varchar(32) NOT NULL DEFAULT COMMENT 手机号,status tinyint(4) NOT NULL DEFAULT 1 COMMENT 状态 -1禁用 1正常,create_by varchar(128) NOT NULL DEFAULT COMMENT 创建人,create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,update_by varchar(128) NOT NULL DEFAULT COMMENT 更新人,update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间,del_flag tinyint(4) unsigned NOT NULL DEFAULT 0 COMMENT 是否删除 1已删除 0正常,PRIMARY KEY (id),KEY name (name) USING BTREE
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COMMENT用户管理;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO sys_user VALUES (1, admin, admin, , $2a$10$hDlSis2/3IPGNYQhFlFfK.Wmi7iH9/jr6wcN.5c.rh7fc/uUnCo4S, , admindsms.com, 13612345678, 1, admin, 2018-08-14 11:11:11, , 2023-01-04 10:17:30, 0);生成CRUD代码
方法一
通过工具生成这种方式生成带缓存的代码。本文采用方法二生成 选择代码位置。
生成的代码。 方法二采纳
在rpc路径下执行如下命令生成不带缓存的代码。
goctl model mysql ddl -src doc/sql/sys/sys_user.sql -dir ./model/sysmodel完善CRUD代码
sysusermodel.go
在model/sysmodel/sysusermodel.go文件中添加常用crud的代码完整代码如下。
package sysmodelimport (contexterrorsgithub.com/zeromicro/go-zero/core/stores/sqlxtime
)
import sq github.com/Masterminds/squirrelvar _ SysUserModel (*customSysUserModel)(nil)type (// SysUserModel is an interface to be customized, add more methods here,// and implement the added methods in customSysUserModel.SysUserModel interface {sysUserModelwithSession(session sqlx.Session) SysUserModelTrans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) errorUpdateBuilder() sq.UpdateBuilderUpdateByQuery(ctx context.Context, updateBuilder sq.UpdateBuilder) errorRowBuilder() sq.SelectBuilderFindOneByQuery(ctx context.Context, rowBuilder sq.SelectBuilder) (*SysUser, error)FindRowsByQuery(ctx context.Context, rowBuilder sq.SelectBuilder, orderBy string) ([]*SysUser, error)CountBuilder(field string) sq.SelectBuilderFindCount(ctx context.Context, countBuilder sq.SelectBuilder) (int64, error)FindAll(ctx context.Context, rowBuilder sq.SelectBuilder, orderBy string) ([]*SysUserList, error)TableName() string}customSysUserModel struct {*defaultSysUserModel}SysUserList struct {Id int64 db:id // 编号Name string db:name // 账号NickName string db:nick_name // 名称Avatar string db:avatar // 头像Password string db:password // 密码Salt string db:salt // 加密盐Email string db:email // 邮箱Mobile string db:mobile // 手机号Status int64 db:status // 状态 -1禁用 1正常CreateBy string db:create_by // 创建人CreateTime time.Time db:create_time // 创建时间UpdateBy string db:update_by // 更新人UpdateTime time.Time db:update_time // 更新时间DelFlag int64 db:del_flag // 是否删除 1已删除 0正常RoleId int64 db:role_idRoleName string db:role_name}
)func (m *customSysUserModel) UpdateByQuery(ctx context.Context, updateBuilder sq.UpdateBuilder) error {query, values, err : updateBuilder.Where(del_flag ?, 0).ToSql()if err ! nil {return err}_, err m.conn.ExecCtx(ctx, query, values...)return err
}func (m *customSysUserModel) UpdateBuilder() sq.UpdateBuilder {return sq.Update(m.table)
}func (m *customSysUserModel) Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error {return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {return fn(ctx, session)})
}func (m *customSysUserModel) TableName() string {return m.table
}func (m *customSysUserModel) FindAll(ctx context.Context, rowBuilder sq.SelectBuilder, orderBy string) ([]*SysUserList, error) {if orderBy {rowBuilder rowBuilder.OrderBy(id AEC)} else {rowBuilder rowBuilder.OrderBy(orderBy)}query, values, err : rowBuilder.Where(del_flag ?, 0).ToSql()if err ! nil {return nil, err}var resp []*SysUserListerr m.conn.QueryRowsCtx(ctx, resp, query, values...)switch err {case nil:return resp, nilcase sqlx.ErrNotFound:return nil, errors.New(查询记录为空)default:return nil, err}
}func (m *customSysUserModel) FindCount(ctx context.Context, countBuilder sq.SelectBuilder) (int64, error) {query, values, err : countBuilder.Where(del_flag ?, 0).ToSql()if err ! nil {return 0, err}var resp int64err m.conn.QueryRowCtx(ctx, resp, query, values...)switch err {case nil:return resp, nildefault:return 0, err}
}func (m *customSysUserModel) CountBuilder(field string) sq.SelectBuilder {return sq.Select(COUNT( field )).From(m.table)
}func (m *customSysUserModel) FindRowsByQuery(ctx context.Context, rowBuilder sq.SelectBuilder, orderBy string) ([]*SysUser, error) {if orderBy {rowBuilder rowBuilder.OrderBy(id DESC)} else {rowBuilder rowBuilder.OrderBy(orderBy)}query, values, err : rowBuilder.Where(del_flag ?, 0).ToSql()if err ! nil {return nil, err}var resp []*SysUsererr m.conn.QueryRowCtx(ctx, resp, query, values...)switch err {case nil:return resp, nilcase sqlx.ErrNotFound:return nil, errors.New(查询记录为空)default:return nil, err}
}func (m *customSysUserModel) FindOneByQuery(ctx context.Context, rowBuilder sq.SelectBuilder) (*SysUser, error) {query, values, err : rowBuilder.Where(del_flag ?, 0).Limit(1).ToSql()if err ! nil {return nil, err}var resp SysUsererr m.conn.QueryRowCtx(ctx, resp, query, values...)switch err {case nil:return resp, nildefault:return nil, err}
}func (m *customSysUserModel) RowBuilder() sq.SelectBuilder {return sq.Select(sysUserRows).From(m.table)
}// NewSysUserModel returns a model for the database table.
func NewSysUserModel(conn sqlx.SqlConn) SysUserModel {return customSysUserModel{defaultSysUserModel: newSysUserModel(conn),}
}func (m *customSysUserModel) withSession(session sqlx.Session) SysUserModel {return NewSysUserModel(sqlx.NewSqlConnFromSession(session))
}修改rpc代码调用crud代码
sys.yaml
修改rpc/sys/etc/sys.yaml如下内容
Name: sys.rpc
ListenOn: 0.0.0.0:8080
Timeout: 10000
Etcd:Hosts:- 192.168.2.204:2379Key: sysa.rpcMysql:Datasource: root:123456tcp(192.168.2.204:3306)/dsms_admin?charsetutf8mb4parseTimetruelocAsia%2FShanghaiCacheRedis:- Host: 192.168.2.204:6379Pass: qkgxChxNkCwKType: nodeconfig.go
修改rpc/sys/internal/config/config.go如下
type Config struct {zrpc.RpcServerConfMysql struct {Datasource string}CacheRedis cache.ClusterConf
}servicecontext.go
修改rpc/sys/internal/svc/servicecontext.go如下
type ServiceContext struct {Config config.ConfigCache cache.CacheRedis *redis.RedisUserModel sysmodel.SysUserModel
}func NewServiceContext(c config.Config) *ServiceContext {sqlConn : sqlx.NewMysql(c.Mysql.Datasource)ca : cache.New(c.CacheRedis, syncx.NewSingleFlight(), cache.NewStat(dc), errors.New(data not find))rConn : redis.New(c.CacheRedis[0].Host, func(r *redis.Redis) {r.Type c.CacheRedis[0].Typer.Pass c.CacheRedis[0].Pass})return ServiceContext{Config: c,Cache: ca,Redis: rConn,UserModel: sysmodel.NewSysUserModel(sqlConn),}
}useraddlogic.go
修改rpc/sys/internal/logic/useraddlogic.go如下
func (l *UserAddLogic) UserAdd(in *sysclient.UserAddReq) (*sysclient.UserAddResp, error) {if in.Name {return nil, errors.New(账号不能为空)}if in.NickName {return nil, errors.New(姓名不能为空)}if in.Email {return nil, errors.New(邮箱不能为空)}//校验账号是否已存在selectBuilder : l.svcCtx.UserModel.CountBuilder(id).Where(sq.Eq{name: in.Name})count, _ : l.svcCtx.UserModel.FindCount(l.ctx, selectBuilder)if count 0 {logx.WithContext(l.ctx).Errorf(账号已存在添加失败userName %s, in.Name)return nil, errors.New(账号已存在)}if in.Password {in.Password 123456}hashedPassword, err : utils.GenerateFromPassword(in.Password)if err ! nil {return nil, errors.New(密码加密出错)}//插入数据result, err : l.svcCtx.UserModel.Insert(l.ctx, sysmodel.SysUser{Name: in.Name,NickName: in.NickName,Avatar: ,Password: hashedPassword,Salt: ,Email: in.Email,Mobile: ,Status: 0,CreateBy: in.CreateBy,UpdateTime: time.Time{},DelFlag: 0,})if err ! nil {return nil, err}insertId, err : result.LastInsertId()if err ! nil {return nil, err}return sysclient.UserAddResp{Id: insertId}, nil
}userinfologic.go
修改rpc/sys/internal/logic/userinfologic.go如下
func (l *UserInfoLogic) UserInfo(in *sysclient.InfoReq) (*sysclient.InfoResp, error) {rowBuilder : l.svcCtx.UserModel.RowBuilder().Where(sq.Eq{id: in.UserId})userInfo, err : l.svcCtx.UserModel.FindOneByQuery(l.ctx, rowBuilder)switch err {case nil:case sqlx.ErrNotFound:logx.WithContext(l.ctx).Infof(用户不存在userId:%s, in.UserId)return nil, fmt.Errorf(用户不存在userId:%s, strconv.FormatInt(in.UserId, 10))default:return nil, err}//var list []*sys.MenuListTree//var listUrls []stringreturn sysclient.InfoResp{Avatar: 11111,Name: userInfo.Name,MenuListTree: nil,BackgroundUrls: nil,ResetPwd: false,}, nil
}common目录
common目录下为通用工具直接拷贝进去即可。
bcrypt.go
common/utils/bcrypt.go
package utilsimport (bytescrypto/md5crypto/randcrypto/rsacrypto/x509encoding/base64encoding/hexencoding/pemfmtloggithub.com/tjfoc/gmsm/sm2x509g github.com/tjfoc/gmsm/x509golang.org/x/crypto/bcrypt
)func GenerateFromPassword(pwd string) (hashedPassword string, err error) {password : []byte(pwd)// Hashing the password with the default cost of 10hashedPasswordBytes, err : bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)hashedPassword string(hashedPasswordBytes)return
}func CompareHashAndPassword(hashedPwd, plainPwd string) bool {byteHash : []byte(hashedPwd)err : bcrypt.CompareHashAndPassword(byteHash, []byte(plainPwd))if err ! nil {return false}return true
}// EncryptSm2 加密
func EncryptSm2(privateKey, content string) string {// 从十六进制导入公私钥priv, err : x509g.ReadPrivateKeyFromHex(privateKey)if err ! nil {log.Fatal(err)}// 公钥加密部分msg : []byte(content)pub : priv.PublicKeycipherTxt, err : sm2.Encrypt(pub, msg, rand.Reader, sm2.C1C2C3) // sm2加密if err ! nil {log.Fatal(err)}// fmt.Printf(加密文字:%s\n加密结果:%x\n, msg, cipherTxt)encodeRes : fmt.Sprintf(%x, cipherTxt)return encodeRes
}// DecryptSm2 解密
func DecryptSm2(privateKey, encryptData string) (string, error) {// 从十六进制导入公私钥priv, err : x509g.ReadPrivateKeyFromHex(privateKey)if err ! nil {return , err}// 私钥解密部分hexData, err : hex.DecodeString(encryptData)if err ! nil {return , err}plainTxt, err : sm2.Decrypt(priv, hexData, sm2.C1C2C3) // sm2解密if err ! nil {return , err}// fmt.Printf(解密后的明文%s\n私钥%s \n 匹配一致, plainTxt, x509.WritePrivateKeyToHex(priv))return string(plainTxt), nil
}// EncryptAndDecrypt 加密/解密
func EncryptAndDecrypt(privateKey, content string) {// 从十六进制导入公私钥priv, err : x509g.ReadPrivateKeyFromHex(privateKey)if err ! nil {log.Fatal(err)}// 公钥加密部分msg : []byte(content)pub : priv.PublicKeycipherTxt, err : sm2.Encrypt(pub, msg, rand.Reader, sm2.C1C2C3) // sm2加密if err ! nil {log.Fatal(err)}fmt.Printf(加密文字:%s\n加密结果:%x\n, msg, cipherTxt)// 私钥解密部分plainTxt, err : sm2.Decrypt(priv, cipherTxt, sm2.C1C2C3) // sm2解密if err ! nil {log.Fatal(err)}if !bytes.Equal(msg, plainTxt) {log.Fatal(原文不匹配:, msg)}fmt.Printf(解密后的明文%s\n私钥%s \n 匹配一致, plainTxt, x509g.WritePrivateKeyToHex(priv))
}// EncryptRSA 加密
func EncryptRSA(content, publicKey string) (encryptStr string, err error) {// var publicKey -----BEGIN PUBLIC KEY-----// MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaIWAL13RUbJN2hfmTSyOBotf// 71pq8jc2ploPBHtN3smTUkYPbX2MIbO9TrRj3u67s/kGQZrz6tyQ68oexpukPN4/// ypzp64UA5CQENSA41ZxTpYADbFQsiX9Spv6aDHhHzUlZtWRru9ptcFO3tDKq0ACT// OAR1ZEHFwQGhzwaAowIDAQAB// -----END PUBLIC KEY-----block, _ : pem.Decode([]byte(publicKey))if block nil {return , fmt.Errorf(failed to parse public key PEM)}publicKeyInterface, err : x509.ParsePKIXPublicKey(block.Bytes)if err ! nil {return , err}// 类型断言rsaPublicKey : publicKeyInterface.(*rsa.PublicKey)// 加密数据encryptedData, err : rsa.EncryptPKCS1v15(rand.Reader, rsaPublicKey, []byte(content))if err ! nil {return , fmt.Errorf(error encrypting data:%v, err)}return base64.StdEncoding.EncodeToString(encryptedData), err}// DecryptRSA 解密
func DecryptRSA(encryptStr, privateKey string) (content string, err error) {// var privateKey -----BEGIN PRIVATE KEY-----// MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANohYAvXdFT5sk3a// FZNLI4Gi1/vWmryNzamWg8Ee03eyZNSRg9tfYwhs71OtGPe7ruzQZBmvPq3JDr// yh7Gm6Q83j/KnOnrhQDkJAQ1IDjVnFOlgANsVCyJf1Km/poMeEfNSVm1ZGu72m1w// U7e0MqrQAJM4BHVkQcXBAaHPBoCjAgMBAAECgYA/aJJN/uyvQwKlBPALn4WDJ73e// PmrvScfpGAR39xqM8WVxcOoy0Y6FRX1wupHWefWIqQSQIH1wEoM5LGzX8yflSo// lG3E0mgJzrMAOTs5FVkdN4tV6rKYq/vA9R67AD0a9nq7yOFeTqjGzWj4l7Vptvu4// prK5GWVi0mpB2kKQJBAP0n1EMAHQSW38zOngfaqC6cvnjEbX4NnhSPRZVzlu3y// ZkitiA/Y96yCCybCWD0TkF43Z1p0wIGuXSJ1Igku6bcCQQDclMziUz1RnQDl7RIN// 449vbmG2mGLoXp5HTD9QP0NB46w64WwXIX7IZL2GubndTRFUFTTPLZZ80XbhFtp6// 19B1AkEAnIgjJGaOisbrjQz5BCw8r821rKDwfu/WninUwcteOLUYb7n1Fq92vZEP// aiDjRKizLL6fRnxIiCcTaXn52KnMUwJBAJaKOxYPRx8G7tD8rcCq2H5tLTFNWNv// B8iTAfbLZiR2tFlu9S0IIBW1ox9qa63b5gKjgmoOq9C9x8swpKUH2u0CQAKDHqwh// aH6lVtV8cw55Ob8Dsh3PgFUazuM1e5PjmZku3/2jeQQJrecu/S6LooPdeUfEtV// OB/5HvFhGpEu2/E// -----END PRIVATE KEY-----block, _ : pem.Decode([]byte(privateKey))if block nil {return , fmt.Errorf(failed to parse private key PEM)}privateKeyData, err : x509.ParsePKCS8PrivateKey(block.Bytes)if err ! nil {return , err}privateKeyInterface : privateKeyData.(*rsa.PrivateKey)// 解密数据byt, err : base64.StdEncoding.DecodeString(encryptStr)if err ! nil {return , fmt.Errorf(base64 DecodeString err:%v, err)}decryptedData, err : rsa.DecryptPKCS1v15(rand.Reader, privateKeyInterface, byt)if err ! nil {return , fmt.Errorf(error decrypting data:%v, err)}return string(decryptedData), nil}func Md5(s []byte) string {m : md5.New()m.Write(s)return hex.EncodeToString(m.Sum(nil))
}code.go
common/errors/code.go
package errorsconst BaseCode 50000const RpcCode 51000const MustUpdatePwdCode 50005const LoginExpired 50001base.go
common/errors/base.go
package errorstype CommonError interface {Error() stringErrorType() stringData() *CommonErrorResp
}type CommonErrorResp struct {Code int json:codeMessage string json:messageType string json:error
}errorx.go
common/errors/errorx/errorx.go
package errorximport go-zero-test/common/errorsvar _ errors.CommonError (*ErrorX)(nil)type ErrorX struct {Code int json:codeMessage string json:messageType string json:error
}func (e *ErrorX) Error() string {return e.Message
}func (e *ErrorX) ErrorType() string {return e.Type
}func (e *ErrorX) Data() *errors.CommonErrorResp {return errors.CommonErrorResp{Code: e.Code,Message: e.Message,Type: e.Type,}
}func New(s string) error {return ErrorX{Code: errors.BaseCode, Message: s, Type: base error}
}func NewCodeErr(code int, s string) error {return ErrorX{Code: code, Message: s, Type: base error}
}rpcerror.go
common/errors/rpcerror/rpcerror.go
package rpcerrorimport go-zero-test/common/errorsvar _ errors.CommonError (*RpcError)(nil)type RpcError struct {Code int json:codeMessage string json:messageType string json:error
}func (e *RpcError) Error() string {return e.Message
}func (e *RpcError) ErrorType() string {return e.Type
}func (e *RpcError) Data() *errors.CommonErrorResp {return errors.CommonErrorResp{Code: e.Code,Message: e.Message,Type: e.Type,}
}// New rpc返回错误
func New(e error) error {msg : e.Error()[len(rpc error: code Unknown desc ):]return RpcError{Code: errors.RpcCode, Message: msg, Type: rpc error}
}// NewError 返回自定义错误rpc返回错误
func NewError(s string, err error) error {msgType : err.Error()[len(rpc error: code Unknown desc ):]return RpcError{Code: errors.RpcCode, Message: s, Type: msgType}
}完整调用演示
最后在根目录go-zero-test执行下命令。
go mod tidy运行rpc服务 修改路径。 之后直接启动即可。 运行api 修改路径。 之后直接启动即可。 api调用
命令请求
curl -i localhost:8888/sys/user/currentUser返回结果
HTTP/1.1 200 OK
Content-Type: application/json; charsetutf-8
Traceparent: 00-7cf8f53fe7009655963024f44767cd53-67d21fe606d82a15-00
Date: Thu, 22 Feb 2024 06:27:28 GMT
Content-Length: 120{code:200,message:成功,data:{avatar:11111,name:admin,menuTree:[],menuTreeVue:[],resetPwd:false}}%或者postman调用也行。 后续研发
后续新增服务、新增接口流程同编写rpc服务模块。