【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(五)角色管理、菜单管理模块

窝来辣😁
在这里插入图片描述

下面是前几篇的内容:

第一篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(一)搭建项目

第二篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(二)日志输出中间件、校验token中间件、配置路由、基础工具函数。

第三篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(三)日志管理(登录日志、操作日志)、用户登录模块

第四篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(四)用户管理、部门管理模块


碎碎念:这几天变得好冷,厚衣服穿得好累😂多穿几天可能就习惯了🤣


本篇内容是角色管理、菜单管理模块,有角色菜单关联权限。废话不多说,直接看代码

角色管理

在这里插入图片描述

controller层:sys_role.go

package sysimport ("github.com/gofiber/fiber/v2""github.com/mozillazg/go-pinyin""go-web2/app/common/config""go-web2/app/common/util""go-web2/app/model/sys""strings"
)type RoleController struct{}// 角色列表分页
func (RoleController) GetPage(c *fiber.Ctx) error {role := sys.SysRole{}role.RoleKey = c.Query("code")role.RoleName = c.Query("name")pageSize := c.QueryInt("pageSize", 10)pageNum := c.QueryInt("pageNum", 1)return c.Status(200).JSON(config.Success(role.GetPage(pageSize, pageNum)))
}// 根据id获取角色
func (RoleController) GetById(c *fiber.Ctx) error {role := sys.SysRole{}role.Id = c.Params("id")role.GetById()return c.Status(200).JSON(config.Success(role))
}// 生成角色代码
func (RoleController) CreateCode(c *fiber.Ctx) error {roleName := c.Query("roleName")p := pinyin.NewArgs()p.Style = pinyin.FirstLetterroleKey := util.ConvertToPinyin(roleName, p)return c.Status(200).JSON(config.Success(roleKey))
}// 新增角色
func (RoleController) Insert(c *fiber.Ctx) error {role := sys.SysRole{}if err := c.BodyParser(&role); err != nil {return c.Status(200).JSON(config.Error(err.Error()))}role.Token = c.Get(config.TokenHeader)err := role.Insert()if err != nil {return c.Status(200).JSON(config.Error(err.Error()))}return c.Status(200).JSON(config.Success(nil))
}// 修改角色
func (RoleController) Update(c *fiber.Ctx) error {role := sys.SysRole{}if err := c.BodyParser(&role); err != nil {//log.Error(err.Error())return c.Status(200).JSON(config.Error(err.Error()))}err := role.Update()if err != nil {return c.Status(200).JSON(config.Error(err.Error()))}return c.Status(200).JSON(config.Success(nil))
}// 修改角色状态
func (RoleController) UpdateState(c *fiber.Ctx) error {role := sys.SysRole{}if err := c.BodyParser(&role); err != nil {//log.Error(err.Error())return c.Status(200).JSON(config.Error(err.Error()))}err := role.UpdateState()if err != nil {return c.Status(200).JSON(config.Error(err.Error()))}return c.Status(200).JSON(config.Success(nil))
}// 删除角色
func (RoleController) Delete(c *fiber.Ctx) error {role := sys.SysRole{}if err := c.BodyParser(&role); err != nil {//log.Error(err.Error())return c.Status(200).JSON(config.Error(err.Error()))}ids := strings.Split(role.Id, ",")if err := role.Delete(ids); err != nil {return c.Status(200).JSON(config.Error(err.Error()))}return c.Status(200).JSON(config.Success(nil))
}// 角色下拉列表
func (RoleController) GetSelectList(c *fiber.Ctx) error {role := sys.SysRole{}return c.Status(200).JSON(config.Success(role.GetSelectList()))
}

model层:sys_role.go

package sysimport ("fmt""github.com/google/uuid""github.com/pkg/errors""go-web2/app/common/config""strings""time"
)// 角色管理
type SysRole struct {config.BaseModelRoleKey  string   `json:"roleKey" form:"roleKey"`          // 角色代码RoleName string   `json:"roleName" form:"roleName"`        // 角色名称IsOpen   bool     `json:"isOpen" form:"isOpen"`            // 菜单树是否展开(0折叠 1展开 )State    int      `json:"state" form:"state"`              // 角色状态(1正常 2停用 3删除)Remark   string   `json:"remark" form:"remark"`            // 备注MenuIds  []string `gorm:"-" json:"menuIds" form:"menuIds"` // 菜单组
}// 获取表名
func (SysRole) TableName() string {return "sys_role"
}// 列表
func (e *SysRole) GetPage(pageSize int, pageNum int) config.PageInfo {var list []SysRole // 查询结果var total int64    // 总数query := config.DB.Table(e.TableName())if e.RoleName != "" {query.Where("role_name like ?", fmt.Sprintf("%%%s%%", e.RoleName))}if e.RoleKey != "" {query.Where("role_key like ?", fmt.Sprintf("%%%s%%", e.RoleKey))}offset := (pageNum - 1) * pageSize                                                 // 计算跳过的记录数query.Debug().Order("create_time desc").Offset(offset).Limit(pageSize).Find(&list) // 分页查询,根据offset和limit来查询query.Count(&total)return config.PageInfo{list, total}
}// 详情
func (e *SysRole) GetById() {config.DB.Table(e.TableName()).Where("id = ?", e.Id).Find(e)
}// 新增
func (e *SysRole) Insert() (err error) {// 校验角色名称和角色代码if checkRoleNameAndKey(e.RoleName, "", "") {err = errors.New("角色名称已存在!")return}if checkRoleNameAndKey("", e.RoleKey, "") {err = errors.New("角色代码已存在!")return}e.Id = strings.ReplaceAll(uuid.NewString(), "-", "")e.CreatorId = GetLoginId(e.Token)e.CreateTime = time.Now()config.DB.Table(e.TableName()).Create(e)// 保存菜单树roleMenu := SysRoleMenu{RoleId: e.Id}roleMenu.Insert(e.MenuIds)return
}// 修改
func (e *SysRole) Update() (err error) {// 校验角色名称和角色代码if checkRoleNameAndKey(e.RoleName, "", e.Id) {err = errors.New("角色名称已存在!")return}if checkRoleNameAndKey("", e.RoleKey, e.Id) {err = errors.New("角色代码已存在!")return}config.DB.Model(&SysRole{}).Select("role_key", "role_name", "is_open", "state", "remark").Where("id = ?", e.Id).Save(e)// 保存菜单树roleMenu := SysRoleMenu{RoleId: e.Id}roleMenu.Insert(e.MenuIds)return
}// 修改状态
func (e *SysRole) UpdateState() (err error) {config.DB.Model(&SysRole{}).Select("state").Where("id = ?", e.Id).Save(e)return
}// 删除
func (e *SysRole) Delete(ids []string) (err error) {for _, id := range ids {e.Id = ide.GetById()// 首先查询角色是否已分配用户if CheckRoleExistUser(id) {err = errors.New(fmt.Sprintf("%s角色已分配,不允许删除", e.RoleName))return}}if err = config.DB.Table(e.TableName()).Delete(&SysRole{}, ids).Error; err != nil {return}// 删除角色同时删除角色菜单关联roleMenu := &SysRoleMenu{}roleMenu.Delete(ids)return
}// 角色下拉列表
func (e *SysRole) GetSelectList() []SysRole {var list []SysRole // 查询结果config.DB.Table(e.TableName()).Find(&list)return list
}// 校验角色名称和代码是否存在
func checkRoleNameAndKey(roleName, roleKey, id string) bool {var count int64query := config.DB.Table(SysRole{}.TableName())if roleName != "" {query.Where("role_name = ?", roleName)}if roleKey != "" {query.Where("role_key = ?", roleKey)}if id != "" {query.Where("id <> ?", id)}query.Count(&count)return count > 0
}

菜单管理

在这里插入图片描述

controller层:sys_menu.go

package sysimport ("github.com/gofiber/fiber/v2""go-web2/app/common/config""go-web2/app/model/sys"
)type MenuController struct{}// 菜单树列表
func (MenuController) GetList(c *fiber.Ctx) error {menu := sys.SysMenu{}menu.Name = c.Query("name")menu.State = c.QueryInt("state")return c.Status(200).JSON(config.Success(menu.GetList()))
}// 路由列表
func (MenuController) GetRouters(c *fiber.Ctx) error {menu := sys.SysMenu{}token := c.Get(config.TokenHeader)menu.Id = sys.GetLoginUser(token).RoleIdreturn c.Status(200).JSON(config.Success(menu.GetRouters()))
}// 根据id获取菜单
func (MenuController) GetById(c *fiber.Ctx) error {menu := sys.SysMenu{}menu.Id = c.Params("id")menu.GetById()return c.Status(200).JSON(config.Success(menu))
}// 获取对应角色菜单列表树
func (MenuController) RoleMenuTree(c *fiber.Ctx) error {menu := sys.SysMenu{}roleMenu := sys.SysRoleMenu{}roleMenu.RoleId = c.Params("roleId")checkedIds := roleMenu.GetMenuIdByRoleId() // 根据角色id获取当前角色选中的菜单idresult := map[string]any{}result["menus"] = menu.GetList()   // 获取所有菜单result["checkedKeys"] = checkedIds // 当前角色选中的菜单idreturn c.Status(200).JSON(config.Success(result))
}// 新增菜单
func (MenuController) Insert(c *fiber.Ctx) error {menu := sys.SysMenu{}if err := c.BodyParser(&menu); err != nil {return c.Status(200).JSON(config.Error(err.Error()))}menu.Token = c.Get(config.TokenHeader)err := menu.Insert()if err != nil {return c.Status(200).JSON(config.Error(err.Error()))}return c.Status(200).JSON(config.Success(nil))
}// 修改菜单
func (MenuController) Update(c *fiber.Ctx) error {menu := sys.SysMenu{}if err := c.BodyParser(&menu); err != nil {//log.Error(err.Error())return c.Status(200).JSON(config.Error(err.Error()))}err := menu.Update()if err != nil {return c.Status(200).JSON(config.Error(err.Error()))}return c.Status(200).JSON(config.Success(nil))
}// 删除菜单
func (MenuController) Delete(c *fiber.Ctx) error {menu := sys.SysMenu{}menu.Id = c.Params("id")if err := menu.Delete(); err != nil {return c.Status(200).JSON(config.Error(err.Error()))}return c.Status(200).JSON(config.Success(nil))
}

model层:sys_menu.go

package sysimport ("fmt""github.com/google/uuid""github.com/pkg/errors""go-web2/app/common/config""strings""time"
)// 菜单管理
type SysMenu struct {config.BaseModelParentId   string    `json:"parentId" form:"parentId"`     // 上级部门idName       string    `json:"name" form:"name"`             // 菜单名称Sort       int       `json:"sort" form:"sort"`             // 排序Url        string    `json:"url" form:"url"`               // 访问路径Path       string    `son:"path" form:"path"`              // 组件名称Type       string    `json:"type" form:"type"`             // 菜单类型(M目录 C菜单 F按钮)State      int       `json:"state" form:"state"`           // 菜单状态(1正常 2停用 3删除)Perms      string    `json:"perms" form:"perms"`           // 权限标识Visible    bool      `json:"visible" form:"visible"`       // 显示状态(0隐藏  1显示)Icon       string    `json:"icon" form:"icon"`             // 菜单图标ActiveMenu string    `json:"activeMenu" form:"activeMenu"` // 菜单高亮IsFrame    bool      `json:"isFrame" form:"isFrame"`       // 是否外链(0 否 1 是)Remark     string    `json:"remark" form:"remark"`         // 备注Children   []SysMenu `gorm:"-" json:"children"`            // 子级数据
}type Meta struct {Title      string `json:"title"`      // 设置该路由在侧边栏和面包屑中展示的名字Icon       string `json:"icon"`       // 菜单图标ActiveMenu string `json:"activeMenu"` // 菜单高亮RedDot     bool   `json:"redDot" `
}// 前端路由
type Router struct {Name       string   `json:"name"`       // 菜单名称Path       string   `json:"path"`       // 组件名称Hidden     bool     `json:"hidden"`     // 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现Redirect   string   `json:"redirect"`   // 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击Component  string   `json:"component"`  // 组件地址AlwaysShow bool     `json:"alwaysShow"` // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面ActiveMenu string   `json:"activeMenu"` // 菜单高亮Meta       Meta     `json:"meta"`       // 其他元素Children   []Router `json:"children"`   // 子级数据
}// 获取表名
func (SysMenu) TableName() string {return "sys_menu"
}// 查询菜单列表的sql
var sql = `select a.id,parent_id,name,type,url,path,state,ifnull(perms,'') as perms,icon, sort,visible,active_menu,is_framefrom sys_menu aleft join sys_role_menu b on a.id = b.menu_id
`// 树形菜单列表
func (e *SysMenu) GetList() interface{} {var list []SysMenu // 查询结果query := config.DB.Table(e.TableName())if e.Id != "" { // 角色id不为空,根据角色获取菜单where := sql + " where b.role_id = ?"args := []interface{}{e.Id}if e.Name != "" {where += " and name like ?"args = append(args, fmt.Sprintf("%%%s%%", e.Name))}if e.State != 0 {where += " and state = ?"args = append(args, e.State)}query.Debug().Order("parent_id,sort asc").Raw(where, args...).Find(&list)} else {if e.Name != "" {query.Where("name like ?", fmt.Sprintf("%%%s%%", e.Name))}if e.State != 0 {query.Where("state = ?", e.State)}query.Debug().Order("parent_id,sort asc").Find(&list)}return e.BuildTree(list, "ROOT")
}// 获取路由(根据当前用户的角色id)
func (e *SysMenu) GetRouters() interface{} {var list []SysMenu // 查询结果where := ` where b.role_id = ? and type in ('M', 'C') and a.state = 1`where = sql + whereconfig.DB.Table(e.TableName()).Debug().Order("parent_id,sort asc").Raw(where, e.Id).Find(&list)return buildMenus(e.BuildTree(list, "ROOT"))
}// 详情
func (e *SysMenu) GetById() {config.DB.Table(e.TableName()).Where("id = ?", e.Id).Find(e)
}// 根据角色id获取菜单权限标识
func GetPermsMenuByRoleId(roleId string) []string {var list []SysMenusql := `select a.id,permsfrom sys_menu aleft join sys_role_menu b on a.id = b.menu_idwhere b.role_id = ?order by parent_id,sort`config.DB.Raw(sql, roleId).Find(&list)var result []stringfor _, menu := range list {result = append(result, menu.Perms)}return result
}// 新增
func (e *SysMenu) Insert() (err error) {var count int64// 校验角色名称和角色代码query := config.DB.Table(e.TableName())if e.ParentId == "0" {e.ParentId = "ROOT"}query.Where("name = ? and parent_id = ?", e.Name, e.ParentId).Count(&count)if count > 0 {err = errors.New("菜单名称已存在!")return}e.Id = strings.ReplaceAll(uuid.NewString(), "-", "")e.CreatorId = GetLoginId(e.Token)e.CreateTime = time.Now()config.DB.Table(e.TableName()).Create(e)return
}// 修改
func (e *SysMenu) Update() (err error) {var count int64// 校验角色名称和角色代码query := config.DB.Table(e.TableName())if e.ParentId == "0" {e.ParentId = "ROOT"}if e.Id == e.ParentId {err = errors.New("上级菜单不能是自己!")return}query.Where("name = ? and parent_id = ? and id <> ?", e.Name, e.ParentId, e.Id).Count(&count)if count > 0 {err = errors.New("菜单名称已存在!")return}//config.DB.Model(&SysMenu{}).Select("parent_id", "name", "sort", "url", "path", "type", "state", "perms", "visible", "icon", "active_menu", "is_frame", "remark").Where("id = ?", e.Id).Save(e)config.DB.Model(&SysMenu{}).Omit("id", "create_time").Where("id = ?", e.Id).Save(e)return
}// 删除
func (e *SysMenu) Delete() (err error) {// 1、校验是否存在下级var count int64query := config.DB.Table(e.TableName())query.Where("parent_id = ?", e.Id).Count(&count)if count > 0 {err = errors.New("存在子级菜单,不允许删除")return}// 2、校验是否存在用户if CheckMenuExistRole(e.Id) {err = errors.New("菜单已分配,不允许删除")return}if err = config.DB.Table(e.TableName()).Where("id = ?", e.Id).Delete(SysMenu{}).Error; err != nil {return}return
}// 构建树结构
func (e *SysMenu) BuildTree(list []SysMenu, parentId string) []SysMenu {var tree []SysMenufor _, item := range list {if item.ParentId == parentId {children := e.BuildTree(list, item.Id)if len(children) > 0 {item.Children = children}tree = append(tree, item)}}return tree
}// 构建前端所需要的路由菜单
func buildMenus(menus []SysMenu) []Router {routerList := []Router{}for _, menu := range menus {router := Router{Hidden: menu.Visible, Name: strings.Title(menu.Path), Path: getRouterPath(menu), Component: menu.Url}meta := Meta{Title: menu.Name, Icon: menu.Icon, ActiveMenu: menu.ActiveMenu}router.Meta = metacMenus := menu.Childrenif len(cMenus) > 0 && menu.Type == "M" {router.AlwaysShow = truerouter.Redirect = "noRedirect"router.Children = buildMenus(cMenus)} else if menu.Type == "C" && menu.ParentId == "ROOT" {childrenList := []Router{}children := Router{Name: strings.Title(menu.Path), Path: menu.Path, Component: menu.Url}childMeta := Meta{Title: menu.Name, Icon: menu.Icon, ActiveMenu: menu.ActiveMenu}children.Meta = childMetachildrenList = append(childrenList, children)router.Children = childrenList}routerList = append(routerList, router)}return routerList
}// 获取路由地址
func getRouterPath(menu SysMenu) string {routerPath := menu.Pathif menu.Type == "M" {if menu.Url != config.PARENT_VIEW {routerPath = "/" + menu.Path}} else if menu.Type == "C" && menu.ParentId == "ROOT" {routerPath = "/"}return routerPath
}

角色菜单关联

model层:sys_role_menu.go

package sysimport "go-web2/app/common/config"// 角色菜单关联
type SysRoleMenu struct {RoleId string `json:"roleId" form:"roleId"` // 角色IDMenuId string `json:"menuId" form:"menuId"` // 菜单ID
}// 获取表名
func (SysRoleMenu) TableName() string {return "sys_role_menu"
}// 新增角色和菜单关联
func (e *SysRoleMenu) Insert(menuIds []string) {// 先删除当前角色关联的菜单idconfig.DB.Table(e.TableName()).Where("role_id = ?", e.RoleId).Delete(SysRoleMenu{})// 再添加当前角色关联的菜单idvar list []SysRoleMenu // 存放要添加的数据for _, menuId := range menuIds {item := SysRoleMenu{RoleId: e.RoleId, MenuId: menuId}list = append(list, item)}config.DB.Table(e.TableName()).Create(&list)
}// 删除角色和菜单关联
func (e *SysRoleMenu) Delete(roleIds []string) {// DELETE FROM `sys_role_menu` WHERE role_id in ('1','2','3')config.DB.Table(e.TableName()).Where("role_id in (?)", roleIds).Delete(SysRoleMenu{})
}// 根据角色id获取菜单列表id
func (e *SysRoleMenu) GetMenuIdByRoleId() []string {var list []SysRoleMenuvar result []stringquery := config.DB.Table(e.TableName())query.Where("role_id = ?", e.RoleId)query.Find(&list)for _, menu := range list {result = append(result, menu.MenuId)}return result
}// 根据菜单id校验该菜单是否已分配给角色
func CheckMenuExistRole(menuId string) bool {var count int64config.DB.Table(SysRoleMenu{}.TableName()).Where("menu_id = ?", menuId).Count(&count)return count > 0
}

最后

好像没啥需要特别注意的地方。


好啦,以上就是本篇文章的全部内容辣,等我更完这个项目的全部文章,我会放出完整代码的地址,到现在的话,大概还剩下一篇文章的内容了,很快这个专栏就能更完了,欢迎大家多多点赞支持下,最后可以关注我不迷路~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/232038.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

挑战52天学小猪佩奇笔记--day26

52天学完小猪佩奇--day26 ​【本文说明】 本文内容来源于对B站UP 脑洞部长 的系列视频 挑战52天背完小猪佩奇----day26 的视频内容总结&#xff0c;方便复习。强烈建议大家去关注一波UP&#xff0c;配合UP视频学习。 day26的主题&#xff1a;堆雪人 猜台词&#xff1a; 旁白&am…

卷积神经网络的学习与实现

基于matlab的卷积神经网络(CNN)讲解及代码_matlab中如何查看cnn损失函数-CSDN博客 可以看到与BP神经网络相比&#xff0c;卷积神经网络更加的复杂&#xff0c;这里将会以cnn作为学习案例。 1.经典反向传播算法公式详细推导 这里引用经典反向传播算法公式详细推导_反向目标公…

docker jar包打成镜像并推送到仓库

shell脚本 #!/bin/bash image_name$1 version$2 echo ${version}echo build...... docker build -t ${image_name}:${version} . echo build doing..... sleep 10 image_idsudo docker images | grep ${image_name} | awk -F" " {print $3} | head -n 1 echo ${imag…

敏捷开发项目管理流程及scrum工具

项目启动&#xff1a; 团队明确项目愿景、目标和范围&#xff0c;确定项目范围和优先级&#xff0c;并建立团队以及开展初步计划。 制定产品待办事项清单&#xff08;Product Backlog&#xff09;&#xff1a; 定义项目所需功能、任务和需求列表&#xff0c;并按优先级排序。 …

使用libaom处理av1编码教程

使用libaom处理av1编码教程 文章目录 使用libaom处理av1编码教程一. av1 是什么二. av1 用处三. libaom 是什么四. libaom 安装五. libaom 安装完成六. 解码av1 一. av1 是什么 AV1&#xff08;AOMedia Video 1&#xff09;是一种 开源视频编码格式 。它由开放媒体联盟 (AOM) …

N6705B 直流电源分析仪,模块化,600 W,4 个插槽,是德科技 低功耗测试专家

N6705B 直流电源分析仪 简述&#xff1a; N6705B 直流电源分析仪将多达 4 个先进电源与数字万用表、示波器、任意波形发生器和 Data logger 特性融为一体&#xff0c;可以显著提高向被测件提供直流电压和电流以及进行测量的效率。N6705B 可独立测量被测件的电流&#xff0c;无…

【重点】【前缀树|字典树】208.实现Trie(前缀树)

题目 前缀树介绍&#xff1a;https://blog.csdn.net/DeveloperFire/article/details/128861092 什么是前缀树 在计算机科学中&#xff0c;trie&#xff0c;又称前缀树或字典树&#xff0c;是一种有序树&#xff0c;用于保存关联数组&#xff0c;其中的键通常是字符串。与二叉查…

手写RTOS准备

1. 确定RTOS基本功能 首先&#xff0c;你需要定义你的RTOS应该具备的基本功能。对于一个简单的RTOS&#xff0c;你可能需要包括以下功能&#xff1a; 任务调度&#xff1a;&#xff08;Task Scheduling&#xff09;&#xff1a;这是RTOS最核心的功能之一。它允许系统支持多个任…

【Apache-StreamPark】Flink 开发利器 StreamPark 的介绍、安装、使用

【Apache-StreamPark】Flink 开发利器 StreamPark 的介绍、安装、使用 1&#xff09;框架介绍与引入1.1.&#x1f680; 什么是 StreamPark1.2.&#x1f389; Features1.3.&#x1f3f3;‍&#x1f308; 组成部分1.4.引入 StreamPark 2&#xff09;安装部署2.1.环境要求2.2.Hado…

【缓存】一、Redis的基本使用与Redisson分布式锁

缓存 缓存技术是一种可以大幅度提高系统性能的技术&#xff0c;我们可以在某些适用的场景下使用缓存来大幅度的提高系统性能 读缓存的基本流程&#xff1a; 请求向缓存中查数据 if (命中) {返回缓存中的数据 } else {从数据库中取出数据将该数据在缓存中再存储一份返回缓存中…

重温经典struts1之八种页面跳转或请求转发的方式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 今天来学习下&#xff0c;struts1框架中实现页面跳转或请求转发的八种方式。 页面跳转方式 request的Dispatcher方法 这种方式在学习servlet编程中&#xff0c;我们学…

ACM32如何保护算法、协议不被破解或者修改

ACM32具有以下几种功能&#xff0c;可以保护算法、协议不被破解或者修改。 1.存储保护  RDP读保护  WRP写保护  PCROP 专有代码读保护  MPU存储区域权限控制  Secure User Memory存储区域加密 2.密码学算法引擎  AES  HASH  随机数生成  …

Electron中Tray的setContextMenu导致窗口无法聚焦

在使用 Electron 开发应用时&#xff0c;经常会遇到使用 Tray&#xff08;托盘&#xff09;和设置上下文菜单&#xff08;ContextMenu&#xff09;导致窗口无法正常聚焦的问题。这会导致用户无法在带有输入框的窗口中进行输入&#xff0c;影响应用的用户体验。 tray.setContex…

Vue3-22-组件-插槽的使用详解

插槽是干啥的 插槽 就是 组件中的一个 占位符&#xff0c; 这个占位符 可以接收 父组件 传递过来的 html 的模板值&#xff0c;然后进行填充渲染。 就这么简单&#xff0c;插槽就是干这个的。要说它的优点吧&#xff0c;基本上就是可以使子组件的内容可以被父组件控制&#xf…

亚信科技AntDB数据库——深入了解AntDB-M元数据锁的实现(一)

锁的获取 5.1 锁的强弱 当线程已经持有的锁比新申请的锁更强时&#xff0c;认为已经持有了锁&#xff0c;无需再对申请锁类型加锁。锁的强弱指持有的锁与其他锁的不兼容集合大小&#xff0c;集合相同锁相同&#xff0c;集合更大锁更强&#xff0c;否则无强弱关系。通过锁的兼…

【Linux】基于框架编写驱动代码、驱动代码编译和测试

基于框架编写驱动代码 驱动代码编译和测试 ARM架构上进行Linux内核模块的交叉编译 总结 内核驱动框架基本驱动测试步骤 基于框架编写驱动代码 编写一个Linux设备驱动框架需要一些基本的步骤&#xff0c;以及一些特定于硬件的信息。由于你提到基于PIN4&#xff0c;我将提供…

JavaScript基础篇

目录 1.初始JavaScript 2.Js数据类型 2.1强制转换类型 1.转换为String类型 2.转换为Number类型 3.转换为 Boolean 4.转义符 2.2运算符 2.3分支结构 1.初始JavaScript <!-- 1. 文件引入 --> <!--<script src"./js/index.js"></script>-…

JVM-7-经典垃圾收集器

Serial收集器 这个收集器是一个单线程工作的收集器&#xff0c;但它的“单线程”的意义并不仅仅是说明它只会使用一个处理器或一条收集线程去完成垃圾收集工作&#xff0c;更重要的是强调在它进行垃圾收集时&#xff0c;必须暂停其他所有工作线程&#xff0c;直到它收集结束。…

普冉(PUYA)单片机开发笔记 [完结篇]:使用体会

失败的移植&#xff1a;FreeRTOS 当使用了 PY32F003 的各种接口和功能后&#xff0c;手痒痒想把 FreeRTOS 也搬到这个 MCU 上&#xff0c;参考 STM32 和 GD32 对 FreeRTOS 的移植步骤&#xff0c;把 FreeRTOS v202212.00 版本的源码搬到了 Keil 工程中&#xff0c;编译倒是通过…

sql服务无法启动 请键入net helpmsg 3534

然后 如果是管理员权限打开命令行输入操作的话 先清空 MySQL 下的 data 文件夹&#xff0c;然后确保系统环境变量中已经配置了 mysql 的 bin 目录到Path中&#xff0c;然后执行 sc delete mysql 得到 [SC] DeleteService 成功 后&#xff08;也可能不会有返回信息&#xff…