Commit 44ba975041d2ccd6be90ef41ba693ce6bd2000a6

Authored by shaofan
1 parent 3924c536

添加小程序菜单相关接口及Magic API集成支持

引入Magic API框架并配置动态数据源,新增获取、添加、修改小程序菜单的相关接口实现。更新Application配置以支持Magic API,优化数据查询及事务逻辑。
boss-boot/src/main/resources/application.properties
... ... @@ -8,4 +8,8 @@ mybatis.configuration.map-underscore-to-camel-case=true
8 8 mybatis.configuration.use-column-label=true
9 9 mybatis.configuration.default-statement-timeout=25000
10 10 mybatis.mapper-locations=classpath*:com/diligrp/boss/dao/mapper/**/*.xml
11   -mybatis.configuration.default-enum-type-handler=com.diligrp.boss.shared.mybatis.GenericEnumTypeHandler
12 11 \ No newline at end of file
  12 +mybatis.configuration.default-enum-type-handler=com.diligrp.boss.shared.mybatis.GenericEnumTypeHandler
  13 +
  14 +magic-api.web=/magic/web
  15 +magic-api.resource.location=classpath:/data/magic-api/
  16 +magic-api.sql-column-case=camel
13 17 \ No newline at end of file
... ...
boss-boot/src/main/resources/data/magic-api/api/api/group.json 0 → 100644
  1 +{
  2 + "properties" : { },
  3 + "id" : "4785b4de9dfc49f59ddc0642305dbbc7",
  4 + "name" : "api",
  5 + "type" : "api",
  6 + "parentId" : "0",
  7 + "path" : "api",
  8 + "createTime" : 1736230531514,
  9 + "updateTime" : null,
  10 + "createBy" : null,
  11 + "updateBy" : null,
  12 + "paths" : [ ],
  13 + "options" : [ ]
  14 +}
0 15 \ No newline at end of file
... ...
boss-boot/src/main/resources/data/magic-api/api/api/修改小程序菜单.ms 0 → 100644
  1 +{
  2 + "properties" : { },
  3 + "id" : "ae25d0a4b6cd4714bf0348f8d387d3a8",
  4 + "script" : null,
  5 + "groupId" : "4785b4de9dfc49f59ddc0642305dbbc7",
  6 + "name" : "修改小程序菜单",
  7 + "createTime" : null,
  8 + "updateTime" : 1736737065617,
  9 + "lock" : null,
  10 + "createBy" : null,
  11 + "updateBy" : null,
  12 + "path" : "updateWXPermission",
  13 + "method" : "POST",
  14 + "parameters" : [ ],
  15 + "options" : [ ],
  16 + "requestBody" : "",
  17 + "headers" : [ ],
  18 + "paths" : [ ],
  19 + "responseBody" : null,
  20 + "description" : null,
  21 + "requestBodyDefinition" : null,
  22 + "responseBodyDefinition" : null
  23 +}
  24 +================================
  25 +if (body) {
  26 + // 取出按钮数据并清空 body 中对应的字段
  27 + var btn = body.btn || null;
  28 + if (btn) {
  29 + body.btn = null; // 移除 btn,确保保存时无多余字段
  30 + }
  31 +
  32 + return db["slave"].transaction(() => {
  33 + // 修改主对象数据
  34 + var result = db["slave"]
  35 + .table("permission")
  36 + .primary("id")
  37 + .save(body);
  38 +
  39 + // 修改子权限(按钮)
  40 + if (btn) {
  41 + btn.each(item => {
  42 + db["slave"]
  43 + .table("permission")
  44 + .primary("id")
  45 + .save({
  46 + id: item.id,
  47 + name: item.name,
  48 + perms: item.perms,
  49 + module: body.module,
  50 + parentId: body.id,
  51 + state: body.state,
  52 + type: "F"
  53 + });
  54 + });
  55 +
  56 + }
  57 +
  58 + return result; // 返回主对象保存结果ID
  59 + });
  60 +}
  61 +
  62 +return 0;
