创建menu有报错 框架报错

This commit is contained in:
戚辰先生 2024-11-30 09:51:05 +08:00
parent 9fce8ff134
commit 3c449aefa3
12 changed files with 496 additions and 285 deletions

View File

@ -0,0 +1,49 @@
package com.qqchen.deploy.backend.api;
import com.qqchen.deploy.backend.entity.Menu;
import com.qqchen.deploy.backend.entity.Tenant;
import com.qqchen.deploy.backend.framework.api.Response;
import com.qqchen.deploy.backend.framework.controller.BaseController;
import com.qqchen.deploy.backend.model.MenuDTO;
import com.qqchen.deploy.backend.model.TenantDTO;
import com.qqchen.deploy.backend.model.query.MenuQuery;
import com.qqchen.deploy.backend.model.query.TenantQuery;
import com.qqchen.deploy.backend.model.response.MenuResponse;
import com.qqchen.deploy.backend.service.IMenuService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/api/v1/menu")
@Tag(name = "菜单管理API", description = "对外提供的菜单管理接口")
public class MenuApiController extends BaseController<Menu, MenuDTO, Long, MenuQuery> {
@Resource
private IMenuService menuService;
/**
* 获取当前用户的菜单
*/
@Operation(summary = "获取当前用户的菜单")
@GetMapping("/current")
public Response<List<MenuResponse>> getCurrentUserMenus() {
// TODO: SecurityContext 获取当前用户ID
// return Response.success(menuService.getUserMenus(1L));
return null;
}
@Override
protected void exportData(HttpServletResponse response, List<MenuDTO> data) {
}
}

View File

@ -0,0 +1,49 @@
//package com.qqchen.deploy.backend.controller;
//
//import com.qqchen.deploy.backend.entity.Menu;
//import com.qqchen.deploy.backend.framework.api.Response;
//import com.qqchen.deploy.backend.framework.controller.BaseController;
//import com.qqchen.deploy.backend.model.MenuDTO;
//import com.qqchen.deploy.backend.model.query.MenuQuery;
//import com.qqchen.deploy.backend.model.response.MenuResponse;
//import com.qqchen.deploy.backend.service.IMenuService;
//import io.swagger.v3.oas.annotations.Operation;
//import io.swagger.v3.oas.annotations.tags.Tag;
//import jakarta.servlet.http.HttpServletResponse;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.web.bind.annotation.GetMapping;
//import org.springframework.web.bind.annotation.RequestMapping;
//import org.springframework.web.bind.annotation.RestController;
//
//import java.util.List;
//
//@Slf4j
//@RestController
//@RequestMapping("/api/v1/menu")
//@Tag(name = "菜单管理", description = "菜单管理相关接口")
//public class MenuController extends BaseController<Menu, MenuDTO, Long, MenuQuery> {
//
// /**
// * 获取菜单树
// */
// @Operation(summary = "获取菜单树")
// @GetMapping("/tree")
// public Response<List<MenuResponse>> getMenuTree() {
// return Response.success(((IMenuService) service).getMenuTree());
// }
//
// /**
// * 获取当前用户的菜单
// */
// @Operation(summary = "获取当前用户的菜单")
// @GetMapping("/current")
// public Response<List<MenuResponse>> getCurrentUserMenus() {
// // TODO: SecurityContext 获取当前用户ID
// return Response.success(((IMenuService) service).getUserMenus(1L));
// }
//
// @Override
// protected void exportData(HttpServletResponse response, List<MenuDTO> data) {
//
// }
//}

View File

@ -0,0 +1,21 @@
package com.qqchen.deploy.backend.converter;
import com.qqchen.deploy.backend.entity.Menu;
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
import com.qqchen.deploy.backend.model.MenuDTO;
import com.qqchen.deploy.backend.model.request.MenuRequest;
import com.qqchen.deploy.backend.model.response.MenuResponse;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(config = BaseConverter.class)
public interface MenuConverter extends BaseConverter<Menu, MenuDTO> {
MenuDTO requestToDto(MenuRequest request);
MenuResponse toResponse(Menu menu);
List<MenuResponse> toResponseList(List<MenuDTO> dtos);
}

View File

