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("返回全部的菜单") @ApiOperation("返回全部的菜单")
@PostMapping(value = "/listMenuByPid") @PostMapping(value = "/listMenuByPid")
@PreAuthorize("@el.check('menu:list','roles:list')") @PreAuthorize("@el.check('menu:list','roles:list')")
public ResponseEntity<List<SystemMenuVo>> listMenuByPid(@RequestParam Long pid) { public ResponseEntity<List<SystemMenuTb>> listMenuByPid(@RequestParam Long pid) {
List<SystemMenuVo> systemMenuTbs = systemMenuService.listMenuByPid(pid); List<SystemMenuTb> systemMenuTbs = systemMenuService.listMenuByPid(pid);
return ResponseEntity.ok(systemMenuTbs); return ResponseEntity.ok(systemMenuTbs);
} }
@@ -17,6 +17,7 @@ package cn.odboy.system.dal.mysql;
import cn.odboy.system.dal.dataobject.SystemMenuTb; import cn.odboy.system.dal.dataobject.SystemMenuTb;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
/** /**
@@ -27,4 +28,7 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface SystemMenuMapper extends BaseMapper<SystemMenuTb> { 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.model.response.SystemRoleVo;
import cn.odboy.system.dal.mysql.SystemMenuMapper; import cn.odboy.system.dal.mysql.SystemMenuMapper;
import cn.odboy.system.framework.permission.core.KitSecurityHelper; import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.util.KitBeanUtil;
import cn.odboy.util.KitClassUtil; import cn.odboy.util.KitClassUtil;
import cn.odboy.util.KitValidUtil; import cn.odboy.util.KitValidUtil;
import cn.odboy.util.xlsx.KitExcelExporter; import cn.odboy.util.xlsx.KitExcelExporter;
@@ -42,11 +41,12 @@ import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -59,23 +59,27 @@ public class SystemMenuService {
private SystemRoleMenuService systemRoleMenuService; private SystemRoleMenuService systemRoleMenuService;
@Autowired @Autowired
private SystemUserRoleService systemUserRoleService; private SystemUserRoleService systemUserRoleService;
@Lazy
@Autowired
private SystemMenuService proxyService;
/** /**
* 创建 * 创建 -> TestPassed
* *
* @param args / * @param args /
*/ */
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void saveMenu(SystemMenuTb args) { public void saveMenu(SystemMenuTb args) {
if (this.getMenuByTitle(args.getTitle()) != null) { if (this.existMenuWithTitle(args.getTitle())) {
throw new BadRequestException("菜单标题已存在"); throw new BadRequestException("菜单标题已存在");
} }
if (StrUtil.isNotBlank(args.getComponentName())) { if (StrUtil.isNotBlank(args.getComponentName())) {
if (this.getMenuByComponentName(args.getComponentName()) != null) { if (this.existMenuWithComponentName(args.getComponentName())) {
throw new BadRequestException("菜单组件名称已存在"); throw new BadRequestException("菜单组件名称已存在");
} }
} }
if (Long.valueOf(0L).equals(args.getPid())) { if (Long.valueOf(0L).equals(args.getPid())) {
// 顶级目录
args.setPid(null); args.setPid(null);
} }
if (args.getIFrame()) { 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 / * @param args /
*/ */
@@ -108,8 +162,7 @@ public class SystemMenuService {
throw new BadRequestException(SystemTransferProtocolConst.PREFIX_HTTPS_BAD_REQUEST); throw new BadRequestException(SystemTransferProtocolConst.PREFIX_HTTPS_BAD_REQUEST);
} }
} }
SystemMenuTb menu1 = this.getMenuByTitle(args.getTitle()); if (this.existMenuWithTitleNeSelf(args.getTitle(), menu.getId())) {
if (menu1 != null && !menu1.getId().equals(menu.getId())) {
throw new BadRequestException("菜单标题已存在"); throw new BadRequestException("菜单标题已存在");
} }
if (args.getPid().equals(0L)) { if (args.getPid().equals(0L)) {
@@ -119,8 +172,7 @@ public class SystemMenuService {
Long oldPid = menu.getPid(); Long oldPid = menu.getPid();
Long newPid = args.getPid(); Long newPid = args.getPid();
if (StrUtil.isNotBlank(args.getComponentName())) { if (StrUtil.isNotBlank(args.getComponentName())) {
menu1 = this.getMenuByComponentName(args.getComponentName()); if (this.existMenuWithComponentNameNeSelf(args.getTitle(), menu.getId())) {
if (menu1 != null && !menu1.getId().equals(menu.getId())) {
throw new BadRequestException("菜单组件名称已存在"); throw new BadRequestException("菜单组件名称已存在");
} }
} }
@@ -139,36 +191,103 @@ public class SystemMenuService {
// auto fill // auto fill
menu.setUpdateBy(null); menu.setUpdateBy(null);
menu.setUpdateTime(null); menu.setUpdateTime(null);
systemMenuMapper.insertOrUpdate(menu); systemMenuMapper.updateById(menu);
// 计算父级菜单节点数目 // 计算父级菜单节点数目
this.updateMenuSubCnt(oldPid); this.updateMenuSubCnt(oldPid);
this.updateMenuSubCnt(newPid); this.updateMenuSubCnt(newPid);
} }
/** /**
* 删除 * 删除 -> TestPassed
*/ */
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deleteMenuByIds(Set<Long> ids) { public void deleteMenuByIds(Set<Long> ids) {
Set<SystemMenuVo> menuSet = new HashSet<>(); // Set<SystemMenuVo> menuSet = new HashSet<>();
for (Long id : ids) { // for (Long id : ids) {
List<SystemMenuVo> menuList = this.listMenuByPid(id); // List<SystemMenuVo> menuList = this.listMenuByPid(id);
menuSet.add(this.getMenuVoById(id)); // menuSet.add(this.getMenuVoById(id));
menuSet = this.queryChildMenuByArgs(menuList, menuSet); // 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()); List<SystemMenuTb> allMenus = systemMenuMapper.listAll();
if (CollUtil.isNotEmpty(menuIds)) { // 根据ID集合获取当前菜单和其子菜单
systemRoleMenuService.deleteRoleMenuByMenuIds(menuIds); Set<Long> allMenuIds = this.getAllMenuIdsWithChildren(ids, allMenus);
systemMenuMapper.deleteByIds(menuIds); if (CollUtil.isNotEmpty(allMenuIds)) {
} // 删除角色菜单关联
for (SystemMenuVo menu : menuSet) { systemRoleMenuService.deleteRoleMenuByMenuIds(allMenuIds);
this.updateMenuSubCnt(menu.getPid()); // 批量删除菜单
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) @Transactional(rollbackFor = Exception.class)
@@ -230,10 +349,10 @@ public class SystemMenuService {
* @param menuSet / * @param menuSet /
* @return / * @return /
*/ */
public Set<SystemMenuVo> queryChildMenuByArgs(List<SystemMenuVo> menuList, Set<SystemMenuVo> menuSet) { public Set<SystemMenuTb> queryChildMenuByArgs(List<SystemMenuTb> menuList, Set<SystemMenuTb> menuSet) {
for (SystemMenuVo menu : menuList) { for (SystemMenuTb menu : menuList) {
menuSet.add(menu); menuSet.add(menu);
List<SystemMenuVo> menus = this.listMenuByPid(menu.getId()); List<SystemMenuTb> menus = this.listMenuByPid(menu.getId());
if (CollUtil.isNotEmpty(menus)) { if (CollUtil.isNotEmpty(menus)) {
queryChildMenuByArgs(menus, menuSet); queryChildMenuByArgs(menus, menuSet);
} }
@@ -247,13 +366,13 @@ public class SystemMenuService {
* @param pid / * @param pid /
* @return / * @return /
*/ */
public List<SystemMenuVo> listMenuByPid(Long pid) { public List<SystemMenuTb> listMenuByPid(Long pid) {
List<SystemMenuVo> menus; List<SystemMenuTb> menus;
if (pid != null && !pid.equals(0L)) { if (pid != null && !pid.equals(0L)) {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemMenuTb::getPid, pid); wrapper.eq(SystemMenuTb::getPid, pid);
wrapper.orderByAsc(SystemMenuTb::getMenuSort); wrapper.orderByAsc(SystemMenuTb::getMenuSort);
return KitBeanUtil.copyToList(systemMenuMapper.selectList(wrapper), SystemMenuVo.class); return systemMenuMapper.selectList(wrapper);
} else { } else {
menus = this.listRootMenu(); menus = this.listRootMenu();
} }
@@ -261,19 +380,19 @@ public class SystemMenuService {
} }
/** /**
* 根据ID查询同级与上级数据 * 根据ID查询同级与上级数据 -> TestPassed
* *
* @param menu / * @param menu /
* @param menus / * @param menus /
* @return / * @return /
*/ */
public List<SystemMenuVo> querySuperiorMenuByArgs(SystemMenuVo menu, List<SystemMenuVo> menus) { public List<SystemMenuTb> querySuperiorMenuByArgs(SystemMenuTb menu, List<SystemMenuTb> menus) {
if (menu.getPid() == null) { if (menu.getPid() == null) {
menus.addAll(this.listRootMenu()); menus.addAll(this.listRootMenu());
return menus; return menus;
} }
menus.addAll(this.listMenuByPid(menu.getPid())); 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; return menuVo1;
} }
public List<SystemMenuVo> listMenuByIds(List<Long> ids) { public List<SystemMenuTb> listMenuByIds(List<Long> ids) {
return KitBeanUtil.copyToList(systemMenuMapper.selectByIds(ids), SystemMenuVo.class); return systemMenuMapper.selectByIds(ids);
}
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);
} }
private Long countMenuByPid(Long pid) { private Long countMenuByPid(Long pid) {
@@ -412,11 +519,14 @@ public class SystemMenuService {
return systemMenuMapper.selectList(wrapper); return systemMenuMapper.selectList(wrapper);
} }
private List<SystemMenuVo> listRootMenu() { /**
* 查询根目录 -> TestPassed
*/
private List<SystemMenuTb> listRootMenu() {
LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SystemMenuTb> wrapper = new LambdaQueryWrapper<>();
wrapper.isNull(SystemMenuTb::getPid); wrapper.isNull(SystemMenuTb::getPid);
wrapper.orderByAsc(SystemMenuTb::getMenuSort); wrapper.orderByAsc(SystemMenuTb::getMenuSort);
return KitBeanUtil.copyToList(systemMenuMapper.selectList(wrapper), SystemMenuVo.class); return systemMenuMapper.selectList(wrapper);
} }
public List<SystemMenuRouterVo> buildFrontMenus() { public List<SystemMenuRouterVo> buildFrontMenus() {
@@ -426,19 +536,19 @@ public class SystemMenuService {
} }
public Set<Long> listChildMenuSetByMenuId(Long id) { public Set<Long> listChildMenuSetByMenuId(Long id) {
Set<SystemMenuVo> menuSet = new HashSet<>(); Set<SystemMenuTb> menuSet = new HashSet<>();
List<SystemMenuVo> menuList = this.listMenuByPid(id); List<SystemMenuTb> menuList = this.listMenuByPid(id);
menuSet.add(this.getMenuVoById(id)); menuSet.add(this.getMenuById(id));
menuSet = this.queryChildMenuByArgs(menuList, menuSet); menuSet = this.queryChildMenuByArgs(menuList, menuSet);
return menuSet.stream().map(SystemMenuVo::getId).collect(Collectors.toSet()); return menuSet.stream().map(SystemMenuVo::getId).collect(Collectors.toSet());
} }
public List<SystemMenuVo> listMenuSuperior(List<Long> ids) { public List<SystemMenuVo> listMenuSuperior(List<Long> ids) {
Set<SystemMenuVo> menus; Set<SystemMenuTb> menus;
List<SystemMenuVo> systemMenuTbs; List<SystemMenuVo> systemMenuTbs;
if (CollUtil.isNotEmpty(ids)) { if (CollUtil.isNotEmpty(ids)) {
menus = new LinkedHashSet<>(this.listMenuByIds(ids)); menus = new LinkedHashSet<>(this.listMenuByIds(ids));
for (SystemMenuVo menu : menus) { for (SystemMenuTb menu : menus) {
List<SystemMenuVo> menuList = this.querySuperiorMenuByArgs(menu, new ArrayList<>()); List<SystemMenuVo> menuList = this.querySuperiorMenuByArgs(menu, new ArrayList<>());
for (SystemMenuVo data : menuList) { for (SystemMenuVo data : menuList) {
if (data.getId().equals(menu.getPid())) { if (data.getId().equals(menu.getPid())) {
@@ -115,7 +115,7 @@ public class SystemRoleMenuService {
* @param menuIds 菜单id集合 * @param menuIds 菜单id集合
*/ */
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deleteRoleMenuByMenuIds(List<Long> menuIds) { public void deleteRoleMenuByMenuIds(Set<Long> menuIds) {
if (CollUtil.isEmpty(menuIds)) { if (CollUtil.isEmpty(menuIds)) {
return; return;
} }