0 63 \ No newline at end of file
... ...
boss-boot/src/main/resources/data/magic-api/api/api/新增小程序菜单.ms 0 → 100644
  1 +{
  2 + "properties" : { },
  3 + "id" : "2edd6c0be3424399b3441a253ecc95fb",
  4 + "script" : null,
  5 + "groupId" : "4785b4de9dfc49f59ddc0642305dbbc7",
  6 + "name" : "新增小程序菜单",
  7 + "createTime" : null,
  8 + "updateTime" : 1736737047991,
  9 + "lock" : null,
  10 + "createBy" : null,
  11 + "updateBy" : null,
  12 + "path" : "addWXPermission",
  13 + "method" : "POST",
  14 + "parameters" : [ ],
  15 + "options" : [ ],
  16 + "requestBody" : "{\r\n \"type\": \"M\",\r\n \"module\": \"app\",\r\n \"state\": \"1\",\r\n \"name\": \"11\",\r\n \"btn\": [\r\n {\r\n \"perms\": \"22\",\r\n \"name\": \"22\"\r\n }\r\n ],\r\n \"parentId\": \"\"\r\n}",
  17 + "headers" : [ ],
  18 + "paths" : [ ],
  19 + "responseBody" : "{\n \"code\": 1,\n \"message\": \"success\",\n \"data\": 1,\n \"timestamp\": 1736318602702,\n \"executeTime\": 314\n}",
  20 + "description" : null,
  21 + "requestBodyDefinition" : null,
  22 + "responseBodyDefinition" : {
  23 + "name" : "",
  24 + "value" : "",
  25 + "description" : "",
  26 + "required" : false,
  27 + "dataType" : "Object",
  28 + "type" : null,
  29 + "defaultValue" : null,
  30 + "validateType" : "",
  31 + "error" : "",
  32 + "expression" : "",
  33 + "children" : [ {
  34 + "name" : "code",
  35 + "value" : "-1",
  36 + "description" : "",
  37 + "required" : false,
  38 + "dataType" : "Integer",
  39 + "type" : null,
  40 + "defaultValue" : null,
  41 + "validateType" : "",
  42 + "error" : "",
  43 + "expression" : "",
  44 + "children" : [ ]
  45 + }, {
  46 + "name" : "message",
  47 + "value" : "系统内部出现错误",
  48 + "description" : "",
  49 + "required" : false,
  50 + "dataType" : "String",
  51 + "type" : null,
  52 + "defaultValue" : null,
  53 + "validateType" : "",
  54 + "error" : "",
  55 + "expression" : "",
  56 + "children" : [ ]
  57 + }, {
  58 + "name" : "timestamp",
  59 + "value" : "1736234673528",
  60 + "description" : "",
  61 + "required" : false,
  62 + "dataType" : "Long",
  63 + "type" : null,
  64 + "defaultValue" : null,
  65 + "validateType" : "",
  66 + "error" : "",
  67 + "expression" : "",
  68 + "children" : [ ]
  69 + }, {
  70 + "name" : "executeTime",
  71 + "value" : "85",
  72 + "description" : "",
  73 + "required" : false,
  74 + "dataType" : "Integer",
  75 + "type" : null,
  76 + "defaultValue" : null,
  77 + "validateType" : "",
  78 + "error" : "",
  79 + "expression" : "",
  80 + "children" : [ ]
  81 + } ]
  82 + }
  83 +}
  84 +================================
  85 +if (body) {
  86 + // 取出按钮数据并清空 body 中对应的字段
  87 + var btn = body.btn || null;
  88 + if (btn) {
  89 + body.btn = null; // 移除 btn,确保保存时无多余字段
  90 + }
  91 +
  92 + return db["slave"].transaction(() => {
  93 + // 保存主对象数据
  94 + var result = db["slave"]
  95 + .table("permission")
  96 + .primary("id")
  97 + .save(body);
  98 +
  99 + // 保存子权限(按钮)
  100 + if (btn) {
  101 + var btnList = btn.map(item => ({
  102 + name: item.name,
  103 + perms: item.perms,
  104 + module: body.module,
  105 + parentId: result,
  106 + state: body.state,
  107 + type: "F"
  108 + }));
  109 + db["slave"].table("permission").batchInsert(Arrays.asList(btnList));
  110 + }
  111 +
  112 + return result; // 返回主对象保存结果ID
  113 + });
  114 +}
  115 +
  116 +return 0;