@ -15,29 +15,56 @@ import lombok.EqualsAndHashCode;
@LogicDelete @LogicDelete
public class Menu extends Entity<Long> { public class Menu extends Entity<Long> {
/**
* 菜单名称
*/
@Column(nullable = false) @Column(nullable = false)
private String name; private String name;
private String permission; /**
* 菜单路径
*/
private String path; private String path;
/**
* 前端组件路径
*/
private String component; private String component;
@Column(nullable = false) /**
private Integer type; // 0-目录 1-菜单 2-按钮 * 菜单图标
*/
private String icon; private String icon;
@Column(name = "parent_id") /**
* 权限标识
*/
private String permission;
/**
* 菜单类型1目录 2菜单 3按钮
*/
@Column(nullable = false)
private Integer type;
/**
* 父级菜单ID
*/
private Long parentId; private Long parentId;
/**
* 显示顺序
*/
@Column(nullable = false) @Column(nullable = false)
private Integer sort = 0; private Integer sort;
private Boolean hidden = false; /**
* 是否隐藏true隐藏 false显示
@Column(nullable = false) */
private Boolean enabled = true; private Boolean hidden;
/**
* 是否启用true启用 false禁用
*/
private Boolean enabled;
} }

View File

@ -0,0 +1,64 @@
package com.qqchen.deploy.backend.model;
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
import lombok.Data;
import java.util.List;
@Data
public class MenuDTO extends BaseDTO {
/**
* 菜单名称
*/
private String name;
/**
* 菜单路径
*/
private String path;
/**
* 前端组件路径
*/
private String component;
/**
* 菜单图标
*/
private String icon;
/**
* 权限标识
*/
private String permission;
/**
* 菜单类型1目录 2菜单 3按钮
*/
private Integer type;
/**
* 父级菜单ID
*/
private Long parentId;
/**
* 显示顺序
*/
private Integer sort;
/**
* 是否隐藏true隐藏 false显示
*/
private Boolean hidden;
/**
* 是否启用true启用 false禁用
*/
private Boolean enabled;
/**
* 子菜单列表
*/
private List<MenuDTO> children;
}

View File

@ -0,0 +1,27 @@
package com.qqchen.deploy.backend.model.query;
import com.qqchen.deploy.backend.framework.query.BaseQuery;
import lombok.Data;
@Data
public class MenuQuery extends BaseQuery {
/**
* 菜单名称
*/
private String name;
/**
* 菜单路径
*/
private String path;
/**
* 菜单类型
*/
private Integer type;
/**
* 是否启用
*/
private Boolean enabled;
}

View File

@ -0,0 +1,61 @@
package com.qqchen.deploy.backend.model.request;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class MenuRequest {
/**
* 菜单名称
*/
@NotBlank(message = "菜单名称不能为空")
private String name;
/**
* 菜单路径
*/
private String path;
/**
* 前端组件路径
*/
private String component;
/**
* 菜单图标
*/
private String icon;
/**
* 权限标识
*/
private String permission;
/**
* 菜单类型1目录 2菜单 3按钮
*/
@NotNull(message = "菜单类型不能为空")
private Integer type;
/**
* 父级菜单ID
*/
private Long parentId;
/**
* 显示顺序
*/
@NotNull(message = "显示顺序不能为空")
private Integer sort;
/**
* 是否隐藏true隐藏 false显示
*/
private Boolean hidden;
/**
* 是否启用true启用 false禁用<EFBFBD><EFBFBD><EFBFBD>
*/
private Boolean enabled;
}

View File

@ -0,0 +1,89 @@
package com.qqchen.deploy.backend.model.response;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class MenuResponse {
/**
* 菜单ID
*/
private Long id;
/**
* 菜单名称
*/
private String name;
/**
* 菜单路径
*/
private String path;
/**
* 前端组件路径
*/
private String component;
/**
* 菜单图标
*/
private String icon;
/**
* 权限标识
*/
private String permission;
/**
* 菜单类型1目录 2菜单 3按钮
*/
private Integer type;
/**
* 父级菜单ID
*/
private Long parentId;
/**
* 显示顺序
*/
private Integer sort;
/**
* 是否隐藏true隐藏 false显示
*/
private Boolean hidden;
/**
* 是否启用true启用 false禁用
*/
private Boolean enabled;
/**
* 子菜单列表
*/
private List<MenuResponse> children;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
/**
* 创建人
*/
private String createBy;
/**
* 更新人
*/
private String updateBy;
}

