[golang gin框架] 42.Gin商城项目-微服务实战之后台Rbac微服务角色增删改查微服务
一.重构后台Rbac用户登录微服务功能
上一节讲解了后台Rbac微服务用户登录功能以及Gorm数据库配置单独抽离,Consul配置单独抽离,这一节讲解后台Rbac微服务角色增删改查微服务功能,Rbac微服务角色增删改查微服务和后台Rbac用户登录微服务是属于同一个Rbac微服务的不同子微服务功能,为了区分不同子微服务功能,所以,在进行后台Rbac微服务角色增删改查微服务功能之前,需要对前面一节Rbac用户登录微服务进行重构
1.重新完善proto文件夹下的rbac.proto
把rbac.proto改名为rbacLogin.proto,并且修改option go_package,go_package = "./proto/rbacLogin",service Rbac该为service RbacLogin,其他代码不变,完整代码如下:
syntax = "proto3";package rbac;option go_package = "./proto/rbacLogin";service RbacLogin {//登录操作rpc Login(LoginRequest) returns (LoginResponse) {}
}//用户信息model:参考models/manager.go,一一对应
message ManagerModel{int64 id=1;string username=2;string password=3;string mobile=4;string email=5;int64 status=6;int64 roleId=7;int64 addTime=8;int64 isSuper=9;
}//登录请求参数
message LoginRequest{string username=1;string password=2;
}//登录返回参数
message LoginResponse{bool isLogin=1;repeated ManagerModel userlist=2; //因为在client端需要返回用户相关信息,故定义一个切片
}
2.删除proto生成的rbac文件夹
3.执行protoc --proto_path=. --micro_out=. --go_out=:. proto/rbacLogin.proto,生成对应的rbacLgin文件夹
4.修改handler文件夹下的rbac.go
把rbac.go文件名改为rbacLigin.go,并把pb "rbac/proto/rbac"修改为pb "rbac/proto/rbacLogin",以及type Rbac struct{}修改为type RbacLogin struct{},完整代码如下:
package handlerimport ("context""rbac/models"pb "rbac/proto/rbacLogin"
)type RbacLogin struct{}//后台用户登录的微服务
func (e *RbacLogin) Login(ctx context.Context, req *pb.LoginRequest, res *pb.LoginResponse) error {managerList := []models.Manager{}err := models.DB.Where("username=? AND password=?", req.Username, req.Password).Find(&managerList).Error//处理数据var templist []*pb.ManagerModelfor i := 0; i < len(managerList); i++ {templist = append(templist, &pb.ManagerModel{Id: int64(managerList[i].Id),Username: managerList[i].Username,Password: managerList[i].Password,Mobile: managerList[i].Mobile,Email: managerList[i].Email,Status: int64(managerList[i].Status),RoleId: int64(managerList[i].RoleId),AddTime: int64(managerList[i].AddTime),IsSuper: int64(managerList[i].IsSuper),})}if len(managerList) > 0 {res.IsLogin = true} else {res.IsLogin = false}res.Userlist = templistreturn err
}
5.完善main.go
把main.go中的pb "rbac/proto/rbac"改成pb "rbac/proto/rbacLogin",以及下面的
pb.RegisterRbacHandler(srv.Server(), new(handler.Rbac))改为pb.RegisterRbacLoginHandler(srv.Server(), new(handler.RbacLogin)),完整代码如下:
package mainimport ("rbac/handler""rbac/models"pb "rbac/proto/rbacLogin""go-micro.dev/v4""go-micro.dev/v4/logger""github.com/go-micro/plugins/v4/registry/consul"
)var (service = "rbac"version = "latest"
)func main() {//集成consulconsulReg := consul.NewRegistry()// Create service//读取.ini里面的配置addr := models.Config.Section("consul").Key("addr").String()srv := micro.NewService(micro.Address(addr), //指定微服务的ip: 选择注册服务器地址,也可以不配置,默认为本机,也可以选择consul集群中的clientmicro.Name(service),micro.Version(version),//注册consulmicro.Registry(consulReg),)srv.Init(micro.Name(service),micro.Version(version),)// Register handlerif err := pb.RegisterRbacLoginHandler(srv.Server(), new(handler.RbacLogin)); err != nil {logger.Fatal(err)}// Run serviceif err := srv.Run(); err != nil {logger.Fatal(err)}
}
6.运行该微服务,看看修改是否报错
7.完善客户端微服务
删除client下项目中proto文件夹下的rbac.proto文件以及rbac文件夹,把server/rbac/proto下的rbacLogin.go以及rbacLogin文件夹复制到client下项目中proto文件夹下
8.修改调用proto/rbac微服务接口的代码
这里只有controllers/login.go下调用了rbac 登录的微服务代码,所以把pbRbac "goshop/proto/rbac"修该为pbRbac "goshop/proto/rbacLogin",以及pbRbac.NewRbacService改为pbRbac.NewRbacLoginService即可
9.校验Rbac用户登录微服务操作是否成功
二.实现后台权限管理Rbac之角色增删改查微服务
1.创建Role模型
要实现角色的增删改查,就需要创建对应的模型,故在server/rbac/models下创建role.go模型文件,参考[golang gin框架] 14.Gin 商城项目-RBAC管理代码如下:
package models//角色模型type Role struct { // 结构体首字母大写, 和数据库表名对应, 默认访问数据表users, 可以设置访问数据表的方法Id intTitle stringDescription stringStatus intAddTime int
}//配置数据库操作的表名称
func (Role) TableName() string {return "role"
}
2.在proto文件夹下创建rbacRole.proto
参考[golang gin框架] 14.Gin 商城项目-RBAC管理,创建rbacRole.proto.生成角色相关方法,具体代码如下:
syntax = "proto3";package rbac;option go_package = "./proto/rbacRole";//角色管理
service RbacRole {//获取角色rpc方法: 请求参数RoleGetRequest, 响应参数RoleGetResponserpc RoleGet(RoleGetRequest) returns (RoleGetResponse) {}//增加角色rpc方法: 请求参数RoleAddRequest, 响应参数RoleAddResponserpc RoleAdd(RoleAddRequest) returns (RoleAddResponse) {}//编辑角色rpc方法: 请求参数RoleEditRequest, 响应参数RoleEditResponserpc RoleEdit(RoleEditRequest) returns (RoleEditResponse) {}//删除角色rpc方法: 请求参数RoleDeleteRequest, 响应参数RoleDeleteResponserpc RoleDelete(RoleDeleteRequest) returns (RoleDeleteResponse) {}
}//角色相关model
message RoleModel{int64 id=1;string title=2;string description=3;int64 status=4;int64 addTime =5;
}//获取角色请求参数
message RoleGetRequest{//角色idint64 id =1;
}//获取角色响应参数
message RoleGetResponse{//角色model切片repeated RoleModel roleList=1;
}//增加角色请求参数
message RoleAddRequest{//角色名称string title=1;//说明string description=2;//状态int64 status=3;//增加时间int64 addTime =4;
}//增加角色响应参数
message RoleAddResponse{//是否增加成功bool success=1;//返回状态说明string message=2;
}//编辑角色请求参数
message RoleEditRequest{//角色idint64 id=1;//角色名称string title=2;//说明string description=3;//状态int64 status=4;//增加时间int64 addTime =5;
}//编辑角色响应参数
message RoleEditResponse{ //是否编辑成功bool success=1;//返回状态说明string message=2;
}//删除角色请求参数
message RoleDeleteRequest{//角色idint64 id=1;
}//删除角色响应参数
message RoleDeleteResponse{ //是否删除成功bool success=1;//返回状态说明string message=2;
}
3.生成role相关pb.go,pb.micro.go文件
在server/rbac下运行命令protoc --proto_path=. --micro_out=. --go_out=:. proto/rbacRole.proto即可
4.在handler文件夹下创建rbacRole.go文件,实现proto中的service方法
参考[golang gin框架] 14.Gin 商城项目-RBAC管理_角色的增删改查,具体rbacRole.go代码如下:
package handlerimport ("context""rbac/models""strconv"pb "rbac/proto/rbacRole"
)type RbacRole struct{}//获取角色
func (e *RbacRole) RoleGet(ctx context.Context, req *pb.RoleGetRequest, res *pb.RoleGetResponse) error {roleList := []models.Role{}where := "1=1"if req.Id > 0 { // 当传入角色id时,获取对应的角色数据, 当没有传入角色id时,获取角色列表数据where += " AND id=" + strconv.Itoa(int(req.Id))}models.DB.Where(where).Find(&roleList)//处理数据var tempList []*pb.RoleModelfor _, v := range roleList {tempList = append(tempList, &pb.RoleModel{Id: int64(v.Id),Title: v.Title,Description: v.Description,Status: int64(v.Status),AddTime: int64(v.AddTime),})}res.RoleList = tempListreturn nil
}//增加角色
func (e *RbacRole) RoleAdd(ctx context.Context, req *pb.RoleAddRequest, res *pb.RoleAddResponse) error {role := models.Role{}role.Title = req.Titlerole.Description = req.Descriptionrole.Status = int(req.Status)role.AddTime = int(req.AddTime)err := models.DB.Create(&role).Errorif err != nil {res.Success = falseres.Message = "增加数据失败"} else {res.Success = trueres.Message = "增加数据成功"}return err
}//修改角色
func (e *RbacRole) RoleEdit(ctx context.Context, req *pb.RoleEditRequest, res *pb.RoleEditResponse) error {role := models.Role{Id: int(req.Id)}models.DB.Find(&role)role.Title = req.Titlerole.Description = req.Descriptionerr := models.DB.Save(&role).Errorif err != nil {res.Success = falseres.Message = "修改数据失败"} else {res.Success = trueres.Message = "修改数据成功"}return nil
}//删除角色
func (e *RbacRole) RoleDelete(ctx context.Context, req *pb.RoleDeleteRequest, res *pb.RoleDeleteResponse) error {role := models.Role{Id: int(req.Id)}err := models.DB.Delete(&role).Errorif err != nil {res.Success = falseres.Message = "删除数据失败"} else {res.Success = trueres.Message = "删除数据成功"}return nil
}
5.在main.go文件中注册注册角色微服务
只需在import中引入pbRole "rbac/proto/rbacRole"以及在main()中加入以下代码即可:
// Register handler:注册角色微服务if err := pbRole.RegisterRbacRoleHandler(srv.Server(), new(handler.RbacRole)); err != nil {logger.Fatal(err)}
具体代码如下:
package mainimport ("rbac/handler""rbac/models"pb "rbac/proto/rbacLogin"pbRole "rbac/proto/rbacRole""go-micro.dev/v4""go-micro.dev/v4/logger""github.com/go-micro/plugins/v4/registry/consul"
)var (service = "rbac"version = "latest"
)func main() {//集成consulconsulReg := consul.NewRegistry()// Create service//读取.ini里面的配置addr := models.Config.Section("consul").Key("addr").String()srv := micro.NewService(micro.Address(addr), //指定微服务的ip: 选择注册服务器地址,也可以不配置,默认为本机,也可以选择consul集群中的clientmicro.Name(service),micro.Version(version),//注册consulmicro.Registry(consulReg),)srv.Init(micro.Name(service),micro.Version(version),)// Register handler:注册登录微服务if err := pb.RegisterRbacLoginHandler(srv.Server(), new(handler.RbacLogin)); err != nil {logger.Fatal(err)}// Register handler:注册角色微服务if err := pbRole.RegisterRbacRoleHandler(srv.Server(), new(handler.RbacRole)); err != nil {logger.Fatal(err)}// Run serviceif err := srv.Run(); err != nil {logger.Fatal(err)}
}
6.实现Rbac角色客户端微服务功能
参考[golang gin框架] 41.Gin商城项目-微服务实战之后台Rbac微服务(用户登录 、Gorm数据库配置单独抽离、 Consul配置单独抽离)
(1).复制server/rbac/proto文件夹下rbacRole.go以及rbacRole文件夹到client项目中的proto文件夹下
(2). 调用Rbac角色增删改查微服务
在controllers/admin/role.go的Index(),DoAdd(),DoEdit(),Delete()方法中调用Rbac角色增删改查微服务功能
原controllers/admin/role.go代码如下:也可参考[golang gin框架] 14.Gin 商城项目-RBAC管理
package adminimport ("github.com/gin-gonic/gin""goshop/models""net/http""strings"
)type RoleController struct {BaseController
}//角色列表
func (con RoleController) Index(c *gin.Context) {//定义一个角色切片roleList := []models.Role{}//获取角色models.DB.Find(&roleList)c.HTML(http.StatusOK, "admin/role/index.html", gin.H{"roleList": roleList,})
}//新增角色
func (con RoleController) Add(c *gin.Context) {c.HTML(http.StatusOK, "admin/role/add.html", gin.H{})
}//新增角色:提交
func (con RoleController) DoAdd(c *gin.Context) {//获取表单的提交数据//strings.Trim(str, cutset), 去除字符串两边的cutset字符title := strings.Trim(c.PostForm("title"), " ") // 去除字符串两边的空格description := strings.Trim(c.PostForm("description"), " ")//判断角色名称是否为空if title == "" {con.Error(c, "角色名称不能为空", "/admin/role/add")return}//给角色模型赋值,并保存数据到数据库role := models.Role{}role.Title = titlerole.Description = descriptionrole.Status = 1role.AddTime = int(models.GetUnix())err := models.DB.Create(&role).Errorif err != nil {con.Error(c, "增加角色失败,请重试", "/admin/role/add")return}con.Success(c, "增加角色成功", "/admin/role")
}//编辑角色
func (con RoleController) Edit(c *gin.Context) {//获取角色idid, err := models.Int(c.Query("id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")} else {role := models.Role{Id: id}models.DB.Find(&role)c.HTML(http.StatusOK, "admin/role/edit.html", gin.H{"role": role,})}
}//编辑角色:提交
func (con RoleController) DoEdit(c *gin.Context) {//获取提交的表单数据id, err := models.Int(c.PostForm("id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")return}//获取表单的提交数据//strings.Trim(str, cutset), 去除字符串两边的cutset字符title := strings.Trim(c.PostForm("title"), " ") // 去除字符串两边的空格description := strings.Trim(c.PostForm("description"), " ")//判断角色名称是否为空if title == "" {con.Error(c, "角色名称不能为空", "/admin/role/add")return}//查询角色是否存在role := models.Role{Id: id}models.DB.Find(&role)//修改角色属性role.Title = titlerole.Description = descriptionerr = models.DB.Save(&role).Errorif err != nil {con.Error(c, "修改数据失败", "/admin/role/edit?id="+models.String(id))return}con.Success(c, "修改数据成功", "/admin/role")
}//删除角色
func (con RoleController) Delete(c *gin.Context) {//获取提交的表单数据id, err := models.Int(c.Query("id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")return}//查询角色是否存在role := models.Role{Id: id}err = models.DB.Delete(&role).Errorif err != nil {con.Error(c, "删除数据失败", "/admin/role")return}con.Success(c, "删除数据成功", "/admin/role")
}//授权
func (con RoleController) Auth(c *gin.Context) {//获取idid, err := models.Int(c.Query("id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")return}role := models.Role{Id: id}models.DB.Find(&role)//获取所有权限列表accessList := []models.Access{}models.DB.Where("module_id = ?", 0).Preload("AccessItem").Find(&accessList)//获取当前角色拥有的权限,并把权限id放在一个map对象中roleAccess := []models.RoleAccess{}models.DB.Where("role_id = ?", id).Find(&roleAccess)roleAccessMap := make(map[int]int)for _, v := range roleAccess {roleAccessMap[v.AccessId] = v.AccessId}//循环遍历所有权限数据,判断当前权限的id是否在角色权限的map对象中,如果是的话给当前数据加入checked属性for i := 0; i < len(accessList); i++ { //循环权限列表if _, ok := roleAccessMap[accessList[i].Id]; ok { // 判断当前权限是否在角色权限的map对象中accessList[i].Checked = true}for j := 0; j < len(accessList[i].AccessItem); j++ { // 判断当前权限的子栏位是否在角色权限的map中if _, ok := roleAccessMap[accessList[i].AccessItem[j].Id]; ok { // 判断当前权限是否在角色权限的map对象中accessList[i].AccessItem[j].Checked = true}}}c.HTML(http.StatusOK, "admin/role/auth.html", gin.H{"roleId": id,"accessList": accessList,})
}//授权提交
func (con RoleController) DoAuth(c *gin.Context) {//获取提交的表单数据roleId, err := models.Int(c.PostForm("role_id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")return}//获取表单提交的权限id切片accessIds := c.PostFormArray("access_node[]")//先删除当前角色对应的权限roleAccess := models.RoleAccess{}models.DB.Where("role_id = ?", roleId).Delete(&roleAccess)//循环遍历accessIds,增加当前角色对应的权限for _, v := range accessIds {roleAccess.RoleId = roleIdaccessId, _ := models.Int(v)roleAccess.AccessId = accessIdmodels.DB.Create(&roleAccess)}con.Success(c, "角色授权成功", "/admin/role")
}
调用Rbac角色增删改查微服务后,代码如下:
package adminimport ("context""github.com/gin-gonic/gin""goshop/models"pbRbac "goshop/proto/rbacRole""net/http""strings"
)type RoleController struct {BaseController
}//角色列表
func (con RoleController) Index(c *gin.Context) {//调用Rbac微服务rbacClient := pbRbac.NewRbacRoleService("rbac", models.RbacClient)res, _ := rbacClient.RoleGet(context.Background(), &pbRbac.RoleGetRequest{})c.HTML(http.StatusOK, "admin/role/index.html", gin.H{"roleList": res.RoleList,})
}//新增角色
func (con RoleController) Add(c *gin.Context) {c.HTML(http.StatusOK, "admin/role/add.html", gin.H{})
}//新增角色:提交
func (con RoleController) DoAdd(c *gin.Context) {//获取表单的提交数据//strings.Trim(str, cutset), 去除字符串两边的cutset字符title := strings.Trim(c.PostForm("title"), " ") // 去除字符串两边的空格description := strings.Trim(c.PostForm("description"), " ")//判断角色名称是否为空if title == "" {con.Error(c, "角色名称不能为空", "/admin/role/add")return}//调用微服务,实现角色的添加rbacClient := pbRbac.NewRbacRoleService("rbac", models.RbacClient)res, _ := rbacClient.RoleAdd(context.Background(), &pbRbac.RoleAddRequest{Title: title,Description: description,AddTime: models.GetUnix(),Status: 1,})if !res.Success {con.Error(c, "增加角色失败 请重试", "/admin/role/add")} else {con.Success(c, "增加角色成功", "/admin/role")}
}//编辑角色
func (con RoleController) Edit(c *gin.Context) {//获取角色idid, err := models.Int(c.Query("id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")} else {//调用微服务,获取角色信息rbacClient := pbRbac.NewRbacRoleService("rbac", models.RbacClient)res, _ := rbacClient.RoleGet(context.Background(), &pbRbac.RoleGetRequest{Id: int64(id),})c.HTML(http.StatusOK, "admin/role/edit.html", gin.H{"role": res.RoleList[0],})}
}//编辑角色:提交
func (con RoleController) DoEdit(c *gin.Context) {//获取提交的表单数据id, err := models.Int(c.PostForm("id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")return}//获取表单的提交数据//strings.Trim(str, cutset), 去除字符串两边的cutset字符title := strings.Trim(c.PostForm("title"), " ") // 去除字符串两边的空格description := strings.Trim(c.PostForm("description"), " ")//判断角色名称是否为空if title == "" {con.Error(c, "角色名称不能为空", "/admin/role/add")return}//调用微服务修改rbacClient := pbRbac.NewRbacRoleService("rbac", models.RbacClient)res, _ := rbacClient.RoleEdit(context.Background(), &pbRbac.RoleEditRequest{Id: int64(id),Title: title,Description: description,})if !res.Success {con.Error(c, "修改数据失败", "/admin/role/edit?id="+models.String(id))return}con.Success(c, "修改数据成功", "/admin/role")
}//删除角色
func (con RoleController) Delete(c *gin.Context) {//获取提交的表单数据id, err := models.Int(c.Query("id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")return}rbacClient := pbRbac.NewRbacRoleService("rbac", models.RbacClient)res, _ := rbacClient.RoleDelete(context.Background(), &pbRbac.RoleDeleteRequest{Id: int64(id),})if res.Success {con.Success(c, "删除数据成功", "/admin/role")return}con.Error(c, "删除数据失败", "/admin/role")
}//授权
func (con RoleController) Auth(c *gin.Context) {//获取idid, err := models.Int(c.Query("id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")return}role := models.Role{Id: id}models.DB.Find(&role)//获取所有权限列表accessList := []models.Access{}models.DB.Where("module_id = ?", 0).Preload("AccessItem").Find(&accessList)//获取当前角色拥有的权限,并把权限id放在一个map对象中roleAccess := []models.RoleAccess{}models.DB.Where("role_id = ?", id).Find(&roleAccess)roleAccessMap := make(map[int]int)for _, v := range roleAccess {roleAccessMap[v.AccessId] = v.AccessId}//循环遍历所有权限数据,判断当前权限的id是否在角色权限的map对象中,如果是的话给当前数据加入checked属性for i := 0; i < len(accessList); i++ { //循环权限列表if _, ok := roleAccessMap[accessList[i].Id]; ok { // 判断当前权限是否在角色权限的map对象中accessList[i].Checked = true}for j := 0; j < len(accessList[i].AccessItem); j++ { // 判断当前权限的子栏位是否在角色权限的map中if _, ok := roleAccessMap[accessList[i].AccessItem[j].Id]; ok { // 判断当前权限是否在角色权限的map对象中accessList[i].AccessItem[j].Checked = true}}}c.HTML(http.StatusOK, "admin/role/auth.html", gin.H{"roleId": id,"accessList": accessList,})
}//授权提交
func (con RoleController) DoAuth(c *gin.Context) {//获取提交的表单数据roleId, err := models.Int(c.PostForm("role_id"))if err != nil {con.Error(c, "传入数据错误", "/admin/role")return}//获取表单提交的权限id切片accessIds := c.PostFormArray("access_node[]")//先删除当前角色对应的权限roleAccess := models.RoleAccess{}models.DB.Where("role_id = ?", roleId).Delete(&roleAccess)//循环遍历accessIds,增加当前角色对应的权限for _, v := range accessIds {roleAccess.RoleId = roleIdaccessId, _ := models.Int(v)roleAccess.AccessId = accessIdmodels.DB.Create(&roleAccess)}con.Success(c, "角色授权成功", "/admin/role")
}
三.校验权限管理Rbac微服务功能
1.先启动服务端
见[golang gin框架] 40.Gin商城项目-微服务实战之Captcha验证码微服务代码, 这里还要启动验证码captcha微服务服务端代码以及Rbac用户登录微服务服务端代码才行
2.启动客户端
在项目根目录下运行 :go run main.go,启动项目
3.校验权限管理Rbac角色增删改查微服务操作是否成功
访问后台登录页面,输入用户名,密码,验证码,登录到后台后,进入角色管理页面,对角色进行增删改查
好了,权限管理Rbac角色增删改查微服务功能客户端操作完成,这里微服务操作的服务端,客户端功能大致与[golang gin框架] 41.Gin商城项目-微服务实战之后台Rbac微服务(用户登录 、Gorm数据库配置单独抽离、 Consul配置单独抽离)类似,可参考该文章操作,下面一节继续讲解权限管理Rbac微服务管理员的增删改查以及管理员和角色关联功能
[上一节]R[golang gin框架] 41.Gin商城项目-微服务实战之后台Rbac微服务(用户登录 、Gorm数据库配置单独抽离、 Consul配置单独抽离)
相关文章:
![](https://img-blog.csdnimg.cn/cc7e89612730476cabad0f97b7219b12.png)
[golang gin框架] 42.Gin商城项目-微服务实战之后台Rbac微服务角色增删改查微服务
一.重构后台Rbac用户登录微服务功能 上一节讲解了后台Rbac微服务用户登录功能以及Gorm数据库配置单独抽离,Consul配置单独抽离,这一节讲解后台Rbac微服务角色增删改查微服务功能,Rbac微服务角色增删改查微服务和后台Rbac用户登录微服务是属于…...
![](https://img-blog.csdnimg.cn/29a3ac4048ee4e0fb8b19e322fd8b81a.png)
项目篇:Echo论坛系统项目
一、登录注册模块 1、注册功能 1.1、注册流程图 1.2、注册代码 /*** 用户注册* param user* return Map<String, Object> 返回错误提示消息,如果返回的 map 为空,则说明注册成功*/public Map<String, Object> register(User user) {Map&l…...
![](https://img-blog.csdnimg.cn/64457f8fd310473b8930816e17a93b27.png)
数据可视化(2)
1.柱状图 #柱状图 #bar(x,height,width,*,aligncenter,**kwargs) #height柱子的高度,即y轴上的数据 #width数组的宽度,默认值0.8 #*表示后面的参数为匿名关键字,必须传入参数 #kwargs关键字参数x[1,2,3,4,5] height[random.randint(10,100)f…...
![](https://img-blog.csdnimg.cn/img_convert/4d751273f4f7ca142cbe0452f5ecca22.png)
MD-MTSP:斑马优化算法ZOA求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)
一、斑马优化算法ZOA 斑马优化算法(Zebra Optimization Algorithm,ZOA)Eva Trojovsk等人于2022年提出,其模拟斑马的觅食和对捕食者攻击的防御行为。斑马优化算法(Zebra Optimization Algorithm,ZOA&#x…...
![](https://img-blog.csdnimg.cn/61897b1ca2854263aea3256bec969bc9.jpeg)
【笔试强训选择题】Day32.习题(错题)解析
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:笔试强训选择题 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!! 文章目录 前言 一、Da…...
![](https://img-blog.csdnimg.cn/e267b8761c80433f974d60afcc30c6de.jpeg)
抖音seo账号矩阵系统源码如何开发布局?
目录 一、 抖音SEO账号矩阵系统源码的开发布局步骤如下: 二。 开发部署源码 三、 开发部署功能设计 1. 短视频AI智能创作 2. 托管式账号管理: 3. 数据分析 4. 智能营销获客 四。 抖音seo源码开发部署交付技术文档包含 五。 开发代码展示: 一、 抖…...
![](https://www.ngui.cc/images/no-images.jpg)
vue项目cdn打包优化
0.用vue ui可以查看项目打包后的情况。 1.定义包的排除 let externals {axios: axios,element-ui: ELEMENT,echarts: echarts,} configureWebpack: {externals: externals }2.配置cdn包资源 // 配置 let cdn {css: [// element-ui csshttps://unpkg.com/element-ui/lib/th…...
![](https://img-blog.csdnimg.cn/img_convert/0ae1c5222c3338e40078aa49c76cfbf0.jpeg)
Android 之 MediaPlayer 播放音频与视频
本节引言: 本节带来的是Android多媒体中的——MediaPlayer,我们可以通过这个API来播放音频和视频 该类是Androd多媒体框架中的一个重要组件,通过该类,我们可以以最小的步骤来获取,解码 和播放音视频。它支持三种不同的…...
![](https://www.ngui.cc/images/no-images.jpg)
React中事件处理器的基本使用
在React中,为了提高性能,跨浏览器兼容性和开发体验,React实现了一套自己的事件机制,利用事件委托和合成事件的方式统一管理事件订阅和分发。 为了让组件能够响应用户的交互行为,React提供了一系列的事件处理器…...
![](https://www.ngui.cc/images/no-images.jpg)
RobotFramework
一、RobotFramework的简介和特点 1、关键字驱动: 把项目中的业务逻辑封装成一个一个的关键字,然后调用不同的关键字组成不同的业务 2、数据驱动 把测试数据放到excel:yaml文件中 通过改变文件中的数据去驱动测试用例执行 3、特点ÿ…...
![](https://img-blog.csdnimg.cn/21520e5389c9486a9803e8ccc9e45dd1.png)
【Matplotlib 绘制折线图】
使用 Matplotlib 绘制折线图 在数据可视化中,折线图是一种常见的图表类型,用于展示随着变量的变化,某个指标的趋势或关系。Python 的 Matplotlib 库为我们提供了方便易用的功能来绘制折线图。 绘制折线图 下面的代码展示了如何使用 Matplo…...
![](https://img-blog.csdnimg.cn/7527c486323c42eba68971008f9f703b.png)
ARM汇编基本变量的定义和使用
一、ARM汇编中基本变量是什么? 数字变量: GBLA LCLA SETA 逻辑变量:GBLL LCLL SETL 字符串:GBLS LCLS SETLS 注意需要TAB键定义变量和行首改变值 二、使用步骤 1.引入库 代码如下(示例): GBLA led_num Reset_Handler PROCEXPORT Reset_Handler [WEA…...
![](https://img-blog.csdnimg.cn/a22fbdf1f9e64febb8686425d9447992.png)
排序算法汇总
每日一句:你的日积月累终会成为别人的望尘莫及 目录 常数时间的操作 选择排列 冒泡排列 【异或运算】 面试题: 1)在一个整形数组中,已知只有一种数出现了奇数次,其他的所有数都出现了偶数次,怎么找到…...
![](https://www.ngui.cc/images/no-images.jpg)
cocos2d 中UserDefault在windows平台下的路径问题
在使用cocos2dx c开发项目时,通常使用cocos自带的UserDefault来存储一些项目所用到的一些配置信息:如游戏的音量,游戏的闯关数等... 但是windows平台下,测试发现如果用户的帐户名使用是中文,在启动程序时会报错&#…...
![](https://img-blog.csdnimg.cn/569062c8596049bb84ee910a9c832a4e.png)
ChatGPT与高等教育变革:价值、影响及未来发展
最近一段时间,ChatGPT吸引了社会各界的目光,它可以撰写会议通知、新闻稿、新年贺信,还可以作诗、写文章,甚至可以撰写学术论文。比尔盖茨、马斯克等知名人物纷纷为此发声,谷歌、百度等知名企业纷纷宣布要提供类似产品。…...
![](https://img-blog.csdnimg.cn/3b64f5126ad54f62beef6bacfd7cf6f9.png)
Matlab Image Processing toolbox 下载安装方法
当安装好Matlab之后,发现没有Image Processing toolbox这个图像处理工具箱 从新安装一遍, 选上 Image Processing toolbox 但是不用选matlab即可 1.找到之前安装时的Setup安装程序包,按照之前安装Matlab步骤,到选择需要安装的Ma…...
![](https://www.ngui.cc/images/no-images.jpg)
什么是消息键(Key)?如何使用消息键进行消息顺序性保证?
消息键(Key)是Kafka消息的一个可选属性,用于标识消息的逻辑关联关系。每条消息可以携带一个关键字作为其键,这个键可以是字符串、整数等数据类型。 使用消息键可以在Kafka中实现消息的顺序性保证,具体方式如下&#x…...
![](https://img-blog.csdnimg.cn/img_convert/8154089778818fb843affaffa572bafe.gif)
慎思笃行,兴业致远:金融行业的数据之道
《中庸》中说,“博学之,审问之,慎思之,明辨之,笃行之”。这段话穿越千年,指引着中国千行百业的发展。对于金融行业来说,庞大的数据量可以说是“博学”的来源。但庞大的数据体量,既是…...
![](https://img-blog.csdnimg.cn/0910fc6f56c54e19b98eef6a5ab17710.gif#pic_center)
Git-分支管理
文章目录 1.分支管理2.合并冲突3.合并模式4.补充 1.分支管理 Git分支管理是指在Git版本控制系统中,使用分支来管理项目的不同开发线路和并行开发的能力。通过分支,开发者可以在独立的环境中进行功能开发、bug修复等工作,而不会影响到主分支上…...
![](https://img-blog.csdnimg.cn/72695eaf029443228e4efda5763ca184.png)
[Ubuntu 22.04] containerd配置HTTP方式拉取私仓Harbor
文章目录 1. 基础环境配置2. Docker安装3. 部署Harbor,HTTP访问4. 部署ContainerD5. 修改docker配置文件,向harbor中推入镜像6. 配置containerd6.1. 拉取镜像验证6.2. 推送镜像验证 1. 基础环境配置 [Ubuntu 22.04] 安装K8S基础环境准备脚本 2. Docker安…...
![](https://www.ngui.cc/images/no-images.jpg)
入门指南:深入解析OpenCV的copyTo函数及其与rect的应用场景
文章目录 导言copyTo函数的示例copyTo函数与rect的应用场景结论 导言 OpenCV是一个功能强大的开源计算机视觉库,广泛应用于图像处理和计算机视觉任务。在OpenCV中,copyTo函数是一个重要的图像处理函数,它允许我们在不同的图像之间复制像素数…...
![](https://img-blog.csdnimg.cn/ba987d6604864c2d87d8c0c45c83e44d.gif#pic_center)
2018年全国硕士研究生入学统一考试管理类专业学位联考写作试题——解析版
2018年1月真题 四、写作:第56~57小题,共65分。其中论证有效性分析30 分,论说文35分。 56.论证有效性分析: 分析下述论证中存在的缺陷和漏洞,选择若干要点,写一篇600字左右的文章,对该论证的有…...
![](https://img-blog.csdnimg.cn/b61bc7d0573b428b8ba136ca581ea640.png)
系统集成|第七章(笔记)
目录 第七章 范围管理7.1 项目范围管理概念7.2 主要过程7.2.1 规划范围管理7.2.2 收集需求7.2.3 定义范围7.2.4 创建工作分解结构 - WBS7.2.5 范围确认7.2.6 范围控制 上篇:第六章、整体管理 第七章 范围管理 7.1 项目范围管理概念 概述:项目范围管理就…...
![](https://img-blog.csdnimg.cn/3fa4a0e1431047d0bbe568d8444eed99.png)
Qt —— Vs2017编译hiredis源码并测试调用(附调用hiredis库源码)
下载hiredis源码 编译hiredis源码 1、解压下载的hiredis源码包,如图使用Vs2017打开hiredis_win.sln 2、如下两图,Vs2017打开.sln后点击升级。 分别对两个工程的debug、release进行配置。Debug配置为多线程调试DLL(MDd)、Release配置为多线程DLL(/MD),这样做是为了配合被调用…...
![](https://www.ngui.cc/images/no-images.jpg)
深入理解设计模式:设计模式定义、设计原则以及组织编目
文章目录 一、设计模式1.1 设计模式的起源1.2 设计模式的定义1.3 记录要素1.4 合理使用模式 二、设计模式的六大原则2.1 开闭原则(Open-Closed Principle, OCP)2.1.1 定义2.1.2 原则分析2.1.3 开闭原则的意义所在 2.2 单一职责原则(Single Responsibility Principle, SRP)2.4.1…...
![](https://img-blog.csdnimg.cn/img_convert/6f4f3727021990ec27c065eee13aedf9.png)
鸿鹄协助管理华为云与炎凰Ichiban
炎凰对华为云的需求 在炎凰日常的开发中,对于服务器上的需求,我们基本都是采用云服务。目前我们主要选择的是华为云,华为云的云主机比较稳定,提供的云主机配置也比较多样,非常适合对于不同场景硬件配置的需求ÿ…...
![](https://img-blog.csdnimg.cn/8b1707958d614ad0929fcb427128ae7f.png)
Vite创建Vue+TS项目引入文件路径报错
使用vite搭建vue3脚手架的时候,发现main.ts中引入App.vue编辑器会报错,但是不影响代码运行。 报错信息:TS2307: Cannot find module ‘./App.vue’ or its corresponding type declarations. 翻译过来是找不到模块或者相关的声明类型&#…...
![](https://img-blog.csdnimg.cn/5ca019c2a7b241f3a26b01c9002d3fad.png)
计算机里基本硬件的组成以及硬件协同
文章目录 冯诺依曼体系输入设备输出设备存储器运算器控制器协同工作的流程 冯诺依曼体系 世界上第一台通用计算机,ENIAC,于1946年诞生于美国一所大学。 ENIAC研发的前期,需要工作人员根据提前设计好的指令手动接线,以这种方式输入…...
![](https://img-blog.csdnimg.cn/0407db3b09ed481e9a6c8769876c9722.jpg)
2023软件设计师中级备考经验分享(文中有资料链接分享)
先摊结论吧,软考中级设计师备考只是备考半个月(期间还摆烂了几天),然而成绩如下: 我自己都没想到会这么好的成绩。。。 上午题:推荐把软考通APP里的历年真题刷3-4遍,直接刷真题,然后…...
![](https://img-blog.csdnimg.cn/img_convert/1570d0b3be7c53ed73252bf8e38df765.png)
Windows 10 中无法最大化任务栏中的程序
方法1:仅选择选项 PC 屏幕 如果您使用双显示器,有时这可能会发生在您的 1 台计算机已插入但您正在访问的应用程序正在另一台计算机上运行的情况下,因此您看不到任何选项。因此,请设置仅在主计算机上显示显示的 PC 屏幕选项。 第…...
![](/images/no-images.jpg)
网站模板服务商/百度竞价推广的优势
用IE的时候,地址栏的路径会多了一层或几层。在js用 window.location.href跳转,用相对路径,google是在项目名后,IE却多一层 。 解答: 其实这个不管iE和chrome不一样。其实也包括Firefox。这是浏览器对相对路径的解析不…...
![](/images/no-images.jpg)
供应链管理五大内容/杭州网站seo
对用户发送的信息加密是否会成为大势所趋?进行信息加密是隐私强调者和阴谋论者一直以来的主张。 雅虎公司(Yahoo! Inc., YHOO)周四表示,将加入竞争对手谷歌(Google Inc., GOOG)的行列明年打造出一个安全邮件系统,有了这个安全邮件系统&#x…...
![](/images/no-images.jpg)
东山县建设银行网站/品牌运营管理有限公司
版权声明:本文首发 http://asing1elife.com ,转载请注明出处。 https://blog.csdn.net/asing1elife/article/details/82848367 i18n是internationalization首字母i和末尾字母n以及中间18个字母的简称,意于国际化 更多精彩 更多技术博客&#…...
![](/images/no-images.jpg)
中科汇联网站建设手册/百度首页排名优化公司
Description L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。由于这座山处于高原内 陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天&…...
![](/images/no-images.jpg)
微信应用平台开发/seo实战技巧
文章来源: 学习通http://www.bdgxy.com/目录普通分页查询 如何优化 偏移量大 采用id限定方式 优化数据量大问题 普通分页查询 当我们在日常工作中遇到大数据查询的时候,第一反应就是使用分页查询。 mysql支持limit语句来选取指定的条数数据࿰…...
如何利用视频网站做数字营销推广/百度知道官网首页登录入口
世界上最安全的地方是哪?大部分人的答案是家。而守护家的安全就绝对离不开一扇坚固的防盗门。现在市场上防盗门品牌繁杂,质量参差不齐,都说自己是最好的,最安全的,但其实内里却是别有乾坤。日上防盗门质检工程师告诉我…...