接口调整
This commit is contained in:
@@ -8,12 +8,14 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.resource.NoResourceFoundException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import static com.njcn.rdms.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
|
||||
import static com.njcn.rdms.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_FOUND;
|
||||
|
||||
/**
|
||||
* Gateway 的全局异常处理器,将 Exception 翻译成 CommonResult + 对应的异常编号
|
||||
@@ -27,6 +29,8 @@ import static com.njcn.rdms.framework.common.exception.enums.GlobalErrorCodeCons
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
|
||||
|
||||
private static final String CHROME_DEVTOOLS_RESOURCE_PATH = "/.well-known/appspecific/com.chrome.devtools.json";
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
|
||||
// 已经 commit,则直接返回异常
|
||||
@@ -37,7 +41,9 @@ public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
|
||||
|
||||
// 转换成 CommonResult
|
||||
CommonResult<?> result;
|
||||
if (ex instanceof ResponseStatusException) {
|
||||
if (ex instanceof NoResourceFoundException) {
|
||||
result = noResourceFoundExceptionHandler(exchange, (NoResourceFoundException) ex);
|
||||
} else if (ex instanceof ResponseStatusException) {
|
||||
result = responseStatusExceptionHandler(exchange, (ResponseStatusException) ex);
|
||||
} else {
|
||||
result = defaultExceptionHandler(exchange, ex);
|
||||
@@ -58,6 +64,24 @@ public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
|
||||
return CommonResult.error(ex.getStatusCode().value(), ex.getReason());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 WebFlux 静态资源不存在异常
|
||||
*/
|
||||
private CommonResult<?> noResourceFoundExceptionHandler(ServerWebExchange exchange,
|
||||
NoResourceFoundException ex) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
String path = request.getPath().value();
|
||||
log.debug("[noResourceFoundExceptionHandler][uri({}/{}) 请求地址不存在]", request.getURI(), request.getMethod());
|
||||
return CommonResult.error(NOT_FOUND.getCode(), buildNoResourceMessage(path));
|
||||
}
|
||||
|
||||
private String buildNoResourceMessage(String path) {
|
||||
if (CHROME_DEVTOOLS_RESOURCE_PATH.equals(path)) {
|
||||
return "当前服务未提供浏览器调试探测资源";
|
||||
}
|
||||
return String.format("请求地址不存在:%s", path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理系统异常,兜底处理所有的一切
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,12 @@ import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||
import com.njcn.rdms.framework.security.config.SecurityProperties;
|
||||
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.*;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthLoginReqVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthLoginRespVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthRegisterReqVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthUserRouteRespVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthUserInfoRespVO;
|
||||
import com.njcn.rdms.module.system.convert.auth.AuthConvert;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
|
||||
@@ -26,7 +31,12 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -83,29 +93,48 @@ public class AuthController {
|
||||
return success(authService.refreshToken(refreshToken));
|
||||
}
|
||||
|
||||
@GetMapping("/get-permission-info")
|
||||
@Operation(summary = "获取登录用户的权限信息")
|
||||
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
|
||||
@GetMapping("/get-user-info")
|
||||
@Operation(summary = "获取登录用户信息")
|
||||
public CommonResult<AuthUserInfoRespVO> getUserInfo() {
|
||||
// 1.1 获得用户信息
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
// 1.2 获得角色列表
|
||||
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
|
||||
if (CollUtil.isEmpty(roleIds)) {
|
||||
// 1.2 获得角色和按钮权限
|
||||
List<RoleDO> roles = getCurrentUserRoles();
|
||||
List<MenuDO> menuList = getCurrentUserMenus(roles);
|
||||
return success(AuthConvert.INSTANCE.convertUserInfo(user, roles, menuList));
|
||||
}
|
||||
|
||||
@GetMapping("/get-user-routes")
|
||||
@Operation(summary = "获取登录用户路由信息")
|
||||
public CommonResult<AuthUserRouteRespVO> getUserRoutes() {
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
List<RoleDO> roles = getCurrentUserRoles();
|
||||
List<MenuDO> menuList = getCurrentUserMenus(roles);
|
||||
return success(AuthConvert.INSTANCE.convertUserRoutes(menuList));
|
||||
}
|
||||
|
||||
@GetMapping("/get-permission-info")
|
||||
@Operation(summary = "获取登录用户的权限信息")
|
||||
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
List<RoleDO> roles = getCurrentUserRoles();
|
||||
if (CollUtil.isEmpty(roles)) {
|
||||
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
|
||||
}
|
||||
List<RoleDO> roles = roleService.getRoleList(roleIds);
|
||||
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
|
||||
|
||||
// 1.3 获得菜单列表
|
||||
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
|
||||
List<MenuDO> menuList = menuService.getMenuList(menuIds);
|
||||
menuList = menuService.filterDisableMenus(menuList);
|
||||
|
||||
// 2. 拼接结果返回
|
||||
List<MenuDO> menuList = getCurrentUserMenus(roles);
|
||||
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
|
||||
}
|
||||
|
||||
@@ -116,4 +145,25 @@ public class AuthController {
|
||||
return success(authService.register(registerReqVO));
|
||||
}
|
||||
|
||||
private List<RoleDO> getCurrentUserRoles() {
|
||||
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
|
||||
if (CollUtil.isEmpty(roleIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<RoleDO> roles = roleService.getRoleList(roleIds);
|
||||
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus()));
|
||||
return roles;
|
||||
}
|
||||
|
||||
private List<MenuDO> getCurrentUserMenus(List<RoleDO> roles) {
|
||||
if (CollUtil.isEmpty(roles)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
|
||||
List<MenuDO> menuList = menuService.getMenuList(menuIds);
|
||||
return menuService.filterDisableMenus(menuList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.njcn.rdms.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 用户路由 Meta Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthRouteMetaRespVO {
|
||||
|
||||
@Schema(description = "菜单或页面标题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String title;
|
||||
|
||||
@Schema(description = "国际化 key")
|
||||
private String i18nKey;
|
||||
|
||||
@Schema(description = "图标名")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "本地图标名")
|
||||
private String localIcon;
|
||||
|
||||
@Schema(description = "排序值")
|
||||
private Integer order;
|
||||
|
||||
@Schema(description = "是否缓存")
|
||||
private Boolean keepAlive;
|
||||
|
||||
@Schema(description = "是否在菜单中隐藏")
|
||||
private Boolean hideInMenu;
|
||||
|
||||
@Schema(description = "当前页面高亮的菜单路由名")
|
||||
private String activeMenu;
|
||||
|
||||
@Schema(description = "是否支持多标签页")
|
||||
private Boolean multiTab;
|
||||
|
||||
@Schema(description = "标签页固定位置")
|
||||
private Integer fixedIndexInTab;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.njcn.rdms.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 用户路由节点 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthRouteNodeRespVO {
|
||||
|
||||
@Schema(description = "路由节点 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "路由名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_user")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "完整路由路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "/system/user")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "前端组件白名单 key", example = "view.system_user")
|
||||
private String component;
|
||||
|
||||
@Schema(description = "重定向路径")
|
||||
private String redirect;
|
||||
|
||||
@Schema(description = "路由 props")
|
||||
private Object props;
|
||||
|
||||
@Schema(description = "路由 meta", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private AuthRouteMetaRespVO meta;
|
||||
|
||||
@Schema(description = "子路由列表")
|
||||
private List<AuthRouteNodeRespVO> children;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.rdms.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 登录用户信息 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthUserInfoRespVO {
|
||||
|
||||
@Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "admin")
|
||||
private String userName;
|
||||
|
||||
@Schema(description = "角色编码列表", example = "[\"SUPER_ADMIN\"]")
|
||||
private List<String> roles;
|
||||
|
||||
@Schema(description = "按钮权限码列表", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
example = "[\"system:user:add\", \"system:user:update\"]")
|
||||
private List<String> buttons;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.njcn.rdms.module.system.controller.admin.auth.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 用户路由 Response VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class AuthUserRouteRespVO {
|
||||
|
||||
@Schema(description = "用户可访问路由树", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<AuthRouteNodeRespVO> routes;
|
||||
|
||||
@Schema(description = "默认首页路由名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_user")
|
||||
private String home;
|
||||
|
||||
}
|
||||
@@ -4,7 +4,11 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthRouteMetaRespVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthRouteNodeRespVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthUserInfoRespVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthUserRouteRespVO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
|
||||
@@ -16,10 +20,15 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.njcn.rdms.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static com.njcn.rdms.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static com.njcn.rdms.framework.common.util.collection.CollectionUtils.filterList;
|
||||
import static com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO.ID_ROOT;
|
||||
@@ -39,6 +48,86 @@ public interface AuthConvert {
|
||||
.build();
|
||||
}
|
||||
|
||||
default AuthUserInfoRespVO convertUserInfo(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
|
||||
return AuthUserInfoRespVO.builder()
|
||||
.userId(String.valueOf(user.getId()))
|
||||
.userName(user.getUsername())
|
||||
.roles(sortDistinctStrings(convertList(roleList, RoleDO::getCode)))
|
||||
.buttons(sortDistinctStrings(convertList(menuList, MenuDO::getPermission,
|
||||
menu -> StrUtil.isNotBlank(menu.getPermission()))))
|
||||
.build();
|
||||
}
|
||||
|
||||
default AuthUserRouteRespVO convertUserRoutes(List<MenuDO> menuList) {
|
||||
if (CollUtil.isEmpty(menuList)) {
|
||||
return AuthUserRouteRespVO.builder()
|
||||
.routes(Collections.emptyList())
|
||||
.home("")
|
||||
.build();
|
||||
}
|
||||
|
||||
List<MenuDO> routeMenus = filterList(menuList, this::canExposeAsRoute);
|
||||
if (CollUtil.isEmpty(routeMenus)) {
|
||||
return AuthUserRouteRespVO.builder()
|
||||
.routes(Collections.emptyList())
|
||||
.home("")
|
||||
.build();
|
||||
}
|
||||
|
||||
Map<Long, MenuDO> menuMap = new LinkedHashMap<>();
|
||||
routeMenus.forEach(menu -> menuMap.put(menu.getId(), menu));
|
||||
|
||||
Map<Long, String> fullPathCache = new HashMap<>();
|
||||
List<MenuDO> validMenus = filterList(routeMenus, menu -> {
|
||||
String fullPath = resolveFullPath(menu, menuMap, fullPathCache);
|
||||
return StrUtil.isNotBlank(fullPath) && !isExternalPath(fullPath);
|
||||
});
|
||||
if (CollUtil.isEmpty(validMenus)) {
|
||||
return AuthUserRouteRespVO.builder()
|
||||
.routes(Collections.emptyList())
|
||||
.home("")
|
||||
.build();
|
||||
}
|
||||
|
||||
Set<Long> validMenuIds = convertSet(validMenus, MenuDO::getId);
|
||||
Set<Long> parentIds = new HashSet<>();
|
||||
validMenus.forEach(menu -> {
|
||||
if (validMenuIds.contains(menu.getParentId())) {
|
||||
parentIds.add(menu.getParentId());
|
||||
}
|
||||
});
|
||||
|
||||
Map<Long, String> routeNameMap = buildRouteNameMap(validMenus, fullPathCache);
|
||||
Map<Long, AuthRouteNodeRespVO> nodeMap = new LinkedHashMap<>();
|
||||
validMenus.forEach(menu -> nodeMap.put(menu.getId(), buildRouteNode(menu,
|
||||
fullPathCache.get(menu.getId()), routeNameMap.get(menu.getId()), parentIds.contains(menu.getId()))));
|
||||
|
||||
List<AuthRouteNodeRespVO> roots = new ArrayList<>();
|
||||
validMenus.forEach(menu -> {
|
||||
AuthRouteNodeRespVO node = nodeMap.get(menu.getId());
|
||||
if (!validMenuIds.contains(menu.getParentId()) || ID_ROOT.equals(menu.getParentId())) {
|
||||
roots.add(node);
|
||||
return;
|
||||
}
|
||||
|
||||
AuthRouteNodeRespVO parentNode = nodeMap.get(menu.getParentId());
|
||||
if (parentNode == null) {
|
||||
roots.add(node);
|
||||
return;
|
||||
}
|
||||
if (parentNode.getChildren() == null) {
|
||||
parentNode.setChildren(new ArrayList<>());
|
||||
}
|
||||
parentNode.getChildren().add(node);
|
||||
});
|
||||
|
||||
List<AuthRouteNodeRespVO> routes = sortRouteNodes(roots);
|
||||
return AuthUserRouteRespVO.builder()
|
||||
.routes(routes)
|
||||
.home(StrUtil.blankToDefault(resolveHome(routes), ""))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将菜单列表,构建成菜单树。
|
||||
*/
|
||||
@@ -69,4 +158,176 @@ public interface AuthConvert {
|
||||
return filterList(treeNodeMap.values(), node -> ID_ROOT.equals(node.getParentId()));
|
||||
}
|
||||
|
||||
default List<String> sortDistinctStrings(List<String> values) {
|
||||
if (CollUtil.isEmpty(values)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return values.stream()
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
default boolean canExposeAsRoute(MenuDO menu) {
|
||||
return menu != null
|
||||
&& !MenuTypeEnum.BUTTON.getType().equals(menu.getType())
|
||||
&& (MenuTypeEnum.DIR.getType().equals(menu.getType()) || !Boolean.FALSE.equals(menu.getVisible()));
|
||||
}
|
||||
|
||||
default String resolveFullPath(MenuDO menu, Map<Long, MenuDO> menuMap, Map<Long, String> cache) {
|
||||
String cachedPath = cache.get(menu.getId());
|
||||
if (cachedPath != null) {
|
||||
return cachedPath;
|
||||
}
|
||||
|
||||
String rawPath = StrUtil.trimToEmpty(menu.getPath());
|
||||
String fullPath;
|
||||
if (StrUtil.isBlank(rawPath)) {
|
||||
fullPath = "";
|
||||
} else if (isExternalPath(rawPath)) {
|
||||
fullPath = rawPath;
|
||||
} else if (StrUtil.startWith(rawPath, "/")) {
|
||||
fullPath = normalizePath(rawPath);
|
||||
} else {
|
||||
MenuDO parent = menuMap.get(menu.getParentId());
|
||||
if (parent == null || ID_ROOT.equals(menu.getParentId())) {
|
||||
fullPath = normalizePath("/" + rawPath);
|
||||
} else {
|
||||
String parentPath = resolveFullPath(parent, menuMap, cache);
|
||||
fullPath = normalizePath(parentPath + "/" + rawPath);
|
||||
}
|
||||
}
|
||||
|
||||
cache.put(menu.getId(), fullPath);
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
default Map<Long, String> buildRouteNameMap(List<MenuDO> menus, Map<Long, String> fullPathCache) {
|
||||
Map<Long, String> routeNameMap = new LinkedHashMap<>();
|
||||
Set<String> usedNames = new HashSet<>();
|
||||
menus.forEach(menu -> {
|
||||
String fullPath = fullPathCache.get(menu.getId());
|
||||
String baseName = normalizeRouteName(fullPath);
|
||||
if (StrUtil.isBlank(baseName)) {
|
||||
baseName = "route_" + menu.getId();
|
||||
}
|
||||
String routeName = baseName;
|
||||
if (usedNames.contains(routeName)) {
|
||||
routeName = baseName + "_" + menu.getId();
|
||||
}
|
||||
usedNames.add(routeName);
|
||||
routeNameMap.put(menu.getId(), routeName);
|
||||
});
|
||||
return routeNameMap;
|
||||
}
|
||||
|
||||
default AuthRouteNodeRespVO buildRouteNode(MenuDO menu, String fullPath, String routeName, boolean hasChildren) {
|
||||
return AuthRouteNodeRespVO.builder()
|
||||
.id(String.valueOf(menu.getId()))
|
||||
.name(routeName)
|
||||
.path(fullPath)
|
||||
.component(resolveComponentKey(menu, routeName, hasChildren))
|
||||
.meta(buildRouteMeta(menu))
|
||||
.build();
|
||||
}
|
||||
|
||||
default AuthRouteMetaRespVO buildRouteMeta(MenuDO menu) {
|
||||
return AuthRouteMetaRespVO.builder()
|
||||
.title(menu.getName())
|
||||
.icon(resolveIcon(menu.getIcon()))
|
||||
.order(menu.getSort())
|
||||
.keepAlive(menu.getKeepAlive())
|
||||
.build();
|
||||
}
|
||||
|
||||
default String resolveComponentKey(MenuDO menu, String routeName, boolean hasChildren) {
|
||||
if (hasChildren) {
|
||||
return "layout.base";
|
||||
}
|
||||
if (ID_ROOT.equals(menu.getParentId())) {
|
||||
return "layout.base$view." + routeName;
|
||||
}
|
||||
return "view." + routeName;
|
||||
}
|
||||
|
||||
default String resolveIcon(String icon) {
|
||||
if (StrUtil.isBlank(icon) || "#".equals(icon)) {
|
||||
return null;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
default String normalizePath(String path) {
|
||||
String normalized = path.replace('\\', '/');
|
||||
normalized = normalized.replaceAll("/{2,}", "/");
|
||||
if (!normalized.startsWith("/")) {
|
||||
normalized = "/" + normalized;
|
||||
}
|
||||
if (normalized.length() > 1 && normalized.endsWith("/")) {
|
||||
normalized = normalized.substring(0, normalized.length() - 1);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
default boolean isExternalPath(String path) {
|
||||
return StrUtil.startWithAnyIgnoreCase(path, "http://", "https://");
|
||||
}
|
||||
|
||||
default String normalizeRouteName(String fullPath) {
|
||||
if (StrUtil.isBlank(fullPath)) {
|
||||
return "";
|
||||
}
|
||||
return fullPath.replaceAll("^/+", "")
|
||||
.replaceAll("/+$", "")
|
||||
.replaceAll("[/\\-.]+", "_")
|
||||
.replaceAll("_+", "_")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
default List<AuthRouteNodeRespVO> sortRouteNodes(List<AuthRouteNodeRespVO> routes) {
|
||||
if (CollUtil.isEmpty(routes)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<AuthRouteNodeRespVO> sortedRoutes = new ArrayList<>(routes);
|
||||
sortedRoutes.sort(Comparator
|
||||
.comparing((AuthRouteNodeRespVO route) -> route.getMeta() != null && route.getMeta().getOrder() != null
|
||||
? route.getMeta().getOrder() : Integer.MAX_VALUE)
|
||||
.thenComparing(AuthRouteNodeRespVO::getPath, Comparator.nullsLast(String::compareTo))
|
||||
.thenComparing(AuthRouteNodeRespVO::getId, Comparator.nullsLast(String::compareTo)));
|
||||
|
||||
sortedRoutes.forEach(route -> {
|
||||
if (CollUtil.isEmpty(route.getChildren())) {
|
||||
route.setChildren(null);
|
||||
return;
|
||||
}
|
||||
|
||||
List<AuthRouteNodeRespVO> children = sortRouteNodes(route.getChildren());
|
||||
route.setChildren(children);
|
||||
route.setRedirect(children.get(0).getPath());
|
||||
});
|
||||
return sortedRoutes;
|
||||
}
|
||||
|
||||
default String resolveHome(List<AuthRouteNodeRespVO> routes) {
|
||||
if (CollUtil.isEmpty(routes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (AuthRouteNodeRespVO route : routes) {
|
||||
if (CollUtil.isNotEmpty(route.getChildren())) {
|
||||
String childHome = resolveHome(route.getChildren());
|
||||
if (StrUtil.isNotBlank(childHome)) {
|
||||
return childHome;
|
||||
}
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(route.getChildren())) {
|
||||
return route.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user