View File

@ -1,13 +1,14 @@
package com.qqchen.deploy.backend.repository; package com.qqchen.deploy.backend.repository;
import com.qqchen.deploy.backend.entity.Menu; import com.qqchen.deploy.backend.entity.Menu;
import com.qqchen.deploy.backend.entity.User;
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
@Repository @Repository
public interface IMenuRepository extends JpaRepository<Menu, Long> { public interface IMenuRepository extends JpaRepository<Menu, Long> {
List<Menu> findByDeletedFalseOrderBySort(); List<Menu> findByDeletedFalseOrderBySort();
List<Menu> findByParentIdAndDeletedFalseOrderBySort(Long parentId); List<Menu> findByParentIdAndDeletedFalseOrderBySort(Long parentId);
@ -23,4 +24,6 @@ public interface IMenuRepository extends JpaRepository<Menu, Long> {
List<Menu> findByParentIdAndDeletedFalse(Long parentId); List<Menu> findByParentIdAndDeletedFalse(Long parentId);
List<Menu> findByTypeInAndDeletedFalseOrderBySort(List<Integer> types); List<Menu> findByTypeInAndDeletedFalseOrderBySort(List<Integer> types);
List<Menu> findByEnabledAndDeletedFalseOrderBySort(Boolean enabled);
} }

View File

@ -1,20 +1,27 @@
//package com.qqchen.deploy.backend.service; package com.qqchen.deploy.backend.service;
import com.qqchen.deploy.backend.entity.User;
import com.qqchen.deploy.backend.framework.service.IBaseService;
import com.qqchen.deploy.backend.entity.Menu;
import com.qqchen.deploy.backend.model.MenuDTO;
import com.qqchen.deploy.backend.model.UserDTO;
import com.qqchen.deploy.backend.model.request.MenuRequest;
import com.qqchen.deploy.backend.model.response.MenuResponse;
import java.util.List;
public interface IMenuService extends IBaseService<Menu, MenuDTO, Long> {
// /**
// * 获取菜单树
// * @return 菜单树
// */
// List<MenuResponse> getMenuTree();
// //
// // /**
//import com.qqchen.deploy.backend.framework.service.IBaseService; // * 获取用户菜单
//import com.qqchen.deploy.backend.entity.Menu; // * @param userId 用户ID
// // * @return 用户菜单
//import java.util.List; // */
// // List<MenuResponse> getUserMenus(Long userId);
//public interface IMenuService extends IBaseService<Menu, Long> { }
//
//// List<MenuDTO> getMenuTree();
//
//// List<MenuDTO> getMenuTreeWithoutButtons();
//
//// List<MenuDTO> getUserMenus(Long userId);
//
// List<Menu> getMenusByRoleId(Long roleId);
//
// void saveRoleMenus(Long roleId, List<Long> menuIds);
//}

View File

@ -1,254 +0,0 @@
//package com.qqchen.deploy.backend.service.impl;
//
//import com.qqchen.application.dto.MenuDTO;
//import com.qqchen.application.query.MenuQuery;
//import com.qqchen.application.service.MenuService;
//import com.qqchen.common.exception.ApiException;
//import com.qqchen.common.service.impl.BaseServiceImpl;
//import com.qqchen.domain.entity.Menu;
//import com.qqchen.domain.entity.RoleMenu;
//import com.qqchen.domain.repository.MenuRepository;
//import com.qqchen.domain.repository.RoleMenuRepository;
//import lombok.RequiredArgsConstructor;
//import org.springframework.beans.BeanUtils;
//import org.springframework.data.jpa.repository.JpaRepository;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.util.ArrayList;
//import java.util.Arrays;
//import java.util.Comparator;
//import java.util.List;
//import java.util.stream.Collectors;
//
//@Service
//@RequiredArgsConstructor
//public class IMenuServiceImpl extends BaseServiceImpl<Menu, MenuQuery> implements MenuService {
//
// private final MenuRepository menuRepository;
// private final RoleMenuRepository roleMenuRepository;
//
// @Override
// protected JpaRepository<Menu, Long> getRepository() {
// return menuRepository;
// }
//
// @Override
// public List<MenuDTO> getMenuTree() {
// List<Menu> menus = menuRepository.findByDeletedFalseOrderBySort();
// return buildMenuTree(menus);
// }
//
// @Override
// public List<MenuDTO> getUserMenus(Long userId) {
// // TODO: 根据用户ID获取角色然后获取菜单
// return new ArrayList<>();
// }
//
// @Override
// public List<Menu> getMenusByRoleId(Long roleId) {
// List<RoleMenu> roleMenus = roleMenuRepository.findByRoleId(roleId);
// return roleMenus.stream()
// .map(rm -> menuRepository.findById(rm.getMenuId())
// .orElseThrow(() -> new ApiException("菜单不存在")))
// .collect(Collectors.toList());
// }
//
// @Override
// @Transactional
// public void saveRoleMenus(Long roleId, List<Long> menuIds) {
// // 先删除原有的关联
// roleMenuRepository.deleteByRoleId(roleId);
//
// // 保存新的关联
// List<RoleMenu> roleMenus = menuIds.stream()
// .map(menuId -> {
// RoleMenu rm = new RoleMenu();
// rm.setRoleId(roleId);
// rm.setMenuId(menuId);
// return rm;
// })
// .collect(Collectors.toList());
//
// roleMenuRepository.saveAll(roleMenus);
// }
//
// @Override
// @Transactional
// public Menu update(Long id, Menu menu) {
// Menu existing = findById(id)
// .orElseThrow(() -> new ApiException("菜单不存在"));
//
// // 设置不允许修改的字段
// menu.setId(id);
// menu.setVersion(existing.getVersion());
// menu.setDeleted(existing.getDeleted());
//
// // 如果是按钮类型清空路径和组件
// if (menu.getType() == 2) {
// menu.setPath(null);
// menu.setComponent(null);
// menu.setIcon(null);
// }
//
// // 如果是目录设置固定组件
// if (menu.getType() == 0) {
// menu.setComponent("LAYOUT");
// }
//
// // 如果没有父级菜单设置为根节点
// if (menu.getParentId() == null) {
// menu.setParentId(0L);
// }
//
// return menuRepository.save(menu);
// }
//
// @Override
// @Transactional
// public Menu save(Menu menu) {
// // 如果是按钮类型清空路径和组件
// if (menu.getType() == 2) {
// menu.setPath(null);
// menu.setComponent(null);
// menu.setIcon(null);
// }
//
// // 如果是目录设置固定组件
// if (menu.getType() == 0) {
// menu.setComponent("LAYOUT");
// }
//
// // 如果没有父级菜单设置为根节点
// if (menu.getParentId() == null) {
// menu.setParentId(0L);
// }
//
// menu.setDeleted(false);
// Menu savedMenu = menuRepository.save(menu);
//
// // 如果是菜单类型自动创建增删改查按钮
// if (menu.getType() == 1) {
// createDefaultButtons(savedMenu);
// }
//
// return savedMenu;
// }
//
// /**
// * 创建默认的按钮权限
// */
// private void createDefaultButtons(Menu menu) {
// // 获取基础权限标识
// String basePermission = getBasePermission(menu.getPath());
//
// // 创建默认按钮列表
// List<Menu> buttons = List.of(
// createButton(menu.getName() + "查看", basePermission + ":view", menu.getId(), 1),
// createButton(menu.getName() + "新增", basePermission + ":add", menu.getId(), 2),
// createButton(menu.getName() + "修改", basePermission + ":edit", menu.getId(), 3),
// createButton(menu.getName() + "删除", basePermission + ":delete", menu.getId(), 4)
// );
//
// menuRepository.saveAll(buttons);
// }
//
// /**
// * 创建按钮
// */
// private Menu createButton(String name, String permission, Long parentId, int sort) {
// Menu button = new Menu();
// button.setName(name);
// button.setPermission(permission);
// button.setType(2);
// button.setParentId(parentId);
// button.setSort(sort);
// button.setEnabled(true);
// button.setDeleted(false);
// return button;
// }
//
// /**
// * 根据路径获取基础权限标识
// * 例如/system/user -> system:user
// */
// private String getBasePermission(String path) {
// if (path == null) {
// return "";
// }
// // 移除开头的斜杠
// if (path.startsWith("/")) {
// path = path.substring(1);
// }
// // 将斜杠替换为冒号
// return path.replace("/", ":");
// }
//
// @Override
// @Transactional
// public void delete(Long id) {
// Menu menu = findById(id)
// .orElseThrow(() -> new ApiException("菜单不存在"));
//
// // 如果是菜单类型同时删除其下的按钮
// if (menu.getType() == 1) {
// List<Menu> buttons = menuRepository.findByParentIdAndDeletedFalse(id);
// if (!buttons.isEmpty()) {
// for (Menu button : buttons) {
// button.setDeleted(true);
// menuRepository.save(button);
// }
// }
// }
//
// // 检查是否有子菜单
// List<Menu> children = menuRepository.findByParentIdAndDeletedFalse(id);
// if (!children.isEmpty()) {
// throw new ApiException("该菜单下还有子菜单,不能删除");
// }
//
// menu.setDeleted(true);
// menuRepository.save(menu);
// }
//
// private List<MenuDTO> buildMenuTree(List<Menu> menus) {
// // 先找出所有的根节点parentId为null或0的节点
// List<Menu> rootMenus = menus.stream()
// .filter(menu -> menu.getParentId() == null || menu.getParentId() == 0)
// .collect(Collectors.toList());
//
// // 构建子树
// return rootMenus.stream()
// .map(menu -> buildMenuNode(menu, menus))
// .collect(Collectors.toList());
// }
//
// /**
// * 构建菜单节点
// */
// private MenuDTO buildMenuNode(Menu menu, List<Menu> allMenus) {
// MenuDTO dto = new MenuDTO();
// BeanUtils.copyProperties(menu, dto);
//
// // 查找当前节点的子节点
// List<Menu> children = allMenus.stream()
// .filter(m -> menu.getId().equals(m.getParentId()))
// .sorted(Comparator.comparing(Menu::getSort))
// .collect(Collectors.toList());
//
// if (!children.isEmpty()) {
// dto.setChildren(children.stream()
// .map(child -> buildMenuNode(child, allMenus))
// .collect(Collectors.toList()));
// }
//
// return dto;
// }
//
// @Override
// public List<MenuDTO> getMenuTreeWithoutButtons() {
// // 获取所有非按钮类型的菜单
// List<Menu> menus = menuRepository.findByTypeInAndDeletedFalseOrderBySort(Arrays.asList(0, 1)); // 0-目录 1-菜单
// return buildMenuTree(menus);
// }
//}

View File

@ -0,0 +1,68 @@
package com.qqchen.deploy.backend.service.impl;
import com.qqchen.deploy.backend.converter.MenuConverter;
import com.qqchen.deploy.backend.entity.Menu;
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.model.MenuDTO;
import com.qqchen.deploy.backend.model.response.MenuResponse;
import com.qqchen.deploy.backend.repository.IMenuRepository;
import com.qqchen.deploy.backend.service.IMenuService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.stream.Collectors;
import static com.qqchen.deploy.backend.framework.annotation.ServiceType.Type.DATABASE;
@Slf4j
@Service
@ServiceType(DATABASE)
public class MenuServiceImpl extends BaseServiceImpl<Menu, MenuDTO, Long> implements IMenuService {
@Resource
private IMenuRepository repository;
@Resource
private MenuConverter converter;
// @Override
// public List<MenuResponse> getMenuTree() {
// List<Menu> allMenus = repository.findByDeletedFalseOrderBySort();
// List<MenuDTO> menuDTOs = converter.toDtoList(allMenus);
// List<MenuDTO> menuTree = buildMenuTree(menuDTOs);
// return converter.toResponseList(menuTree);
// }
//
// @Override
// public List<MenuResponse> getUserMenus(Long userId) {
// // TODO: 根据用户角色获取菜单
// return getMenuTree();
// }
//
// private List<MenuDTO> buildMenuTree(List<MenuDTO> menus) {
// Map<Long, MenuDTO> menuMap = menus.stream()
// .collect(Collectors.toMap(MenuDTO::getId, menu -> menu));
//
// List<MenuDTO> rootMenus = new ArrayList<>();
//
// for (MenuDTO menu : menus) {
// if (menu.getParentId() == null || menu.getParentId() == 0) {
// rootMenus.add(menu);
// } else {
// MenuDTO parent = menuMap.get(menu.getParentId());
// if (parent != null) {
// if (parent.getChildren() == null) {
// parent.setChildren(new ArrayList<>());
// }
// parent.getChildren().add(menu);
// }
// }
// }
//
// return rootMenus;
// }
}