From 7e597e53bc70172f5bb84e81e46c6807ab54dcf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Tue, 21 May 2024 23:05:31 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "\345\244\207\345\277\230\345\275\225.md" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/\345\244\207\345\277\230\345\275\225.md" "b/\345\244\207\345\277\230\345\275\225.md" index 1886150..31975cf 100644 --- "a/\345\244\207\345\277\230\345\275\225.md" +++ "b/\345\244\207\345\277\230\345\275\225.md" @@ -8,6 +8,8 @@ - [ ] 考虑使用一个注解对密级字段进行权限控制。将注解放到实体类的指定字段上,就可以控制整条数据的权限。 - [ ] 需要接口调用频率的控制。 - [ ] 级联删除与取代删除不支持批量操作。普通批量删除方式删除当前节点后,子节点将无法通过根节点找到,需要通过定时任务进行定期删除。 +- [ ] 检查枚举中的toString方法是否多余。 +- [ ] 检查枚举在代码与字符不同的情况下,用于param是否正确(字符串是否可以正确转换为枚举) # 正在进行 -- Gitee From eb2387f2f4dec2e632fe211385b71427d655d12b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Wed, 22 May 2024 23:01:26 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E8=B7=A8=E5=9F=9F=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/top/milkbox/Application.java | 3 +- .../core/config/SaTokenConfiguration.java | 63 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/milkbox-app/src/main/java/top/milkbox/Application.java b/milkbox-app/src/main/java/top/milkbox/Application.java index 7914742..fcb7793 100644 --- a/milkbox-app/src/main/java/top/milkbox/Application.java +++ b/milkbox-app/src/main/java/top/milkbox/Application.java @@ -22,7 +22,8 @@ import java.util.TimeZone; * @author milkbox */ @Slf4j -@EnableWebMvc +// 注意:使用satoken不能加这个注解,否则在SaServletFilter中调用SpringMVCUtil.getRequest()“报错非Web上下文无法获取Request” +//@EnableWebMvc @RestController @SpringBootApplication public class Application { diff --git a/milkbox-app/src/main/java/top/milkbox/core/config/SaTokenConfiguration.java b/milkbox-app/src/main/java/top/milkbox/core/config/SaTokenConfiguration.java index 225c2c4..8118764 100644 --- a/milkbox-app/src/main/java/top/milkbox/core/config/SaTokenConfiguration.java +++ b/milkbox-app/src/main/java/top/milkbox/core/config/SaTokenConfiguration.java @@ -1,10 +1,20 @@ package top.milkbox.core.config; +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.filter.SaServletFilter; import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.router.SaHttpMethod; +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.util.SaResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +@Slf4j @Configuration public class SaTokenConfiguration implements WebMvcConfigurer { @@ -14,4 +24,57 @@ public class SaTokenConfiguration implements WebMvcConfigurer { // 注册 Sa-Token 拦截器,打开注解式鉴权功能 registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); } + + + /** + * 注册 [Sa-Token 全局过滤器] + */ + @Bean + public SaServletFilter getSaServletFilter() { + return new SaServletFilter() + +// // 指定 [拦截路由] 与 [放行路由] + .addInclude("/**") + .addExclude( + "/favicon.ico", + "/", + "/sysUser/login" + ) +// +// // 认证函数: 每次请求执行 + .setAuth(obj -> { + SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue()); + // ... + }) + + // 异常处理函数:每次认证函数发生异常时执行此函数 + .setError(e -> { + log.error("----- 认证失败,原因:{}", e.getMessage()); + e.printStackTrace(); + return SaResult.error(e.getMessage()); + }) + + // 前置函数:在每次认证函数之前执行(BeforeAuth 不受 includeList 与 excludeList 的限制,所有请求都会进入) + .setBeforeAuth(obj -> { + SaHolder.getResponse() + + // ---------- 设置跨域响应头 ---------- + // 允许指定域访问跨域资源 + .setHeader("Access-Control-Allow-Origin", "*") + // 允许所有请求方式 + .setHeader("Access-Control-Allow-Methods", "*") + // 允许的header参数 + .setHeader("Access-Control-Allow-Headers", "*") + // 有效时间 + .setHeader("Access-Control-Max-Age", "3600"); + + // 如果是预检请求,则立即返回到前端 + SaRouter.match(SaHttpMethod.OPTIONS) + .free(r -> System.out.println("--------OPTIONS预检请求,不做处理")) + .back(); + }) + ; + } + + } -- Gitee From b0010a8b6528523b9610fa74afff80e038e57a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Mon, 3 Jun 2024 16:18:16 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E8=B7=A8=E5=9F=9F=E8=AF=B7=E6=B1=82=EF=BC=8C=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E5=85=81=E8=AE=B8=E6=B5=8F=E8=A7=88=E5=99=A8=E5=A4=84=E7=90=86?= =?UTF-8?q?cookie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/config/SaTokenConfiguration.java | 150 +++++++++++++----- 1 file changed, 106 insertions(+), 44 deletions(-) diff --git a/milkbox-app/src/main/java/top/milkbox/core/config/SaTokenConfiguration.java b/milkbox-app/src/main/java/top/milkbox/core/config/SaTokenConfiguration.java index 8118764..ae1b2d3 100644 --- a/milkbox-app/src/main/java/top/milkbox/core/config/SaTokenConfiguration.java +++ b/milkbox-app/src/main/java/top/milkbox/core/config/SaTokenConfiguration.java @@ -1,18 +1,20 @@ package top.milkbox.core.config; -import cn.dev33.satoken.SaManager; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.filter.SaServletFilter; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.router.SaHttpMethod; import cn.dev33.satoken.router.SaRouter; -import cn.dev33.satoken.stp.StpUtil; -import cn.dev33.satoken.util.SaResult; +import cn.dev33.satoken.util.SaTokenConsts; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import top.milkbox.common.enums.CommonStatusCodeEnum; +import top.milkbox.common.pojo.CommonResult; @Slf4j @Configuration @@ -28,52 +30,112 @@ public class SaTokenConfiguration implements WebMvcConfigurer { /** * 注册 [Sa-Token 全局过滤器] + *
+     * 可通过如下方式设置过滤器链,详情请参照官方文档:
+     * 自定义过滤器执行顺序
+     * @Bean
+     * public FilterRegistrationBean<SaServletFilter>
+     * 
+ *

+ * 这里的filter拦截器早于interceptor + *

*/ @Bean public SaServletFilter getSaServletFilter() { - return new SaServletFilter() + SaServletFilter saServletFilter = new SaServletFilter(); -// // 指定 [拦截路由] 与 [放行路由] + // 前置函数:在每次认证函数之前执行(BeforeAuth 不受 includeList 与 excludeList 的限制,所有请求都会进入) + // 不管什么请求,都先经过这里。obj是拓展字段,目前没有任何意义(1.37.0版本的sa-token) + saServletFilter.setBeforeAuth(obj -> { + + SaHolder.getResponse() + + // ---------- 设置跨域响应头 ---------- + /* + 对于跨域请求,我们分两种情况 + 1. 不使用浏览器的自动管理cookie功。也就是说在前后端分离的项目中(小程序,h5,手机应用等)禁用了cookie功能。 + sa-token的登录令牌(token)需要在前端手动控制存储 + 浏览器无需管理cookie,所以权限比较松,配置参考如下: + // 允许所有域 + .setHeader("Access-Control-Allow-Origin", "*") + // 允许所有请求方式 + .setHeader("Access-Control-Allow-Methods", "*") + // 允许所有头 + .setHeader("Access-Control-Allow-Headers", "*") + // 有效时间 + .setHeader("Access-Control-Max-Age", "3600"); + + 2. 如果硬是要用浏览器的自动存储cookie功能,需要一些额外配置,由于浏览器安全策略,必须明确指定允许的域、方法和允许的头。 + 并且需要额外配置Access-Control-Allow-Credentials为true。配置参考如下: + // 使用SaHolder.getRequest().getHeader("Origin")获取请求的来源,相当于允许所有的域 + .setHeader("Access-Control-Allow-Origin", SaHolder.getRequest().getHeader("Origin")) + // 允许所有请求方式 + .setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT") + // 允许的header参数 + .setHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With") + // 有效时间 + .setHeader("Access-Control-Max-Age", "3600") + // 允许浏览器发送与保存cookie + .setHeader("Access-Control-Allow-Credentials", "true"); + + // 如果前端使用的是axios(其他的请求框架类似)这需要额外配置,允许跨域携带cookie:withCredentials: true + // 设置axios + const axiosInstance = axios.create({ + // 设置请求地址 + baseURL: import.meta.env.VITE_APP_SERVER_URL, + // 允许跨域保存与携带cookie + withCredentials: true, + }) + */ + .setHeader("Access-Control-Allow-Origin", SaHolder.getRequest().getHeader("Origin")) + // 允许所有请求方式 + .setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT") + // 允许的header参数 + .setHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With") + // 有效时间 + .setHeader("Access-Control-Max-Age", "3600") + // 允许浏览器发送与保存cookie + .setHeader("Access-Control-Allow-Credentials", "true"); + + // 如果是预检请求,则立即返回到前端 + // 这里的match可以理解为立即匹配请求方法,其参数是可变参数,可以传递多个 + SaRouter.match(SaHttpMethod.OPTIONS) + // 当匹配到指定的请求方法后执行free中的函数式接口,参数r代表的是链式写法中操作的对象SaRouterStaff + // 可以在函数式接口中抛出StopMatchException异常来立即跳过SaServletFilter过滤器 + .free(r -> System.out.println("--------OPTIONS预检请求,不做处理")) + // 若匹配到则报错BackResultException,若未匹配到则只返回SaRouterStaff对象 + // 抛出BackResultException异常会由sa-token处理,以text/plain格式将报错信息写入响应体 + // 而实际上报错的BackResultException中没有任何信息 + .back(); + }); + + // 指定 [拦截路由] 与 [放行路由] + saServletFilter .addInclude("/**") - .addExclude( - "/favicon.ico", - "/", - "/sysUser/login" - ) -// -// // 认证函数: 每次请求执行 - .setAuth(obj -> { - SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue()); - // ... - }) - - // 异常处理函数:每次认证函数发生异常时执行此函数 - .setError(e -> { - log.error("----- 认证失败,原因:{}", e.getMessage()); - e.printStackTrace(); - return SaResult.error(e.getMessage()); - }) - - // 前置函数:在每次认证函数之前执行(BeforeAuth 不受 includeList 与 excludeList 的限制,所有请求都会进入) - .setBeforeAuth(obj -> { - SaHolder.getResponse() - - // ---------- 设置跨域响应头 ---------- - // 允许指定域访问跨域资源 - .setHeader("Access-Control-Allow-Origin", "*") - // 允许所有请求方式 - .setHeader("Access-Control-Allow-Methods", "*") - // 允许的header参数 - .setHeader("Access-Control-Allow-Headers", "*") - // 有效时间 - .setHeader("Access-Control-Max-Age", "3600"); - - // 如果是预检请求,则立即返回到前端 - SaRouter.match(SaHttpMethod.OPTIONS) - .free(r -> System.out.println("--------OPTIONS预检请求,不做处理")) - .back(); - }) - ; + .addExclude("/favicon.ico"); + + // 认证函数: 每次请求执行 + // 在setBeforeAuth之后,且必须满足addInclude与addExclude的条件时才执行 + // obj是拓展字段,目前没有任何意义(1.37.0版本的sa-token) + saServletFilter.setAuth(obj -> { + // 拦截指定的路径后要干的事情...(目前没什么事可干) + // ... + }); + + // 异常处理函数:每次认证函数发生异常时执行此函数 + // 在setBeforeAuth和setAuth阶段发生异常时执行此函数传递的函数式接口 + // 函数式接口中,e:表示异常对象;返回值将会写入到响应对象中,默认是text/plain格式,可以修改响应的格式来返回json,具体见其源码的注释 + // 此处拦截的异常早于SpringBoot的全局异常拦截器,不受全局异常拦截器的影响 + saServletFilter.setError(e -> { + String message = StrUtil.format("顶级拦截器(跨域处理)异常,原因:{}", e.getMessage()); + log.error(message, e); + SaHolder.getResponse().setHeader("Content-Type", SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON); + // 由于此处不经过springMVC,所以需要手动转换为json + return JSONUtil.toJsonStr( + new CommonResult<>(CommonStatusCodeEnum.ERROR500.getCode(), message, e.getStackTrace())); + }); + + return saServletFilter; } -- Gitee From 4ff6a462521cb69426973f04c2ab548f678e4e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Mon, 3 Jun 2024 18:35:37 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sys/modular/menu/service/impl/SysMenuServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/impl/SysMenuServiceImpl.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/impl/SysMenuServiceImpl.java index ba41be1..9118070 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/impl/SysMenuServiceImpl.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/impl/SysMenuServiceImpl.java @@ -210,7 +210,7 @@ public class SysMenuServiceImpl extends CommonServiceImpl userMenuIdList = sysRelationshipService.findObjectIdListByTargetId( + List userMenuIdList = sysRelationshipService.findTargetIdListByObjectId( loginUserId, SysRelationshipTypeEnum.SYS_USER_RELATE_SYS_MENU); // 合并两个集合 -- Gitee From 46113129abfa2bb968611067096e054b29d0e3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Tue, 9 Jul 2024 17:54:29 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E8=87=AA=E5=B7=B1=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E7=9A=84=E9=9B=86=E5=90=88=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../milkbox/common/utils/CommonCollUtil.java | 180 ++++++++++++++++++ .../top/milkbox/common/utils/CommonUtil.java | 151 ++++++++++++++- .../milkbox/common/utils/base/CommonNode.java | 32 ++++ .../common/utils/base/CycleRefException.java | 9 + "\345\244\207\345\277\230\345\275\225.md" | 4 + 5 files changed, 369 insertions(+), 7 deletions(-) create mode 100644 milkbox-common/src/main/java/top/milkbox/common/utils/CommonCollUtil.java create mode 100644 milkbox-common/src/main/java/top/milkbox/common/utils/base/CommonNode.java create mode 100644 milkbox-common/src/main/java/top/milkbox/common/utils/base/CycleRefException.java diff --git a/milkbox-common/src/main/java/top/milkbox/common/utils/CommonCollUtil.java b/milkbox-common/src/main/java/top/milkbox/common/utils/CommonCollUtil.java new file mode 100644 index 0000000..6e55814 --- /dev/null +++ b/milkbox-common/src/main/java/top/milkbox/common/utils/CommonCollUtil.java @@ -0,0 +1,180 @@ +package top.milkbox.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import top.milkbox.common.utils.base.CommonNode; +import top.milkbox.common.utils.base.CycleRefException; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 集合工具类 + * + * @author 郭泳辰 + */ +public class CommonCollUtil { + + /** + * 获取给定集合中重复的元素
+ *
+     * // 使用举例:
+     * List<ImportCategoryData> cachedDataList = new ArrayList<>();
+     * // cachedDataList............
+     * List<String> duplicateList =
+     *          CommonCollUtil.getDuplicateElements(cachedDataList, ImportCategoryData::getCode);
+     * if (ObjectUtil.isNotEmpty(duplicateList)) {
+     *      // 某某某重复
+     *      duplicateList.forEach(item -> log.info("某某某【" + item + "】重复"));
+     * }
+     * 
+ * + * @param objectList 指定集合 + * @param function 指定字段 + * @param 集合中对象的类型 + * @param 指定的字段类型 + * @return 返回集合中重复的所有元素 + */ + public static List getDuplicateElements(Collection objectList, Function function) { + return getDuplicateElements(objectList.stream().map(function)); + } + + /** + * 获取给定的简单集合中重复的元素
+ * 仅支持简单类型的集合,复杂类型集合请使用重载方法:{@link #getDuplicateElements(Collection, Function)} + * + * @param simpleList 指定集合 + * @param 集合中对象的类型,必须是简单类型对象 + * @return 返回重复的所有元素 + */ + public static List getDuplicateElements(Collection simpleList) { + return getDuplicateElements(simpleList.stream()); + } + + /** + * 获取给定的流中重复的元素
+ * 依靠分组操作求重复元素 + * + * @param stream 指定的流对象(内部必须是简单类型) + * @param 流中元素的类型,必须是简单类型 + * @return 返回重复的元素 + */ + public static List getDuplicateElements(Stream stream) { + return stream + // 去空 + .filter(ObjectUtil::isNotNull) + // 分组 + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) + // 获取键值对集合 + .entrySet().stream() + // 值大于1的键就是重复的元素 + .filter(entry -> entry.getValue() > 1) + // 获取键 + .map(Map.Entry::getKey) + // 转为键集合 + .collect(Collectors.toList()); + } + + + /** + * 线性集合转为森林
+ *
+     * 节点类型必须实现{@link CommonNode}接口
+     *
+     * 满足一下任意条件表示是一个顶级节点:
+     * 1. 当前节点的parentId为空
+     * 2. 当前节点的parentId为空或者等于0
+     * 3. 当前节点的有parentId但是未在节点集合中找到其上级
+     * 
+ * + * @param nodes 节点集合 + * @param 节点id类型 + * @param 节点类型 + * @return 返回森林 + * @throws CycleRefException 构建过程中出现循环引用异常 + */ + public static > List toForest(List nodes) throws CycleRefException { + Map nodeMap = nodes.stream().collect(Collectors.toMap(CommonNode::getId, node -> node)); + List rootForest = new ArrayList<>(); + + for (T node : nodes) { + if (ObjectUtil.isEmpty(node.getParentId()) || CommonUtil.isZero(node.getParentId())) { + rootForest.add(node); + } else { + T parentNode = nodeMap.get(node.getParentId()); + if (parentNode != null) { + LinkedList path = findFromForest(node.getParentId(), Collections.singletonList(node)); + if (ObjectUtil.isNotEmpty(path)) { + throw new CycleRefException("循环引用:" + CollUtil.join(path, " <- ")); + } + if (parentNode.getChildrenList() == null) { + parentNode.initChildrenList(); + } + parentNode.getChildrenList().add(node); + } else { + rootForest.add(node); + } + } + } + + return rootForest; + } + + /** + * 递归查找指定节点在森林中的路径 + * + * @param id 节点id + * @param forest 森林 + * @param path 节点所在的路径 + * @param 节点id类型 + * @param 节点类型 + * @return 递归过程中使用,true表示找到节点并立即结束整个递归 + */ + private static > boolean findFromForestDFS(S id, List forest, LinkedList path) { + if (ObjectUtil.isEmpty(forest)) { + return false; + } + for (T node : forest) { + path.add(node.getId()); + + // 找到目标节点 或者 下一层递归告诉我需要立即结束递归,则返回true(返回true表示立即结束整个递归) + if (id.equals(node.getId()) || findFromForestDFS(id, node.getChildrenList(), path)) { + return true; + } + + path.removeLast(); + } + return false; + } + + /** + * 找到指定节点在森林中的路径 + * + * @param id 节点id + * @param forest 森林 + * @param 节点id类型 + * @param 节点类型 + * @return 如果找到,则返回路径,否则返回空集合 + */ + public static > LinkedList findFromForest(S id, List forest) { + LinkedList path = new LinkedList<>(); + findFromForestDFS(id, forest, path); + return path; + } + + /** + * 判断指定节点是否在森林中 + * + * @param id 节点id + * @param forest 森林 + * @param 节点id类型 + * @param 节点类型 + * @return 如果在,则返回true,否则返回false + */ + public static > boolean isInForest(S id, List forest) { + return ObjectUtil.isNotEmpty(findFromForest(id, forest)); + } + +} diff --git a/milkbox-common/src/main/java/top/milkbox/common/utils/CommonUtil.java b/milkbox-common/src/main/java/top/milkbox/common/utils/CommonUtil.java index 39b7fd5..1f51979 100644 --- a/milkbox-common/src/main/java/top/milkbox/common/utils/CommonUtil.java +++ b/milkbox-common/src/main/java/top/milkbox/common/utils/CommonUtil.java @@ -5,10 +5,12 @@ import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.TreeNode; import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; +import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; @@ -25,14 +27,14 @@ public class CommonUtil { /** * 将集合转换为森林 * - * @param sourceList 要转换的集合,集合中的元素必须实现接口CommonMethodUtil.EntityTree + * @param sourceList 要转换的集合,集合中的元素必须实现接口CommonUtil.EntityTree * @param rootId 以这个值为树的根节点 * @param id与parentId的数据类型 * @param 集合中每个元素的类型 * @return 返回森林 - * @author milkbox + * @author 郭泳辰 */ - public static > List> toTree( + public static > List> toTree( List sourceList, S rootId) { // 将OkrNormCategory集合对象转为TreeNode集合对象 List> treeNodeList = sourceList.stream().map(treeNode -> { @@ -57,6 +59,102 @@ public class CommonUtil { String getName(); } + /** + * 将森林转换为只包含id的集合 + * + * @param forest 森林 + * @param Tree的泛型 + * @return 返回Tree对象的id字段的集合 + * @author 郭泳辰 + */ + public static List forestToIdList(List> forest) { + ArrayList resultList = new ArrayList<>(); + generateIdListByDFS(forest, resultList); + return resultList; + } + + /** + * 从指定的数组中根据传递的id查询这个id的所有子级。
+ * 此方法为内部方法,不建议直接调用。请使用findAllChildren(......)系列方法 + * + * @param entityList 被查找的元素集合(集合中的元素必须实现接口CommonUtil.EntityTree) + * @param id 上级id + * @param childrenList 结果(集合中的元素必须实现接口CommonUtil.EntityTree) + * @param deepCount 当前递归深度(从1开始) + * @param deepLimit 最大递归深度(传递0表示无限制递归深度) + * @param 集合中id与parentId的类型 + * @param 集合中元素的类型 + * @return 返回子级集合 + */ + private static > List findAllChildrenHelper( + List entityList, S id, List childrenList, int deepCount, int deepLimit) { + if (entityList == null || id == null || childrenList == null || (deepLimit != 0 && deepCount > deepLimit)) { + return childrenList; + } + for (T entity : entityList) { + if (id.equals(entity.getParentId())) { + childrenList.add(entity); // 不确定此处如果同时将原集合的元素删除是否会提高效率 + findAllChildrenHelper(entityList, entity.getId(), childrenList, deepCount + 1, deepLimit); + } + } + return childrenList; + } + + /** + * 此方法为内部方法,不建议直接调用。请使用findAllChildren(......)系列方法 + */ + private static > List findAllChildrenHelper( + List entityList, S id, List childrenList, int deepLimit) { + return findAllChildrenHelper(entityList, id, childrenList, 1, deepLimit); + } + + /** + * 从指定的集合(entityList)中找出id的所有子级(包括子级的子级......)。 + * + * @param entityList 被查找的元素集合(集合中的元素必须实现接口CommonUtil.EntityTree) + * @param id 上级id + * @param deepLimit 最大递归深度(传递0表示无限制递归深度) + * @param 集合中id与parentId的类型 + * @param 集合中元素的类型 + * @return 返回子级集合 + */ + public static > List findAllChildren( + List entityList, S id, int deepLimit) { + return findAllChildrenHelper(entityList, id, new ArrayList<>(), deepLimit); + } + + /** + * 从指定的集合(entityList)中找出id的所有子级(包括子级的子级......)。
+ * 此方法限制递归深度为32层 + * + * @param entityList 被查找的元素集合(集合中的元素必须实现接口CommonUtil.EntityTree) + * @param id 上级id + * @param 集合中id与parentId的类型 + * @param 集合中元素的类型 + * @return 返回子级集合 + */ + public static > List findAllChildren( + List entityList, S id) { + return findAllChildrenHelper(entityList, id, new ArrayList<>(), 32); + } + + /** + * 深度优先遍历,将森林转换为只包含id的集合 + * + * @param forest 森林 + * @param resultList 返回结果集合 + * @param Tree对象的泛型 + * @author 郭泳辰 + */ + private static void generateIdListByDFS(List> forest, List resultList) { + forest.forEach(tree -> { + resultList.add(tree.getId()); + if (ObjectUtil.isNotEmpty(tree.getChildren())) { + generateIdListByDFS(tree.getChildren(), resultList); + } + }); + } + /** * 转为其他类型page,自定义每一项的转换方式 @@ -66,7 +164,7 @@ public class CommonUtil { * @param 目标page类型 * @param 原page类型 * @return 返回转换后的page - * @author milkbox + * @author 郭泳辰 */ public static Page convertPage(Page page, Function converter) { return convertPage(page, page.getRecords().stream().map(converter).collect(Collectors.toList())); @@ -80,7 +178,7 @@ public class CommonUtil { * @param 目标page类型 * @param 原page类型 * @return 返回转换后的page - * @author milkbox + * @author 郭泳辰 */ public static Page convertPage(Page page, Class targetClass) { return convertPage(page, BeanUtil.copyToList(page.getRecords(), targetClass)); @@ -94,9 +192,9 @@ public class CommonUtil { * @param 目标page类型 * @param 原page类型 * @return 返回转换后的page - * @author milkbox + * @author 郭泳辰 */ - private static Page convertPage(Page page, List targetRecords) { + public static Page convertPage(Page page, List targetRecords) { Page targetPage = new Page<>(); targetPage.setRecords(targetRecords); targetPage.setTotal(page.getTotal()); @@ -111,4 +209,43 @@ public class CommonUtil { return targetPage; } + /** + * 将Page<Object>转换为Page<JSONObject> + * + * @param page 原始分页对象 + * @param 原始分页对象类型 + * @return 返回JSONObject类型分页对象 + * @author 郭泳辰 + */ + public static Page toJSONObjects(Page page) { + return CommonUtil.convertPage(page, JSONUtil::parseObj); + } + + + /** + * 判断任意简单对象是否为0,如果是0则返回true,否则返回false
+ * IllegalArgumentException表示类型不支持,传递null值也会抛出异常 + * + * @param obj 任意简单对象 + */ + public static boolean isZero(Object obj) { + if (obj instanceof String) { + return "0".equals(obj); + } + if (obj instanceof Number) { + Number number = (Number) obj; + if (number instanceof Integer || number instanceof Long || number instanceof Short || number instanceof Byte) { + return number.intValue() == 0; + } else if (number instanceof Double || number instanceof Float) { + return number.doubleValue() == 0.0; + } + } + if (obj instanceof Character) { + Character character = (Character) obj; + return character.equals('0'); + } + throw new IllegalArgumentException("不支持的类型:" + obj.getClass().getName()); + } + + } diff --git a/milkbox-common/src/main/java/top/milkbox/common/utils/base/CommonNode.java b/milkbox-common/src/main/java/top/milkbox/common/utils/base/CommonNode.java new file mode 100644 index 0000000..541fa51 --- /dev/null +++ b/milkbox-common/src/main/java/top/milkbox/common/utils/base/CommonNode.java @@ -0,0 +1,32 @@ +package top.milkbox.common.utils.base; + +import java.util.List; + +public interface CommonNode { + + /** + * 获取节点的唯一标识 + */ + T getId(); + + /** + * 获取父节点的唯一标识 + */ + T getParentId(); + + /** + * 获取子节点列表 + */ + > List getChildrenList(); + + /** + * 初始化子节点列表 + *
+     *     // 一般只需要这么写
+     *     public void initChildrenList() {
+     *         this.childrenList = new ArrayList<>();
+     *     }
+     * 
+ */ + void initChildrenList(); +} \ No newline at end of file diff --git a/milkbox-common/src/main/java/top/milkbox/common/utils/base/CycleRefException.java b/milkbox-common/src/main/java/top/milkbox/common/utils/base/CycleRefException.java new file mode 100644 index 0000000..730f3d7 --- /dev/null +++ b/milkbox-common/src/main/java/top/milkbox/common/utils/base/CycleRefException.java @@ -0,0 +1,9 @@ +package top.milkbox.common.utils.base; + +import cn.hutool.core.util.ObjectUtil; + +public class CycleRefException extends Exception { + public CycleRefException(String message) { + super(ObjectUtil.isEmpty(message) ? "循环引用异常" : message); + } +} diff --git "a/\345\244\207\345\277\230\345\275\225.md" "b/\345\244\207\345\277\230\345\275\225.md" index 31975cf..22b3f43 100644 --- "a/\345\244\207\345\277\230\345\275\225.md" +++ "b/\345\244\207\345\277\230\345\275\225.md" @@ -10,6 +10,10 @@ - [ ] 级联删除与取代删除不支持批量操作。普通批量删除方式删除当前节点后,子节点将无法通过根节点找到,需要通过定时任务进行定期删除。 - [ ] 检查枚举中的toString方法是否多余。 - [ ] 检查枚举在代码与字符不同的情况下,用于param是否正确(字符串是否可以正确转换为枚举) +- [ ] 考虑数据翻译。两种方式: + 1. 使用easyTrans,在公共模块中创建sysUser实体以及其响应的mybatisplus操作,用来统一翻译创建人和修改人。由于公共模块被所有业务模块依赖,所以在各个业务模块中可以拿到公共模块中的sysUser,就可以对其他人员姓名字段进行翻译。如果关系到用户的角色名或者用户的部门名,可以尝试easyTrans是否可以递归深层翻译 + 2. 使用easyTrans,调整项目的分包方式,放弃业务单独分模块,所有业务模块都放在一个模块中。 +- [ ] 尝试将dev和sys两个模块合并,因为目前感觉dev中的功能并不多,没必要单独拆分 # 正在进行 -- Gitee From 8eef7a59ee0d5029748d1a41a22d1d80678c8164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Tue, 27 Aug 2024 14:23:59 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E8=87=AA=E5=B7=B1=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E7=9A=84=E9=87=8D=E8=AF=95=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../top/milkbox/common/utils/RetryUtil.java | 110 ++++++++++++++++++ .../utils/base/ThrowsExceptionFunction.java | 28 +++++ "\345\244\207\345\277\230\345\275\225.md" | 2 +- 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 milkbox-common/src/main/java/top/milkbox/common/utils/RetryUtil.java create mode 100644 milkbox-common/src/main/java/top/milkbox/common/utils/base/ThrowsExceptionFunction.java diff --git a/milkbox-common/src/main/java/top/milkbox/common/utils/RetryUtil.java b/milkbox-common/src/main/java/top/milkbox/common/utils/RetryUtil.java new file mode 100644 index 0000000..554b844 --- /dev/null +++ b/milkbox-common/src/main/java/top/milkbox/common/utils/RetryUtil.java @@ -0,0 +1,110 @@ +package top.milkbox.common.utils; + +import cn.hutool.core.util.RandomUtil; +import lombok.extern.slf4j.Slf4j; +import top.milkbox.common.utils.base.ThrowsExceptionFunction; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +/** + *

重试工具类

+ * + * @author milkbox + */ +@Slf4j +public class RetryUtil { + + public static final int DEFAULT_TIMES = 2; // 默认重试次数 + public static final long DEFAULT_WAIT_TIME = 3000; // 默认重试间隔时间(毫秒) + + /** + *

重试函数

+ *

+ * 使用函数式接口方式,指定要重试的函数,当函数出现Exception类型的异常时,会进行重试。重试次数由times指定,每次重试之间会等待waitTime毫秒 + *

+ *

+ * 重试次数不包括第1次执行,所以times=2表示重试2次,共执行3次。无论如何,第1次一定会执行 + *

+ *

+ * 例: + *

+ *
+     * // 尝试通过接口获取token,如果失败,则再重试3次,每次重试之间等待2秒
+     * String token = RetryUtil.retries((i) -> rpcGetToken(config), 3, 2000);
+     * 
+ * + * @param retriesFunction 需要重试的函数,此函数的参数为当前重试的次数(0表示首次),返回值会被原样返回 + * @param times 重试次数,无论传递什么值,retriesFunction一定会被执行一次 + * @param waitTime 每次重试之间的等待时间,单位为毫秒,如果小于等于0,则立即重试不进行等待 + * @param retriesFunction的返回值类型 + * @return 原样返回retriesFunction的返回值 + * @throws Exception 如果重试次数耗尽,则抛出原异常(就是retriesFunction内部的异常) + */ + private static R retries(ThrowsExceptionFunction retriesFunction, int times, long waitTime) + throws Exception { + int i = 0; + while (true) { + try { + // 执行函数,如果没有异常,则直接返回 + return retriesFunction.apply(i); + } catch (Exception e) { + if (i >= times) { + log.error(">>>>>>>>>>>>>>>> 重试次数耗尽,相应的操作失败!"); + throw e; // 抛出原异常,并结束循环 + } + i++; + if (waitTime > 0) { + // 保留两位小数 + log.warn(String.format(">>>>>>>>>>>>>>>> %.2f秒后重试......", (float) (waitTime) / 1000)); + // 本质上还是Thread.sleep(waitTime),只不过不需要处理异常,且当时间小于等于0的时候不会执行休眠操作 + TimeUnit.MILLISECONDS.sleep(waitTime); + } + log.warn(">>>>>>>>>>>>>>>> 正在重试({}/{})......", i, times); + } + } + } + + /** + *

重试函数

+ * {@link RetryUtil#retries(ThrowsExceptionFunction, int, long)}的重载,自定义重试次数,重试间隔为{@link RetryUtil#DEFAULT_WAIT_TIME}
+ * 详情参见{@link RetryUtil#retries(ThrowsExceptionFunction, int, long)} + */ + public static R retries(ThrowsExceptionFunction consumer, int times) throws Exception { + return retries(consumer, times, DEFAULT_WAIT_TIME); + } + + /** + *

重试函数

+ * {@link RetryUtil#retries(ThrowsExceptionFunction, int, long)}的重载,默认重试次数为{@link RetryUtil#DEFAULT_TIMES},重试间隔为{@link RetryUtil#DEFAULT_WAIT_TIME}
+ * 详情参见{@link RetryUtil#retries(ThrowsExceptionFunction, int, long)} + */ + public static R retries(ThrowsExceptionFunction consumer) throws Exception { + return retries(consumer, DEFAULT_TIMES, DEFAULT_WAIT_TIME); + } + + public static void main(String[] args) { + for (int i = 0; i < 5; i++) { + log.info("第" + (i + 1) + "次测试开始......"); + test(); + log.info("\n\n"); + } + } + + /** + * 模拟除0异常测试函数 + */ + private static void test() { + try { + int result = RetryUtil.retries((i) -> { + int randomInt = RandomUtil.randomInt(0, 2); // 生成0或1,模拟除0异常 + int num = 10; + log.info("尝试计算" + num + "除以" + randomInt + "的结果......"); + return num / randomInt; + }, 2, 1000); + log.info("最终结果:" + result); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } +} diff --git a/milkbox-common/src/main/java/top/milkbox/common/utils/base/ThrowsExceptionFunction.java b/milkbox-common/src/main/java/top/milkbox/common/utils/base/ThrowsExceptionFunction.java new file mode 100644 index 0000000..a488071 --- /dev/null +++ b/milkbox-common/src/main/java/top/milkbox/common/utils/base/ThrowsExceptionFunction.java @@ -0,0 +1,28 @@ +package top.milkbox.common.utils.base; + +import java.util.Objects; + +/** + * 可以抛出异常的Function,由{@link java.util.function.Function}改造而来 + * + * @param 参数类型 + */ +@FunctionalInterface +public interface ThrowsExceptionFunction { + + R apply(T t) throws Exception; + + default ThrowsExceptionFunction compose(ThrowsExceptionFunction before) { + Objects.requireNonNull(before); + return (V v) -> apply(before.apply(v)); + } + + default ThrowsExceptionFunction andThen(ThrowsExceptionFunction after) { + Objects.requireNonNull(after); + return (T t) -> after.apply(apply(t)); + } + + static ThrowsExceptionFunction identity() { + return t -> t; + } +} diff --git "a/\345\244\207\345\277\230\345\275\225.md" "b/\345\244\207\345\277\230\345\275\225.md" index 22b3f43..a3afd64 100644 --- "a/\345\244\207\345\277\230\345\275\225.md" +++ "b/\345\244\207\345\277\230\345\275\225.md" @@ -11,7 +11,7 @@ - [ ] 检查枚举中的toString方法是否多余。 - [ ] 检查枚举在代码与字符不同的情况下,用于param是否正确(字符串是否可以正确转换为枚举) - [ ] 考虑数据翻译。两种方式: - 1. 使用easyTrans,在公共模块中创建sysUser实体以及其响应的mybatisplus操作,用来统一翻译创建人和修改人。由于公共模块被所有业务模块依赖,所以在各个业务模块中可以拿到公共模块中的sysUser,就可以对其他人员姓名字段进行翻译。如果关系到用户的角色名或者用户的部门名,可以尝试easyTrans是否可以递归深层翻译 + 1. 使用easyTrans,在公共模块中创建sysUser实体以及其相应的mybatisplus操作,用来统一翻译创建人和修改人。由于公共模块被所有业务模块依赖,所以在各个业务模块中可以拿到公共模块中的sysUser,就可以对其他人员姓名字段进行翻译。如果关系到用户的角色名或者用户的部门名,可以尝试easyTrans是否可以递归深层翻译 2. 使用easyTrans,调整项目的分包方式,放弃业务单独分模块,所有业务模块都放在一个模块中。 - [ ] 尝试将dev和sys两个模块合并,因为目前感觉dev中的功能并不多,没必要单独拆分 -- Gitee From 8ec4edbfa884757da0ef3bfadeeed6a3aae9e3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Thu, 17 Oct 2024 18:24:07 +0800 Subject: [PATCH 07/10] =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../milkbox/core/handler/GlobalControllerAdvice.java | 5 +++-- .../java/top/milkbox/common/pojo/CommonResult.java | 6 ++++++ .../java/top/milkbox/common/utils/RetryUtil.java | 12 ++++++------ .../sys/modular/menu/entity/SysMenuEntity.java | 10 +++++++++- .../sys/modular/menu/param/SysMenuAddParam.java | 9 ++++++++- .../sys/modular/menu/param/SysMenuEditParam.java | 9 ++++++++- .../sys/modular/menu/param/SysMenuPageParam.java | 9 ++++++++- .../top/milkbox/sys/modular/menu/vo/SysMenuVo.java | 9 ++++++++- .../user/service/impl/SysUserServiceImpl.java | 2 +- 9 files changed, 57 insertions(+), 14 deletions(-) diff --git a/milkbox-app/src/main/java/top/milkbox/core/handler/GlobalControllerAdvice.java b/milkbox-app/src/main/java/top/milkbox/core/handler/GlobalControllerAdvice.java index 638f4cd..1ad6efd 100644 --- a/milkbox-app/src/main/java/top/milkbox/core/handler/GlobalControllerAdvice.java +++ b/milkbox-app/src/main/java/top/milkbox/core/handler/GlobalControllerAdvice.java @@ -58,8 +58,9 @@ public class GlobalControllerAdvice { // 服务层业务逻辑异常 if (exception instanceof CommonServiceException commonServiceException) { - return new CommonResult<>(CommonStatusCodeEnum.ERROR506.getCode(), - CommonStatusCodeEnum.ERROR506.getMessage(), commonServiceException.getMessage()); + return CommonResult.create() + .withCode(CommonStatusCodeEnum.ERROR506.getCode()) + .withMessage(commonServiceException.getMessage()); } // 用户未登录异常处理 diff --git a/milkbox-common/src/main/java/top/milkbox/common/pojo/CommonResult.java b/milkbox-common/src/main/java/top/milkbox/common/pojo/CommonResult.java index 641331b..35febeb 100644 --- a/milkbox-common/src/main/java/top/milkbox/common/pojo/CommonResult.java +++ b/milkbox-common/src/main/java/top/milkbox/common/pojo/CommonResult.java @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.With; import top.milkbox.common.enums.CommonStatusCodeEnum; import java.io.Serializable; @@ -15,6 +16,7 @@ import java.io.Serializable; * @author milkbox */ @Data +@With @NoArgsConstructor @AllArgsConstructor public class CommonResult implements Serializable { @@ -30,6 +32,10 @@ public class CommonResult implements Serializable { @Schema(description = "返回的数据") private ResultType data; + public static CommonResult create() { + return new CommonResult<>(); + } + public static CommonResult ok() { return CommonResult.ok(null); } diff --git a/milkbox-common/src/main/java/top/milkbox/common/utils/RetryUtil.java b/milkbox-common/src/main/java/top/milkbox/common/utils/RetryUtil.java index 554b844..9d631fe 100644 --- a/milkbox-common/src/main/java/top/milkbox/common/utils/RetryUtil.java +++ b/milkbox-common/src/main/java/top/milkbox/common/utils/RetryUtil.java @@ -1,10 +1,8 @@ package top.milkbox.common.utils; -import cn.hutool.core.util.RandomUtil; import lombok.extern.slf4j.Slf4j; import top.milkbox.common.utils.base.ThrowsExceptionFunction; -import java.util.ArrayList; import java.util.concurrent.TimeUnit; /** @@ -50,17 +48,18 @@ public class RetryUtil { return retriesFunction.apply(i); } catch (Exception e) { if (i >= times) { - log.error(">>>>>>>>>>>>>>>> 重试次数耗尽,相应的操作失败!"); + log.error("重试次数耗尽,相应的操作失败!"); throw e; // 抛出原异常,并结束循环 } i++; + log.warn(e.getMessage(), e); if (waitTime > 0) { // 保留两位小数 - log.warn(String.format(">>>>>>>>>>>>>>>> %.2f秒后重试......", (float) (waitTime) / 1000)); + log.warn(String.format("%.2f秒后重试......", (float) (waitTime) / 1000)); // 本质上还是Thread.sleep(waitTime),只不过不需要处理异常,且当时间小于等于0的时候不会执行休眠操作 TimeUnit.MILLISECONDS.sleep(waitTime); } - log.warn(">>>>>>>>>>>>>>>> 正在重试({}/{})......", i, times); + log.warn("正在重试({}/{})......", i, times); } } } @@ -97,7 +96,7 @@ public class RetryUtil { private static void test() { try { int result = RetryUtil.retries((i) -> { - int randomInt = RandomUtil.randomInt(0, 2); // 生成0或1,模拟除0异常 + int randomInt = (int) (Math.random() * 2); // 生成0或1,模拟除0异常 int num = 10; log.info("尝试计算" + num + "除以" + randomInt + "的结果......"); return num / randomInt; @@ -107,4 +106,5 @@ public class RetryUtil { log.error(e.getMessage(), e); } } + } diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/entity/SysMenuEntity.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/entity/SysMenuEntity.java index 8ec44ac..5c1fd00 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/entity/SysMenuEntity.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/entity/SysMenuEntity.java @@ -67,7 +67,7 @@ public class SysMenuEntity extends CommonEntity implements CommonUtil.EntityTree @Schema(title = "组件的导包路径", description = "组件的导包路径。相对于组件的基准目录,基准目录单独配置,开头不加反斜杠") @TableField(updateStrategy = FieldStrategy.ALWAYS) - private String component; + private String componentPath; /** * 相对于父级的路由地址;开头要加反斜杠,可以多级 @@ -93,6 +93,14 @@ public class SysMenuEntity extends CommonEntity implements CommonUtil.EntityTree @TableField(typeHandler = JacksonTypeHandler.class, updateStrategy = FieldStrategy.ALWAYS) private Object extend; + /** + * 布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效 + */ + @Schema(title = "布局页面的组件名称", + description = "布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效") + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private String layoutName; + /** * 是否可见;隐藏后可以访问页面,但不在菜单列表显示。1可见,0不可见 */ diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuAddParam.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuAddParam.java index 08d4bfe..3449c45 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuAddParam.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuAddParam.java @@ -51,7 +51,7 @@ public class SysMenuAddParam implements Serializable { */ @Schema(title = "组件的导包路径", description = "组件的导包路径。相对于组件的基准目录,基准目录单独配置,开头不加反斜杠") - private String component; + private String componentPath; /** * 相对于父级的路由地址;开头要加反斜杠,可以多级 @@ -74,6 +74,13 @@ public class SysMenuAddParam implements Serializable { description = "扩展信息。Json格式") private Object extend; + /** + * 布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效 + */ + @Schema(title = "布局页面的组件名称", + description = "布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效") + private String layoutName; + /** * 是否可见;隐藏后可以访问页面,但不在菜单列表显示。1可见,0不可见 */ diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuEditParam.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuEditParam.java index 57cb05f..25c8101 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuEditParam.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuEditParam.java @@ -60,7 +60,7 @@ public class SysMenuEditParam implements Serializable { */ @Schema(title = "组件的导包路径", description = "组件的导包路径。相对于组件的基准目录,基准目录单独配置,开头不加反斜杠") - private String component; + private String componentPath; /** * 相对于父级的路由地址;开头要加反斜杠,可以多级 @@ -83,6 +83,13 @@ public class SysMenuEditParam implements Serializable { description = "扩展信息。Json格式") private Object extend; + /** + * 布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效 + */ + @Schema(title = "布局页面的组件名称", + description = "布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效") + private String layoutName; + /** * 是否可见;隐藏后可以访问页面,但不在菜单列表显示。1可见,0不可见 */ diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuPageParam.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuPageParam.java index 6cbbc4d..e65b0ca 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuPageParam.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuPageParam.java @@ -49,7 +49,7 @@ public class SysMenuPageParam extends CommonPageParam implements Serializable { */ @Schema(title = "组件的导包路径", description = "组件的导包路径。相对于组件的基准目录,基准目录单独配置,开头不加反斜杠") - private String component; + private String componentPath; /** * 相对于父级的路由地址;开头要加反斜杠,可以多级 @@ -72,6 +72,13 @@ public class SysMenuPageParam extends CommonPageParam implements Serializable { description = "扩展信息。Json格式") private Object extend; + /** + * 布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效 + */ + @Schema(title = "布局页面的组件名称", + description = "布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效") + private String layoutName; + /** * 是否可见;隐藏后可以访问页面,但不在菜单列表显示。1可见,0不可见 */ diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java index 75d62a3..87c47cd 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java @@ -57,7 +57,7 @@ public class SysMenuVo extends CommonVo implements Serializable { */ @Schema(title = "组件的导包路径", description = "组件的导包路径。相对于组件的基准目录,基准目录单独配置,开头不加反斜杠") - private String component; + private String componentPath; /** * 相对于父级的路由地址;开头要加反斜杠,可以多级 @@ -80,6 +80,13 @@ public class SysMenuVo extends CommonVo implements Serializable { description = "扩展信息。Json格式") private Object extend; + /** + * 布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效 + */ + @Schema(title = "布局页面的组件名称", + description = "布局页面的组件名称。布局页面的组件名称,表示当前记录在哪个布局页面内。仅顶级有效") + private String layoutName; + /** * 是否可见;隐藏后可以访问页面,但不在菜单列表显示。1可见,0不可见 */ diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/user/service/impl/SysUserServiceImpl.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/user/service/impl/SysUserServiceImpl.java index dad219b..2313d7c 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/user/service/impl/SysUserServiceImpl.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/user/service/impl/SysUserServiceImpl.java @@ -163,7 +163,7 @@ public class SysUserServiceImpl extends CommonServiceImpl Date: Mon, 21 Oct 2024 18:20:11 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E8=8F=9C=E5=8D=95=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../top/milkbox/sys/modular/menu/entity/SysMenuEntity.java | 4 ++-- .../top/milkbox/sys/modular/menu/enums/SysMenuTypeEnum.java | 2 +- .../top/milkbox/sys/modular/menu/param/SysMenuAddParam.java | 4 ++-- .../top/milkbox/sys/modular/menu/param/SysMenuEditParam.java | 4 ++-- .../top/milkbox/sys/modular/menu/param/SysMenuPageParam.java | 4 ++-- .../main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/entity/SysMenuEntity.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/entity/SysMenuEntity.java index 5c1fd00..2f2a583 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/entity/SysMenuEntity.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/entity/SysMenuEntity.java @@ -110,10 +110,10 @@ public class SysMenuEntity extends CommonEntity implements CommonUtil.EntityTree private Boolean isShow; /** - * 类型;菜单MENU或目录CATALOG + * 类型;页面PAGE或目录CATALOG */ @Schema(title = "类型", - description = "类型。菜单MENU或目录CATALOG") + description = "类型;页面PAGE或目录CATALOG") @TableField(updateStrategy = FieldStrategy.ALWAYS) private SysMenuTypeEnum type; diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/enums/SysMenuTypeEnum.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/enums/SysMenuTypeEnum.java index a67bfa2..4ab244f 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/enums/SysMenuTypeEnum.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/enums/SysMenuTypeEnum.java @@ -13,7 +13,7 @@ import lombok.AllArgsConstructor; @AllArgsConstructor // 如果使用此注解,请勿随意修改成员变量的定义顺序 public enum SysMenuTypeEnum { - MENU("菜单", "MENU"), + MENU("页面", "PAGE"), CATALOG("目录", "CATALOG"); private final String label; diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuAddParam.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuAddParam.java index 3449c45..89d175a 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuAddParam.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuAddParam.java @@ -89,10 +89,10 @@ public class SysMenuAddParam implements Serializable { private Boolean isShow; /** - * 类型;菜单MENU或目录CATALOG + * 类型;页面PAGE或目录CATALOG */ @Schema(title = "类型", - description = "类型。菜单MENU或目录CATALOG") + description = "类型;页面PAGE或目录CATALOG") private SysMenuTypeEnum type; /** diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuEditParam.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuEditParam.java index 25c8101..5862807 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuEditParam.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuEditParam.java @@ -98,10 +98,10 @@ public class SysMenuEditParam implements Serializable { private Boolean isShow; /** - * 类型;菜单MENU或目录CATALOG + * 类型;页面PAGE或目录CATALOG */ @Schema(title = "类型", - description = "类型。菜单MENU或目录CATALOG") + description = "类型;页面PAGE或目录CATALOG") private SysMenuTypeEnum type; /** diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuPageParam.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuPageParam.java index e65b0ca..4315530 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuPageParam.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/param/SysMenuPageParam.java @@ -87,10 +87,10 @@ public class SysMenuPageParam extends CommonPageParam implements Serializable { private Boolean isShow; /** - * 类型;菜单MENU或目录CATALOG + * 类型;页面PAGE或目录CATALOG */ @Schema(title = "类型", - description = "类型。菜单MENU或目录CATALOG") + description = "类型;页面PAGE或目录CATALOG") private SysMenuTypeEnum type; /** diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java index 87c47cd..d12bfaa 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/vo/SysMenuVo.java @@ -95,10 +95,10 @@ public class SysMenuVo extends CommonVo implements Serializable { private Boolean isShow; /** - * 类型;菜单MENU或目录CATALOG + * 类型;页面PAGE或目录CATALOG */ @Schema(title = "类型", - description = "类型。菜单MENU或目录CATALOG") + description = "类型;页面PAGE或目录CATALOG") private SysMenuTypeEnum type; /** -- Gitee From 7d0f63c56edfa87c0b3b48d8bf5562efdd00d330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Tue, 29 Oct 2024 18:19:19 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=89=80=E6=9C=89?= =?UTF-8?q?=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/top/milkbox/common/utils/CommonUtil.java | 3 +-- .../sys/modular/menu/controller/SysMenuController.java | 9 +++++++++ .../milkbox/sys/modular/menu/service/SysMenuService.java | 7 +++++++ .../modular/menu/service/impl/SysMenuServiceImpl.java | 5 +++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/milkbox-common/src/main/java/top/milkbox/common/utils/CommonUtil.java b/milkbox-common/src/main/java/top/milkbox/common/utils/CommonUtil.java index 1f51979..7296502 100644 --- a/milkbox-common/src/main/java/top/milkbox/common/utils/CommonUtil.java +++ b/milkbox-common/src/main/java/top/milkbox/common/utils/CommonUtil.java @@ -34,8 +34,7 @@ public class CommonUtil { * @return 返回森林 * @author 郭泳辰 */ - public static > List> toTree( - List sourceList, S rootId) { + public static > List> toTree(List sourceList, S rootId) { // 将OkrNormCategory集合对象转为TreeNode集合对象 List> treeNodeList = sourceList.stream().map(treeNode -> { if (ObjectUtil.isEmpty(treeNode.getParentId())) { diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/controller/SysMenuController.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/controller/SysMenuController.java index f06f1d8..bf87c3b 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/controller/SysMenuController.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/controller/SysMenuController.java @@ -111,4 +111,13 @@ public class SysMenuController { return CommonResult.ok(sysMenuService.forest()); } + // TODO 应设较高权限 + @GetMapping("/forestAll") + @Operation(summary = "获取所有菜单森林", description = "获取所有菜单森林") + @CommonLog(value = "获取所有菜单森林", description = "获取所有菜单森林", + module = SysConfiguration.MODULE_NAME, type = LogTypeEnum.SELECT) + public CommonResult>> forestAll() { + return CommonResult.ok(sysMenuService.forestAll()); + } + } \ No newline at end of file diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/SysMenuService.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/SysMenuService.java index 6a1e9e8..70fa65c 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/SysMenuService.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/SysMenuService.java @@ -91,4 +91,11 @@ public interface SysMenuService extends CommonService { * @return 菜单森林 */ List> forest(); + + /** + * 获取所有菜单森林 + * + * @return 菜单森林 + */ + List> forestAll(); } \ No newline at end of file diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/impl/SysMenuServiceImpl.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/impl/SysMenuServiceImpl.java index 9118070..9ea0cbe 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/impl/SysMenuServiceImpl.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/service/impl/SysMenuServiceImpl.java @@ -231,4 +231,9 @@ public class SysMenuServiceImpl extends CommonServiceImpl> forestAll() { + return CommonUtil.toTree(super.list(), 0); + } + } \ No newline at end of file -- Gitee From 0ce1c65de86fef274935d8434850919dc388dfb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=B3=B3=E8=BE=B0?= <312189607@qq.com> Date: Thu, 31 Oct 2024 10:42:55 +0800 Subject: [PATCH 10/10] =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../milkbox/sys/modular/menu/controller/SysMenuController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/controller/SysMenuController.java b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/controller/SysMenuController.java index bf87c3b..c4fd28a 100644 --- a/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/controller/SysMenuController.java +++ b/milkbox-service/service-sys/src/main/java/top/milkbox/sys/modular/menu/controller/SysMenuController.java @@ -112,6 +112,7 @@ public class SysMenuController { } // TODO 应设较高权限 + // TODO 这里的菜单应该具有条件查询功能,在查询的时候需要注意通过结果查询其上级,最终构建一棵树 @GetMapping("/forestAll") @Operation(summary = "获取所有菜单森林", description = "获取所有菜单森林") @CommonLog(value = "获取所有菜单森林", description = "获取所有菜单森林", -- Gitee