0 117 \ No newline at end of file
... ...
boss-boot/src/main/resources/data/magic-api/api/api/获取小程序菜单列表.ms 0 → 100644
  1 +{
  2 + "properties" : { },
  3 + "id" : "84221554f7b942a98b44aeff67937ff7",
  4 + "script" : null,
  5 + "groupId" : "4785b4de9dfc49f59ddc0642305dbbc7",
  6 + "name" : "获取小程序菜单列表",
  7 + "createTime" : null,
  8 + "updateTime" : 1736319305474,
  9 + "lock" : null,
  10 + "createBy" : null,
  11 + "updateBy" : null,
  12 + "path" : "listWXPermission",
  13 + "method" : "GET",
  14 + "parameters" : [ {
  15 + "name" : "page",
  16 + "value" : "1",
  17 + "description" : null,
  18 + "required" : true,
  19 + "dataType" : "Integer",
  20 + "type" : null,
  21 + "defaultValue" : null,
  22 + "validateType" : null,
  23 + "error" : null,
  24 + "expression" : null,
  25 + "children" : null
  26 + }, {
  27 + "name" : "perPage",
  28 + "value" : "10",
  29 + "description" : null,
  30 + "required" : true,
  31 + "dataType" : "Integer",
  32 + "type" : null,
  33 + "defaultValue" : null,
  34 + "validateType" : null,
  35 + "error" : null,
  36 + "expression" : null,
  37 + "children" : null
  38 + } ],
  39 + "options" : [ ],
  40 + "requestBody" : "",
  41 + "headers" : [ ],
  42 + "paths" : [ ],
  43 + "responseBody" : "{\n \"code\": 1,\n \"message\": \"success\",\n \"data\": {\n \"page\": 1,\n \"pageSize\": 10,\n \"total\": 4,\n \"data\": [\n {\n \"id\": 1,\n \"name\": \"系统设置\",\n \"module\": \"app\",\n \"type\": \"M\",\n \"state\": 1,\n \"children\": []\n },\n {\n \"id\": 2,\n \"name\": \"测试菜单\",\n \"module\": \"app\",\n \"type\": \"C\",\n \"state\": 1,\n \"children\": []\n },\n {\n \"id\": 3,\n \"name\": \"aaa\",\n \"module\": \"app\",\n \"type\": \"C\",\n \"state\": 1,\n \"children\": []\n },\n {\n \"id\": 4,\n \"name\": \"cc\",\n \"module\": \"app\",\n \"type\": \"M\",\n \"state\": 1,\n \"children\": [\n {\n \"id\": 5,\n \"parentId\": 4,\n \"name\": \"dd\",\n \"module\": \"app\",\n \"type\": \"M\",\n \"state\": 1,\n \"children\": []\n }\n ]\n }\n ]\n },\n \"timestamp\": 1736246946523,\n \"executeTime\": 579\n}",
  44 + "description" : null,
  45 + "requestBodyDefinition" : null,
  46 + "responseBodyDefinition" : {
  47 + "name" : "",
  48 + "value" : "",
  49 + "description" : "",
  50 + "required" : false,
  51 + "dataType" : "Object",
  52 + "type" : null,
  53 + "defaultValue" : null,
  54 + "validateType" : "",
  55 + "error" : "",
  56 + "expression" : "",
  57 + "children" : [ {
  58 + "name" : "code",
  59 + "value" : "1",
  60 + "description" : "",
  61 + "required" : false,
  62 + "dataType" : "Integer",
  63 + "type" : null,
  64 + "defaultValue" : null,
  65 + "validateType" : "",
  66 + "error" : "",
  67 + "expression" : "",
  68 + "children" : [ ]
  69 + }, {
  70 + "name" : "message",
  71 + "value" : "success",
  72 + "description" : "",
  73 + "required" : false,
  74 + "dataType" : "String",
  75 + "type" : null,
  76 + "defaultValue" : null,
  77 + "validateType" : "",
  78 + "error" : "",
  79 + "expression" : "",
  80 + "children" : [ ]
  81 + }, {
  82 + "name" : "data",
  83 + "value" : "",
  84 + "description" : "",
  85 + "required" : false,
  86 + "dataType" : "Array",
  87 + "type" : null,
  88 + "defaultValue" : null,
  89 + "validateType" : "",
  90 + "error" : "",
  91 + "expression" : "",
  92 + "children" : [ {
  93 + "name" : "",
  94 + "value" : "",
  95 + "description" : "",
  96 + "required" : false,
  97 + "dataType" : "Object",
  98 + "type" : null,
  99 + "defaultValue" : null,
  100 + "validateType" : "",
  101 + "error" : "",
  102 + "expression" : "",
  103 + "children" : [ {
  104 + "name" : "id",
  105 + "value" : "1",
  106 + "description" : "",
  107 + "required" : false,
  108 + "dataType" : "Integer",
  109 + "type" : null,
  110 + "defaultValue" : null,
  111 + "validateType" : "",
  112 + "error" : "",
  113 + "expression" : "",
  114 + "children" : [ ]
  115 + }, {
  116 + "name" : "parent_id",
  117 + "value" : "0",
  118 + "description" : "",
  119 + "required" : false,
  120 + "dataType" : "Integer",
  121 + "type" : null,
  122 + "defaultValue" : null,
  123 + "validateType" : "",
  124 + "error" : "",
  125 + "expression" : "",
  126 + "children" : [ ]
  127 + }, {
  128 + "name" : "name",
  129 + "value" : "基础设置",
  130 + "description" : "",
  131 + "required" : false,
  132 + "dataType" : "String",
  133 + "type" : null,
  134 + "defaultValue" : null,
  135 + "validateType" : "",
  136 + "error" : "",
  137 + "expression" : "",
  138 + "children" : [ ]
  139 + }, {
  140 + "name" : "group",
  141 + "value" : "app",
  142 + "description" : "",
  143 + "required" : false,
  144 + "dataType" : "String",
  145 + "type" : null,
  146 + "defaultValue" : null,
  147 + "validateType" : "",
  148 + "error" : "",
  149 + "expression" : "",
  150 + "children" : [ ]
  151 + }, {
  152 + "name" : "type",
  153 + "value" : "m",
  154 + "description" : "",
  155 + "required" : false,
  156 + "dataType" : "String",
  157 + "type" : null,
  158 + "defaultValue" : null,
  159 + "validateType" : "",
  160 + "error" : "",
  161 + "expression" : "",
  162 + "children" : [ ]
  163 + }, {
  164 + "name" : "state",
  165 + "value" : "1",
  166 + "description" : "",
  167 + "required" : false,
  168 + "dataType" : "Integer",
  169 + "type" : null,
  170 + "defaultValue" : null,
  171 + "validateType" : "",
  172 + "error" : "",
  173 + "expression" : "",
  174 + "children" : [ ]
  175 + } ]
  176 + } ]
  177 + }, {
  178 + "name" : "timestamp",
  179 + "value" : "1736230864666",
  180 + "description" : "",
  181 + "required" : false,
  182 + "dataType" : "Long",
  183 + "type" : null,
  184 + "defaultValue" : null,
  185 + "validateType" : "",
  186 + "error" : "",
  187 + "expression" : "",
  188 + "children" : [ ]
  189 + }, {
  190 + "name" : "executeTime",
  191 + "value" : "830",
  192 + "description" : "",
  193 + "required" : false,
  194 + "dataType" : "Integer",
  195 + "type" : null,
  196 + "defaultValue" : null,
  197 + "validateType" : "",
  198 + "error" : "",
  199 + "expression" : "",
  200 + "children" : [ ]
  201 + } ]
  202 + }
  203 +}
  204 +================================
  205 +// 分页参数:从请求中获取 `page` 和 `pageSize` 参数
  206 +var page = page ? page : 1; // 默认为第 1 页
  207 +var pageSize = perPage ? perPage : 10; // 每页默认 10 条
  208 +
  209 +// 计算分页的偏移量
  210 +var offset = (page - 1) * pageSize;
  211 +
  212 +// 查询顶级权限并分页
  213 +var parent = db.slave.select(
  214 + `SELECT * FROM permission
  215 + WHERE module = 'app' AND (parent_id IS NULL OR parent_id = 0) AND type != 'F'
  216 + LIMIT #{pageSize} OFFSET #{offset}`, {
  217 + pageSize: pageSize,
  218 + offset: offset
  219 + } // 参数绑定
  220 +);
  221 +
  222 +// 定义递归函数:查询子权限及其所有子权限
  223 +var findChildren = (parentId) => {
  224 + // 查询当前权限的直接子权限
  225 + var children = db.slave.select(
  226 + `SELECT * FROM permission WHERE parent_id = #{parentId} AND type != 'F'`, {
  227 + parentId: parentId
  228 + }
  229 + );
  230 +
  231 + // 如果有子权限,继续递归查询
  232 + if (children && children.length > 0) {
  233 + children.forEach(child => {
  234 + // 递归写入子权限的 children 字段
  235 + child.children = findChildren(child.id);
  236 + });
  237 + }
  238 +
  239 + return children; // 返回子权限
  240 +};
  241 +
  242 +// 如果有顶级权限,递归查询子权限
  243 +if (parent) {
  244 + parent.forEach(item => {
  245 + item.children = findChildren(item.id); // 递归查询该顶级权限的子权限
  246 + });
  247 +}
  248 +
  249 +// 查询总顶级权限记录数(用于分页返回)
  250 +var total = db.slave.selectOne(
  251 + `SELECT COUNT(*) AS total
  252 + FROM permission
  253 + WHERE module = 'app' AND (parent_id IS NULL OR parent_id = 0) AND type != 'F'`
  254 +).total;
  255 +
  256 +// 返回分页结果
  257 +return {
  258 + page: page,
  259 + pageSize: pageSize,
  260 + total: total,
  261 + data: parent // 当前页数据
  262 +};
