refactor(menu): 重构菜单服务提升性能和代码质量
- 将控制器返回类型从SystemMenuVo改为SystemMenuTb,避免不必要的对象转换 - 在Mapper层添加listAll默认方法提高数据查询效率 - 移除KitBeanUtil依赖减少代码耦合 - 引入懒加载代理解决循环依赖问题 - 优化菜单创建和编辑逻辑,使用exists方法提升数据库查询性能 - 重写菜单删除逻辑,采用批量操作和层级遍历提升删除效率 - 更新方法签名统一使用SystemMenuTb实体类 - 简化菜单父子关系查询逻辑,提升代码可读性
This commit is contained in:
+2
-2
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+167
-57
@@ -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())) {
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user