refactor(menu): 重构菜单服务提升性能和代码质量

- 将控制器返回类型从SystemMenuVo改为SystemMenuTb,避免不必要的对象转换
- 在Mapper层添加listAll默认方法提高数据查询效率
- 移除KitBeanUtil依赖减少代码耦合
- 引入懒加载代理解决循环依赖问题
- 优化菜单创建和编辑逻辑,使用exists方法提升数据库查询性能
- 重写菜单删除逻辑,采用批量操作和层级遍历提升删除效率
- 更新方法签名统一使用SystemMenuTb实体类
- 简化菜单父子关系查询逻辑,提升代码可读性
This commit is contained in:
2026-01-15 19:18:40 +08:00
parent a93a44c3d4
commit 8918ce781b
4 changed files with 174 additions and 60 deletions
@@ -67,8 +67,8 @@ public class SystemMenuController {
@ApiOperation("返回全部的菜单")
@PostMapping(value = "/listMenuByPid")
@PreAuthorize("@el.check('menu:list','roles:list')")
public ResponseEntity<List<SystemMenuVo>> listMenuByPid(@RequestParam Long pid) {
List<SystemMenuVo> systemMenuTbs = systemMenuService.listMenuByPid(pid);
public ResponseEntity<List<SystemMenuTb>> listMenuByPid(@RequestParam Long pid) {
List<SystemMenuTb> systemMenuTbs = systemMenuService.listMenuByPid(pid);
return ResponseEntity.ok(systemMenuTbs);
}
@@ -17,6 +17,7 @@ package cn.odboy.system.dal.mysql;
import cn.odboy.system.dal.dataobject.SystemMenuTb;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
/**
@@ -27,4 +28,7 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SystemMenuMapper extends BaseMapper<SystemMenuTb> {
default List<SystemMenuTb> listAll() {
return selectList(null);
}
}
@@ -30,7 +30,6 @@ import cn.odboy.system.dal.model.response.SystemMenuVo;
import cn.odboy.system.dal.model.response.SystemRoleVo;
import cn.odboy.system.dal.mysql.SystemMenuMapper;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.util.KitBeanUtil;
import cn.odboy.util.KitClassUtil;
import cn.odboy.util.KitValidUtil;
import cn.odboy.util.xlsx.KitExcelExporter;
@@ -42,11 +41,12 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -59,23 +59,27 @@ public class SystemMenuService {
private SystemRoleMenuService systemRoleMenuService;
@Autowired
private SystemUserRoleService systemUserRoleService;
@Lazy
@Autowired
private SystemMenuService proxyService;
/**
* 创建
* 创建 -> TestPassed
*
* @param args /
*/
@Transactional(rollbackFor = Exception.class)
public void saveMenu(SystemMenuTb args) {
if (this.getMenuByTitle(args.getTitle()) != null) {
if (this.existMenuWithTitle(args.getTitle())) {
throw new BadRequestException("菜单标题已存在");
}
if (StrUtil.isNotBlank(args.getComponentName())) {
if (this.getMenuByComponentName(args.getComponentName()) != null) {
if (this.existMenuWithComponentName(args.getComponentName())) {
throw new BadRequestException("菜单组件名称已存在");
}
}
if (Long.valueOf(0L).equals(args.getPid())) {
// 顶级目录
args.setPid(null);
}
if (args.getIFrame()) {
@@ -92,7 +96,57 @@ public class SystemMenuService {
}
/**
* 编辑
* 根据组件名称查询菜单是否存在 -> TestPassed
*
* @param componentName 组件名称
* @return /
*/
private boolean existMenuWithComponentName(String componentName) {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemMenuTb::getComponentName, componentName);
return systemMenuMapper.exists(wrapper);
}
/**
* 根据组件名称查询菜单是否存在 -> TestPassed
*
* @param componentName 组件名称
* @return /
*/
private boolean existMenuWithComponentNameNeSelf(String componentName, Long currentMenuId) {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemMenuTb::getComponentName, componentName);
wrapper.ne(SystemMenuTb::getId, currentMenuId);
return systemMenuMapper.exists(wrapper);
}
/**
* 根据菜单标题查询菜单是否存在 -> TestPassed
*
* @param title 菜单标题
* @return /
*/
private boolean existMenuWithTitle(String title) {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemMenuTb::getTitle, title);
return systemMenuMapper.exists(wrapper);
}
/**
* 根据菜单标题查询菜单是否存在 -> TestPassed
*
* @param title 菜单标题
* @return /
*/
private boolean existMenuWithTitleNeSelf(String title, Long currentMenuId) {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemMenuTb::getTitle, title);
wrapper.ne(SystemMenuTb::getId, currentMenuId);
return systemMenuMapper.exists(wrapper);
}
/**
* 编辑 -> TestPassed
*
* @param args /
*/
@@ -108,8 +162,7 @@ public class SystemMenuService {
throw new BadRequestException(SystemTransferProtocolConst.PREFIX_HTTPS_BAD_REQUEST);
}
}
SystemMenuTb menu1 = this.getMenuByTitle(args.getTitle());
if (menu1 != null && !menu1.getId().equals(menu.getId())) {
if (this.existMenuWithTitleNeSelf(args.getTitle(), menu.getId())) {
throw new BadRequestException("菜单标题已存在");
}
if (args.getPid().equals(0L)) {
@@ -119,8 +172,7 @@ public class SystemMenuService {
Long oldPid = menu.getPid();
Long newPid = args.getPid();
if (StrUtil.isNotBlank(args.getComponentName())) {
menu1 = this.getMenuByComponentName(args.getComponentName());
if (menu1 != null && !menu1.getId().equals(menu.getId())) {
if (this.existMenuWithComponentNameNeSelf(args.getTitle(), menu.getId())) {
throw new BadRequestException("菜单组件名称已存在");
}
}
@@ -139,36 +191,103 @@ public class SystemMenuService {
// auto fill
menu.setUpdateBy(null);
menu.setUpdateTime(null);
systemMenuMapper.insertOrUpdate(menu);
systemMenuMapper.updateById(menu);
// 计算父级菜单节点数目
this.updateMenuSubCnt(oldPid);
this.updateMenuSubCnt(newPid);
}
/**
* 删除
* 删除 -> TestPassed
*/
@Transactional(rollbackFor = Exception.class)
public void deleteMenuByIds(Set<Long> ids) {
Set<SystemMenuVo> menuSet = new HashSet<>();
for (Long id : ids) {
List<SystemMenuVo> menuList = this.listMenuByPid(id);
menuSet.add(this.getMenuVoById(id));
menuSet = this.queryChildMenuByArgs(menuList, menuSet);
// Set<SystemMenuVo> menuSet = new HashSet<>();
// for (Long id : ids) {
// List<SystemMenuVo> menuList = this.listMenuByPid(id);
// menuSet.add(this.getMenuVoById(id));
// menuSet = this.queryChildMenuByArgs(menuList, menuSet);
// }
// List<Long> menuIds = menuSet.stream().map(SystemMenuVo::getId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
// if (CollUtil.isNotEmpty(menuIds)) {
// systemRoleMenuService.deleteRoleMenuByMenuIds(menuIds);
// systemMenuMapper.deleteByIds(menuIds);
// }
// for (SystemMenuVo menu : menuSet) {
// this.updateMenuSubCnt(menu.getPid());
// }
// ========= 优化 20260114 =========
if (CollUtil.isEmpty(ids)) {
return;
}
List<Long> menuIds =
menuSet.stream().map(SystemMenuVo::getId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
if (CollUtil.isNotEmpty(menuIds)) {
systemRoleMenuService.deleteRoleMenuByMenuIds(menuIds);
systemMenuMapper.deleteByIds(menuIds);
}
for (SystemMenuVo menu : menuSet) {
this.updateMenuSubCnt(menu.getPid());
// 查询所有菜单数据
List<SystemMenuTb> allMenus = systemMenuMapper.listAll();
// 根据ID集合获取当前菜单和其子菜单
Set<Long> allMenuIds = this.getAllMenuIdsWithChildren(ids, allMenus);
if (CollUtil.isNotEmpty(allMenuIds)) {
// 删除角色菜单关联
systemRoleMenuService.deleteRoleMenuByMenuIds(allMenuIds);
// 批量删除菜单
systemMenuMapper.deleteByIds(allMenuIds);
// 更新父级菜单子节点数量
this.updateParentMenuCounts(allMenuIds, allMenus);
}
}
private SystemMenuVo getMenuVoById(Long id) {
return KitBeanUtil.copyToClass(systemMenuMapper.selectById(id), SystemMenuVo.class);
/**
* 从所有菜单中找出指定ID及其子菜单ID
*
* @param rootIds 要删除的根菜单ID集合
* @param allMenus 所有菜单数据
* @return 包含根菜单及其所有子菜单的ID集合
*/
private Set<Long> getAllMenuIdsWithChildren(Set<Long> rootIds, List<SystemMenuTb> allMenus) {
Set<Long> result = new HashSet<>(rootIds);
Set<Long> currentLevelIds = new HashSet<>(rootIds);
// 构建父ID到子菜单的映射
Map<Long, List<SystemMenuTb>> parentToChildrenMap = allMenus.stream()
.filter(menu -> menu.getPid() != null)
.collect(Collectors.groupingBy(SystemMenuTb::getPid));
while (!currentLevelIds.isEmpty()) {
Set<Long> nextLevelIds = new HashSet<>();
// 对于当前层级的每个菜单ID,查找其子菜单
for (Long parentId : currentLevelIds) {
List<SystemMenuTb> children = parentToChildrenMap.get(parentId);
if (children != null && !children.isEmpty()) {
for (SystemMenuTb child : children) {
if (result.add(child.getId())) { // 如果成功添加(之前不存在),则继续查找其子菜单
nextLevelIds.add(child.getId());
}
}
}
}
currentLevelIds = nextLevelIds;
}
return result;
}
/**
* 更新被删除菜单的父菜单子节点计数
*/
private void updateParentMenuCounts(Set<Long> deletedMenuIds, List<SystemMenuTb> allMenus) {
// 获取被删除菜单的父ID
Set<Long> parentIds = allMenus.stream()
.filter(menu -> deletedMenuIds.contains(menu.getId()) && menu.getPid() != null)
.map(SystemMenuTb::getPid)
.collect(Collectors.toSet());
// 更新每个父菜单的子节点计数
for (Long parentId : parentIds) {
proxyService.updateMenuSubCnt(parentId);
}
}
/**
* 根据菜单id查询目录 -> TestPassed
*
* @param id 菜单id
*/
private SystemMenuTb getMenuById(Long id) {
return systemMenuMapper.selectById(id);
}
@Transactional(rollbackFor = Exception.class)
@@ -230,10 +349,10 @@ public class SystemMenuService {
* @param menuSet /
* @return /
*/
public Set<SystemMenuVo> queryChildMenuByArgs(List<SystemMenuVo> menuList, Set<SystemMenuVo> menuSet) {
for (SystemMenuVo menu : menuList) {
public Set<SystemMenuTb> queryChildMenuByArgs(List<SystemMenuTb> menuList, Set<SystemMenuTb> menuSet) {
for (SystemMenuTb menu : menuList) {
menuSet.add(menu);
List<SystemMenuVo> menus = this.listMenuByPid(menu.getId());
List<SystemMenuTb> menus = this.listMenuByPid(menu.getId());
if (CollUtil.isNotEmpty(menus)) {
queryChildMenuByArgs(menus, menuSet);
}
@@ -247,13 +366,13 @@ public class SystemMenuService {
* @param pid /
* @return /
*/
public List<SystemMenuVo> listMenuByPid(Long pid) {
List<SystemMenuVo> menus;
public List<SystemMenuTb> listMenuByPid(Long pid) {
List<SystemMenuTb> menus;
if (pid != null && !pid.equals(0L)) {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemMenuTb::getPid, pid);
wrapper.orderByAsc(SystemMenuTb::getMenuSort);
return KitBeanUtil.copyToList(systemMenuMapper.selectList(wrapper), SystemMenuVo.class);
return systemMenuMapper.selectList(wrapper);
} else {
menus = this.listRootMenu();
}
@@ -261,19 +380,19 @@ public class SystemMenuService {
}
/**
* 根据ID查询同级与上级数据
* 根据ID查询同级与上级数据 -> TestPassed
*
* @param menu /
* @param menus /
* @return /
*/
public List<SystemMenuVo> querySuperiorMenuByArgs(SystemMenuVo menu, List<SystemMenuVo> menus) {
public List<SystemMenuTb> querySuperiorMenuByArgs(SystemMenuTb menu, List<SystemMenuTb> menus) {
if (menu.getPid() == null) {
menus.addAll(this.listRootMenu());
return menus;
}
menus.addAll(this.listMenuByPid(menu.getPid()));
return querySuperiorMenuByArgs(this.getMenuVoById(menu.getPid()), menus);
return querySuperiorMenuByArgs(this.getMenuById(menu.getPid()), menus);
}
/**
@@ -375,20 +494,8 @@ public class SystemMenuService {
return menuVo1;
}
public List<SystemMenuVo> listMenuByIds(List<Long> ids) {
return KitBeanUtil.copyToList(systemMenuMapper.selectByIds(ids), SystemMenuVo.class);
}
private SystemMenuTb getMenuByComponentName(String componentName) {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemMenuTb::getComponentName, componentName);
return systemMenuMapper.selectOne(wrapper);
}
private SystemMenuTb getMenuByTitle(String title) {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemMenuTb::getTitle, title);
return systemMenuMapper.selectOne(wrapper);
public List<SystemMenuTb> listMenuByIds(List<Long> ids) {
return systemMenuMapper.selectByIds(ids);
}
private Long countMenuByPid(Long pid) {
@@ -412,11 +519,14 @@ public class SystemMenuService {
return systemMenuMapper.selectList(wrapper);
}
private List<SystemMenuVo> listRootMenu() {
/**
* 查询根目录 -> TestPassed
*/
private List<SystemMenuTb> listRootMenu() {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.isNull(SystemMenuTb::getPid);
wrapper.orderByAsc(SystemMenuTb::getMenuSort);
return KitBeanUtil.copyToList(systemMenuMapper.selectList(wrapper), SystemMenuVo.class);
return systemMenuMapper.selectList(wrapper);
}
public List<SystemMenuRouterVo> buildFrontMenus() {
@@ -426,19 +536,19 @@ public class SystemMenuService {
}
public Set<Long> listChildMenuSetByMenuId(Long id) {
Set<SystemMenuVo> menuSet = new HashSet<>();
List<SystemMenuVo> menuList = this.listMenuByPid(id);
menuSet.add(this.getMenuVoById(id));
Set<SystemMenuTb> menuSet = new HashSet<>();
List<SystemMenuTb> menuList = this.listMenuByPid(id);
menuSet.add(this.getMenuById(id));
menuSet = this.queryChildMenuByArgs(menuList, menuSet);
return menuSet.stream().map(SystemMenuVo::getId).collect(Collectors.toSet());
}
public List<SystemMenuVo> listMenuSuperior(List<Long> ids) {
Set<SystemMenuVo> menus;
Set<SystemMenuTb> menus;
List<SystemMenuVo> systemMenuTbs;
if (CollUtil.isNotEmpty(ids)) {
menus = new LinkedHashSet<>(this.listMenuByIds(ids));
for (SystemMenuVo menu : menus) {
for (SystemMenuTb menu : menus) {
List<SystemMenuVo> menuList = this.querySuperiorMenuByArgs(menu, new ArrayList<>());
for (SystemMenuVo data : menuList) {
if (data.getId().equals(menu.getPid())) {
@@ -115,7 +115,7 @@ public class SystemRoleMenuService {
* @param menuIds 菜单id集合
*/
@Transactional(rollbackFor = Exception.class)
public void deleteRoleMenuByMenuIds(List<Long> menuIds) {
public void deleteRoleMenuByMenuIds(Set<Long> menuIds) {
if (CollUtil.isEmpty(menuIds)) {
return;
}