0 263 \ No newline at end of file
... ...
boss-boot/src/main/resources/data/magic-api/api/api/获取小程序菜单详情.ms 0 → 100644
  1 +{
  2 + "properties" : { },
  3 + "id" : "9f412c90bffa4561b70784abba10f628",
  4 + "script" : null,
  5 + "groupId" : "4785b4de9dfc49f59ddc0642305dbbc7",
  6 + "name" : "获取小程序菜单详情",
  7 + "createTime" : null,
  8 + "updateTime" : 1736319896807,
  9 + "lock" : null,
  10 + "createBy" : null,
  11 + "updateBy" : null,
  12 + "path" : "getWxPermission",
  13 + "method" : "GET",
  14 + "parameters" : [ {
  15 + "name" : "id",
  16 + "value" : "1",
  17 + "description" : null,
  18 + "required" : true,
  19 + "dataType" : "Long",
  20 + "type" : null,
  21 + "defaultValue" : null,
  22 + "validateType" : "pass",
  23 + "error" : null,
  24 + "expression" : null,
  25 + "children" : null
  26 + } ],
  27 + "options" : [ ],
  28 + "requestBody" : "",
  29 + "headers" : [ ],
  30 + "paths" : [ ],
  31 + "responseBody" : "{\n \"code\": 1,\n \"message\": \"success\",\n \"data\": 0,\n \"timestamp\": 1736319890730,\n \"executeTime\": 19289\n}",
  32 + "description" : null,
  33 + "requestBodyDefinition" : null,
  34 + "responseBodyDefinition" : null
  35 +}
  36 +================================
  37 +var permission = db.slave.selectOne("SELECT * FROM permission WHERE id = #{id}");
  38 +if (permission) {
  39 + var btnList = db.slave.select("SELECT * FROM permission WHERE parent_id = #{id} AND type = 'F'");
  40 + if (btnList) {
  41 + permission.btn = btnList;
  42 + }
  43 + return permission;
  44 +}
  45 +
  46 +
  47 +return 0;
