# 应用管理技术方案 ## 一、功能概述 应用管理模块用于管理接入盘古用户认证中心的第三方应用系统,实现应用注册、密钥管理、接口授权等功能。 ## 二、数据库设计 ### 2.1 ER 关系图 ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ pg_application │ │ pg_app_api │ │ pg_api_dict │ │ (第三方应用表) │ 1───n │ (应用API授权表) │ n───1 │ (API接口字典表) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### 2.2 表结构设计 #### 2.2.1 第三方应用表 (pg_application) | 字段名 | 类型 | 必填 | 说明 | |--------|------|------|------| | app_id | bigint | 是 | 应用ID(主键,雪花算法) | | app_code | varchar(32) | 是 | 应用编码(唯一,格式:YY000001) | | app_name | varchar(100) | 是 | 应用名称 | | app_secret | varchar(100) | 是 | 应用密钥(32位UUID) | | contact_person | varchar(50) | 否 | 联系人 | | contact_phone | varchar(20) | 否 | 联系电话 | | status | char(1) | 是 | 状态(0正常 1停用) | | tenant_id | varchar(20) | 是 | 租户编号 | | create_dept | bigint | 否 | 创建部门 | | create_by | bigint | 否 | 创建者 | | create_time | datetime | 否 | 创建时间 | | update_by | bigint | 否 | 更新者 | | update_time | datetime | 否 | 更新时间 | | del_flag | char(1) | 是 | 删除标志(0存在 1删除) | | remark | varchar(500) | 否 | 备注 | **索引**: - PRIMARY KEY (`app_id`) - UNIQUE KEY `uk_app_code` (`app_code`) #### 2.2.2 API接口字典表 (pg_api_dict) | 字段名 | 类型 | 必填 | 说明 | |--------|------|------|------| | api_id | bigint | 是 | API ID(主键) | | api_code | varchar(50) | 是 | API编码(唯一) | | api_name | varchar(100) | 是 | API名称 | | api_path | varchar(200) | 是 | API路径 | | api_method | varchar(10) | 是 | 请求方法(GET/POST/PUT/DELETE) | | api_desc | varchar(500) | 否 | API描述 | | status | char(1) | 是 | 状态(0正常 1停用) | | order_num | int | 是 | 排序号 | **索引**: - PRIMARY KEY (`api_id`) - UNIQUE KEY `uk_api_code` (`api_code`) #### 2.2.3 应用API授权表 (pg_app_api) | 字段名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | bigint | 是 | 主键 | | app_id | bigint | 是 | 应用ID | | api_id | bigint | 是 | API ID | | create_time | datetime | 否 | 创建时间 | **索引**: - PRIMARY KEY (`id`) - UNIQUE KEY `uk_app_api` (`app_id`, `api_id`) ### 2.3 SQL 脚本 ```sql -- 第三方应用表 DROP TABLE IF EXISTS `pg_application`; CREATE TABLE `pg_application` ( `app_id` bigint NOT NULL COMMENT '应用ID', `app_code` varchar(32) NOT NULL COMMENT '应用编码', `app_name` varchar(100) NOT NULL COMMENT '应用名称', `app_secret` varchar(100) NOT NULL COMMENT '应用密钥', `contact_person` varchar(50) DEFAULT NULL COMMENT '联系人', `contact_phone` varchar(20) DEFAULT NULL COMMENT '联系电话', `status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)', `tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号', `create_dept` bigint DEFAULT NULL COMMENT '创建部门', `create_by` bigint DEFAULT NULL COMMENT '创建者', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_by` bigint DEFAULT NULL COMMENT '更新者', `update_time` datetime DEFAULT NULL COMMENT '更新时间', `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)', `remark` varchar(500) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`app_id`), UNIQUE KEY `uk_app_code` (`app_code`) ) ENGINE=InnoDB COMMENT='第三方应用表'; -- API接口字典表 DROP TABLE IF EXISTS `pg_api_dict`; CREATE TABLE `pg_api_dict` ( `api_id` bigint NOT NULL COMMENT 'API ID', `api_code` varchar(50) NOT NULL COMMENT 'API编码', `api_name` varchar(100) NOT NULL COMMENT 'API名称', `api_path` varchar(200) NOT NULL COMMENT 'API路径', `api_method` varchar(10) DEFAULT 'GET' COMMENT '请求方法', `api_desc` varchar(500) DEFAULT NULL COMMENT 'API描述', `status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)', `order_num` int DEFAULT 0 COMMENT '排序', PRIMARY KEY (`api_id`), UNIQUE KEY `uk_api_code` (`api_code`) ) ENGINE=InnoDB COMMENT='API接口字典表'; -- 应用API授权表 DROP TABLE IF EXISTS `pg_app_api`; CREATE TABLE `pg_app_api` ( `id` bigint NOT NULL COMMENT '主键', `app_id` bigint NOT NULL COMMENT '应用ID', `api_id` bigint NOT NULL COMMENT 'API ID', `create_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_app_api` (`app_id`, `api_id`) ) ENGINE=InnoDB COMMENT='应用API授权表'; -- 菜单数据 INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time) VALUES (2300, '应用管理', 0, 4, 'application', 'business/application/index', '', 1, 0, 'C', '0', '0', 'business:application:list', 'component', 103, 1, NOW()); INSERT INTO sys_menu VALUES (2301, '应用查询', 2300, 1, '', '', '', 1, 0, 'F', '0', '0', 'business:application:query', '#', 103, 1, NOW(), NULL, NULL, ''); INSERT INTO sys_menu VALUES (2302, '应用新增', 2300, 2, '', '', '', 1, 0, 'F', '0', '0', 'business:application:add', '#', 103, 1, NOW(), NULL, NULL, ''); INSERT INTO sys_menu VALUES (2303, '应用修改', 2300, 3, '', '', '', 1, 0, 'F', '0', '0', 'business:application:edit', '#', 103, 1, NOW(), NULL, NULL, ''); INSERT INTO sys_menu VALUES (2304, '应用删除', 2300, 4, '', '', '', 1, 0, 'F', '0', '0', 'business:application:remove', '#', 103, 1, NOW(), NULL, NULL, ''); INSERT INTO sys_menu VALUES (2305, '重置密钥', 2300, 5, '', '', '', 1, 0, 'F', '0', '0', 'business:application:resetSecret', '#', 103, 1, NOW(), NULL, NULL, ''); INSERT INTO sys_menu VALUES (2306, '接口授权', 2300, 6, '', '', '', 1, 0, 'F', '0', '0', 'business:application:api', '#', 103, 1, NOW(), NULL, NULL, ''); -- API字典初始数据 INSERT INTO pg_api_dict (api_id, api_code, api_name, api_path, api_method, api_desc, status, order_num) VALUES (1700000000000000001, 'OPEN_STUDENT_LIST', '学生列表', '/open/api/student/list', 'GET', '开放API-学生列表分页查询', '0', 10); ``` ## 三、后端代码结构 ### 3.1 目录结构 ``` pangu-modules/pangu-business/src/main/java/org/dromara/pangu/application/ ├── controller/ │ └── PgApplicationController.java # 应用管理控制器 ├── domain/ │ ├── PgApplication.java # 第三方应用实体 │ ├── PgApiDict.java # API字典实体 │ └── PgAppApi.java # 应用API授权实体 ├── mapper/ │ ├── PgApplicationMapper.java # 应用Mapper │ ├── PgApiDictMapper.java # API字典Mapper │ └── PgAppApiMapper.java # 应用API授权Mapper └── service/ ├── IPgApplicationService.java # 应用服务接口 ├── IPgApiDictService.java # API字典服务接口 └── impl/ ├── PgApplicationServiceImpl.java # 应用服务实现 └── PgApiDictServiceImpl.java # API字典服务实现 ``` ### 3.2 API 接口列表 | 接口 | 方法 | 路径 | 权限标识 | 说明 | |------|------|------|----------|------| | 应用列表 | GET | /business/application/list | business:application:list | 分页查询应用列表 | | 应用详情 | GET | /business/application/{appId} | business:application:query | 获取应用详情 | | 新增应用 | POST | /business/application | business:application:add | 新增第三方应用 | | 修改应用 | PUT | /business/application | business:application:edit | 修改应用信息 | | 删除应用 | DELETE | /business/application/{appIds} | business:application:remove | 删除应用 | | 重置密钥 | PUT | /business/application/resetSecret/{appId} | business:application:edit | 重置应用密钥 | | 接口列表 | GET | /business/application/apiList | business:application:list | 获取可授权的API列表 | ### 3.3 核心代码 #### 3.3.1 控制器 (PgApplicationController.java) ```java @Validated @RequiredArgsConstructor @RestController @RequestMapping("/business/application") public class PgApplicationController extends BaseController { private final IPgApplicationService applicationService; private final IPgApiDictService apiDictService; @SaCheckPermission("business:application:list") @GetMapping("/list") public TableDataInfo list(PgApplication app, PageQuery pageQuery) { return applicationService.selectPageList(app, pageQuery); } @SaCheckPermission("business:application:edit") @Log(title = "应用管理", businessType = BusinessType.UPDATE) @PutMapping("/resetSecret/{appId}") public R resetSecret(@PathVariable Long appId) { PgApplication app = applicationService.selectById(appId); if (app == null) { return R.fail("应用不存在"); } String newSecret = IdUtil.fastSimpleUUID(); app.setAppSecret(newSecret); applicationService.update(app); return R.ok(app); } } ``` #### 3.3.2 服务实现 (PgApplicationServiceImpl.java) ```java @RequiredArgsConstructor @Service public class PgApplicationServiceImpl implements IPgApplicationService { private final PgApplicationMapper baseMapper; private final PgAppApiMapper appApiMapper; private final PgApiDictMapper apiDictMapper; @Override @Transactional(rollbackFor = Exception.class) public int insert(PgApplication app) { // 自动生成应用编码(格式:YY000001) String appCode = generateAppCode(); app.setAppCode(appCode); // 自动生成32位密钥 app.setAppSecret(IdUtil.fastSimpleUUID()); int rows = baseMapper.insert(app); // 保存接口授权 if (rows > 0 && app.getApiCodes() != null && !app.getApiCodes().isEmpty()) { saveAppApis(app.getAppId(), app.getApiCodes()); } return rows; } private String generateAppCode() { // 查询当前最大编码,生成下一个序号 // 格式:YY + 6位数字,如 YY000001 } @Override public boolean checkApiPermission(String appCode, String apiPath) { // 校验应用是否有访问该接口的权限 List paths = appApiMapper.selectApiPathsByAppCode(appCode); return paths != null && paths.contains(apiPath); } } ``` #### 3.3.3 实体类 (PgApplication.java) ```java @Data @EqualsAndHashCode(callSuper = true) @TableName("pg_application") public class PgApplication extends BaseEntity { @TableId(type = IdType.ASSIGN_ID) private Long appId; private String appCode; private String appName; private String appSecret; private String contactPerson; private String contactPhone; private String status; private String tenantId; @TableLogic private String delFlag; private String remark; /** 接口授权:API编码列表(不落库) */ @TableField(exist = false) private List apiCodes; } ``` ## 四、前端代码结构 ### 4.1 目录结构 ``` frontend/src/ ├── api/pangu/ │ └── application.js # API接口定义 └── views/application/ ├── index.vue # 应用列表页面 └── components/ ├── AppDialog.vue # 新增/编辑弹窗 └── SecretDialog.vue # 密钥展示弹窗 ``` ### 4.2 API 接口 (application.js) ```javascript import request from '@/utils/request' // 获取应用列表 export function getApplicationList(params) { return request({ url: '/business/application/list', method: 'get', params }) } // 新增应用 export function addApplication(data) { return request({ url: '/business/application', method: 'post', data }) } // 修改应用 export function updateApplication(data) { return request({ url: '/business/application', method: 'put', data }) } // 删除应用 export function deleteApplication(appId) { return request({ url: `/business/application/${appId}`, method: 'delete' }) } // 重置应用密钥 export function resetAppSecret(appId) { return request({ url: `/business/application/resetSecret/${appId}`, method: 'put' }) } // 获取接口授权选项列表 export function getApiAuthOptions() { return request({ url: '/business/application/apiList', method: 'get' }) } ``` ### 4.3 页面组件 #### 列表页面 (index.vue) - 搜索条件:应用名称、应用编码、状态 - 列表字段:应用名称、应用编码、授权接口、状态、创建时间、创建人 - 操作按钮:新增、编辑、重置密钥、删除 #### 新增/编辑弹窗 (AppDialog.vue) - 表单字段:应用名称、应用描述、联系人、联系电话、状态、接口授权 - 接口授权:多选框组,从 API 字典加载 ## 五、业务流程 ### 5.1 新增应用流程 ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 填写表单 │───>│ 提交保存 │───>│ 生成编码 │───>│ 生成密钥 │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ v v ┌──────────────────────────┐ │ 保存应用 + 接口授权 │ └──────────────────────────┘ ``` ### 5.2 第三方调用接口流程 ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 携带凭证 │───>│ 拦截校验 │───>│ 权限检查 │───>│ 执行业务 │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ v v │ 校验AppCode 校验该应用 │ 和AppSecret 是否有权限 │ 访问该接口 v 请求头携带: X-App-Code X-App-Secret X-Timestamp X-Sign ``` ## 六、文件清单 ### 6.1 后端文件 | 文件路径 | 说明 | |----------|------| | `pangu-business/src/.../application/controller/PgApplicationController.java` | 应用管理控制器 | | `pangu-business/src/.../application/domain/PgApplication.java` | 第三方应用实体 | | `pangu-business/src/.../application/domain/PgApiDict.java` | API字典实体 | | `pangu-business/src/.../application/domain/PgAppApi.java` | 应用API授权实体 | | `pangu-business/src/.../application/mapper/PgApplicationMapper.java` | 应用Mapper | | `pangu-business/src/.../application/mapper/PgApiDictMapper.java` | API字典Mapper | | `pangu-business/src/.../application/mapper/PgAppApiMapper.java` | 应用API授权Mapper | | `pangu-business/src/.../application/service/IPgApplicationService.java` | 应用服务接口 | | `pangu-business/src/.../application/service/IPgApiDictService.java` | API字典服务接口 | | `pangu-business/src/.../application/service/impl/PgApplicationServiceImpl.java` | 应用服务实现 | | `pangu-business/src/.../application/service/impl/PgApiDictServiceImpl.java` | API字典服务实现 | ### 6.2 前端文件 | 文件路径 | 说明 | |----------|------| | `frontend/src/api/pangu/application.js` | API接口定义 | | `frontend/src/views/application/index.vue` | 应用列表页面 | | `frontend/src/views/application/components/AppDialog.vue` | 新增/编辑弹窗 | | `frontend/src/views/application/components/SecretDialog.vue` | 密钥展示弹窗 | ### 6.3 SQL 文件 | 文件路径 | 说明 | |----------|------| | `pangu-business/sql/pangu_tables.sql` | 表结构(包含pg_application、pg_api_dict、pg_app_api) | | `pangu-business/sql/pangu_menu.sql` | 菜单数据 | | `pangu-business/sql/open_api_dict_data.sql` | API字典初始数据 | --- *文档版本:v1.0* *更新日期:2026-02-04* *作者:pangu*