0 48 \ No newline at end of file
... ...
boss-shared/build.gradle
... ... @@ -14,5 +14,6 @@ dependencies {
14 14 api 'com.github.pagehelper:pagehelper-spring-boot-starter:2.1.0'
15 15 api 'org.springframework.boot:spring-boot-starter-validation'
16 16 api 'cn.hutool:hutool-all:5.8.30'
  17 + api 'org.ssssssss:magic-api-spring-boot-starter:2.1.1'
17 18 runtimeOnly 'mysql:mysql-connector-java:8.0.33'
18 19 }
19 20 \ No newline at end of file
... ...
boss-shared/src/main/java/com/diligrp/boss/shared/datasource/DataSourceConfiguration.java
... ... @@ -11,6 +11,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
11 11 import org.springframework.context.annotation.Bean;
12 12 import org.springframework.context.annotation.Configuration;
13 13 import org.springframework.context.annotation.Primary;
  14 +import org.ssssssss.magicapi.datasource.model.MagicDynamicDataSource;
14 15  
15 16 import javax.sql.DataSource;
16 17 import java.util.HashMap;
... ... @@ -28,6 +29,14 @@ public class DataSourceConfiguration {
28 29 }
29 30  
30 31 @Bean
  32 + public MagicDynamicDataSource magicDynamicDataSource() {
  33 + MagicDynamicDataSource dynamicDataSource = new MagicDynamicDataSource();
  34 + dynamicDataSource.setDefault(masterDataSource()); // 设置默认数据源
  35 + dynamicDataSource.add("slave", salveDataSource());
  36 + return dynamicDataSource;
  37 + }
  38 +
  39 + @Bean
31 40 @ConfigurationProperties(prefix = "spring.datasource.hikari")
32 41 public DataSource masterDataSource() {
33 42 HikariDataSource dataSource = new HikariDataSource();
... ... @@ -71,16 +80,16 @@ public class DataSourceConfiguration {
71 80 }
72 81  
73 82 @Pointcut(value = "@annotation(com.diligrp.boss.shared.datasource.DataSourceOption)")
74   - public void dataSourcePointCut(){
  83 + public void dataSourcePointCut() {
75 84 }
76 85  
77 86 @Around("dataSourcePointCut()")
78 87 public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
79 88 DataSourceName name = getMetadata(joinPoint).value();
80   - try{
  89 + try {
81 90 DataSourceNameContext.setDataSourceName(name);
82 91 return joinPoint.proceed();
83   - }finally {
  92 + } finally {
84 93 DataSourceNameContext.removeDataSourceName();
85 94 }
86 95 }
... ...