9.0 KiB
9.0 KiB
开放接口实现说明
📋 实现概述
已按照方案一(独立 OpenApi Service 层)完成了开放接口的完整实现,包括后端业务逻辑和前端管理界面。
✅ 已完成的工作
1️⃣ 后端实现
核心文件清单
| 文件路径 | 说明 | 状态 |
|---|---|---|
openapi/utils/DataMaskUtil.java |
数据脱敏工具类 | ✅ 新建 |
openapi/domain/vo/OpenStudentVo.java |
开放接口学生VO | ✅ 已优化 |
openapi/service/IOpenApiStudentService.java |
开放接口服务接口 | ✅ 已存在 |
openapi/service/impl/OpenApiStudentServiceImpl.java |
开放接口服务实现 | ✅ 已完善 |
openapi/controller/OpenApiStudentController.java |
开放接口控制器 | ✅ 已更新 |
实现细节
1. DataMaskUtil 工具类
位置:org.dromara.pangu.openapi.utils.DataMaskUtil
提供的脱敏方法:
- maskName() // 姓名脱敏:张三 -> 张*
- maskPhone() // 手机号脱敏:13812345678 -> 138****5678
- maskIdCard() // 身份证脱敏:110101199001011234 -> 110101********1234
- maskEmail() // 邮箱脱敏:example@qq.com -> e****e@qq.com
- maskAddress() // 地址脱敏:保留省市区
2. OpenApiStudentServiceImpl 服务实现
核心逻辑:
1. 调用原有业务服务(IPgStudentService)获取数据
2. 在 Service 层进行数据转换(StudentVo -> OpenStudentVo)
3. 使用 DataMaskUtil 对敏感字段进行脱敏
4. 敏感字段不返回(身份证号、住址、会员信息等)
5. 返回开放接口专用 VO
3. OpenApiStudentController 控制器
接口定义:
GET /open/api/student/list
查询参数:
- studentName: 学生姓名(模糊查询)
- schoolId: 学校ID
- gradeId: 年级ID
- classId: 班级ID
- pageNum: 页码
- pageSize: 每页条数
返回数据:
{
"code": 200,
"msg": "操作成功",
"rows": [
{
"studentId": 1,
"studentCode": "S2024001",
"studentName": "张*", // 已脱敏
"gender": "1",
"schoolId": 1,
"schoolName": "第一小学",
"gradeId": 1,
"gradeName": "三年级",
"classId": 1,
"className": "1班"
}
],
"total": 100
}
技术亮点
-
分层清晰
- Controller 只负责接收请求
- Service 处理业务逻辑(脱敏、转换)
- 复用原有 Service,避免重复代码
-
数据安全
- 敏感字段脱敏(姓名使用 maskName)
- 高敏感字段不返回(身份证、住址等)
- 使用专用 VO,与内部数据结构解耦
-
易于扩展
- 新增开放接口只需:
- 创建专用 VO
- 创建 Service 接口和实现
- 创建 Controller
- DataMaskUtil 可复用
- 新增开放接口只需:
2️⃣ 前端实现
核心文件清单
| 文件路径 | 说明 | 状态 |
|---|---|---|
views/application/index.vue |
应用管理主页面 | ✅ 已优化 |
views/application/components/AppDialog.vue |
新增/编辑弹窗 | ✅ 已优化 |
views/application/components/SecretDialog.vue |
密钥展示弹窗 | ✅ 已存在 |
api/pangu/application.js |
应用管理API | ✅ 已存在 |
功能实现
1. 应用列表页面
功能点:
- ✅ 搜索:应用名称、应用编码、状态
- ✅ 列表展示:应用信息、授权接口、状态
- ✅ 新增应用
- ✅ 编辑应用
- ✅ 查看密钥
- ✅ 重置密钥(需二次确认)
- ✅ 删除应用(需二次确认)
- ✅ 分页功能
2. 新增/编辑弹窗
表单字段:
- 应用名称(必填)
- 应用编码(自动生成)
- 应用描述
- 联系人
- 联系电话(手机号格式校验)
- 状态(正常/停用)
- 接口授权(多选框,展示接口名称、路径、描述)
特性:
- ✅ 表单校验
- ✅ 接口授权选项动态加载
- ✅ 新增成功后自动显示密钥
- ✅ 编辑时回显数据
3. 密钥展示弹窗
功能:
- 展示应用名称、编码、密钥
- 一键复制密钥
- 安全提示(密钥重置后旧密钥失效)
🔍 使用示例
第三方应用调用示例
1. Java 调用
// 1. 准备请求参数
Map<String, String> params = new TreeMap<>();
params.put("pageNum", "1");
params.put("pageSize", "10");
params.put("studentName", "张");
// 2. 计算签名
String timestamp = String.valueOf(System.currentTimeMillis());
StringBuilder signStr = new StringBuilder();
params.forEach((k, v) -> signStr.append(k).append("=").append(v).append("&"));
signStr.append("appSecret=").append(APP_SECRET);
String sign = DigestUtils.md5Hex(signStr.toString()).toUpperCase();
// 3. 发送请求
HttpRequest request = HttpRequest.get(BASE_URL + "/open/api/student/list")
.header("X-App-Id", APP_CODE)
.header("X-Timestamp", timestamp)
.header("X-Sign", sign)
.form(params);
String response = request.execute().body();
2. Python 调用
import hashlib
import time
import requests
# 1. 准备参数
params = {
"pageNum": "1",
"pageSize": "10",
"studentName": "张"
}
# 2. 计算签名
timestamp = str(int(time.time() * 1000))
sorted_params = sorted(params.items())
sign_str = "&".join([f"{k}={v}" for k, v in sorted_params])
sign_str += f"&appSecret={APP_SECRET}"
sign = hashlib.md5(sign_str.encode()).hexdigest().upper()
# 3. 发送请求
headers = {
"X-App-Id": APP_CODE,
"X-Timestamp": timestamp,
"X-Sign": sign
}
response = requests.get(
f"{BASE_URL}/open/api/student/list",
params=params,
headers=headers
)
print(response.json())
🧪 测试建议
后端测试
-
单元测试 DataMaskUtil
@Test public void testMaskName() { assertEquals("张*", DataMaskUtil.maskName("张三")); assertEquals("李**", DataMaskUtil.maskName("李四五")); } -
集成测试 OpenApiStudentService
- 测试分页查询
- 测试数据脱敏是否生效
- 测试敏感字段是否被过滤
-
接口测试 OpenApiStudentController
- 使用 Postman 或 curl 测试
- 验证鉴权是否生效
- 验证返回数据格式
前端测试
-
功能测试
- 应用列表加载
- 新增应用(含接口授权)
- 编辑应用
- 查看密钥
- 重置密钥
- 删除应用
-
表单校验
- 必填项校验
- 手机号格式校验
📝 后续扩展指南
新增开放接口(以教师接口为例)
步骤一:创建专用 VO
// openapi/domain/vo/OpenTeacherVo.java
@Data
@Schema(description = "开放接口教师信息")
public class OpenTeacherVo implements Serializable {
private Long teacherId;
private String teacherName; // 已脱敏
private String teacherCode;
private String schoolName;
// 敏感字段不暴露
}
步骤二:创建 Service 接口
// openapi/service/IOpenApiTeacherService.java
public interface IOpenApiTeacherService {
TableDataInfo<OpenTeacherVo> selectPageList(
String teacherName,
Long schoolId,
PageQuery pageQuery
);
}
步骤三:创建 Service 实现
// openapi/service/impl/OpenApiTeacherServiceImpl.java
@Service
@RequiredArgsConstructor
public class OpenApiTeacherServiceImpl implements IOpenApiTeacherService {
private final IPgTeacherService teacherService; // 复用原有服务
@Override
public TableDataInfo<OpenTeacherVo> selectPageList(...) {
// 1. 调用原有服务
// 2. 转换并脱敏
// 3. 返回
}
private OpenTeacherVo convertToOpenApiVo(TeacherVo source) {
// 使用 DataMaskUtil 进行脱敏
}
}
步骤四:创建 Controller
// openapi/controller/OpenApiTeacherController.java
@RestController
@RequestMapping("/open/api/teacher")
public class OpenApiTeacherController {
private final IOpenApiTeacherService openApiTeacherService;
@GetMapping("/list")
public TableDataInfo<OpenTeacherVo> list(...) {
return openApiTeacherService.selectPageList(...);
}
}
步骤五:添加接口字典
INSERT INTO pg_api_dict (api_id, api_code, api_name, api_path, api_method, api_desc, status, order_num)
VALUES (1700000000000000002, 'OPEN_TEACHER_LIST', '教师列表查询', '/open/api/teacher/list', 'GET', '分页查询教师信息', '0', 20);
步骤六:在应用管理中授权
前端应用管理页面 -> 编辑应用 -> 勾选"教师列表查询"接口
🎯 核心优势总结
-
安全可控
- 五重验证机制(参数、时间戳、应用状态、签名、接口权限)
- 敏感数据脱敏
- 高敏感字段不返回
-
易于扩展
- Service 层可复用
- DataMaskUtil 可复用
- 新增接口遵循统一规范
-
便于维护
- 分层清晰
- 代码解耦
- 文档完善
-
用户友好
- 前端界面直观
- 接口授权可视化
- 密钥管理便捷
📞 技术支持
如有问题,请参考:
- 需求与技术设计方案文档
- 代码注释
- 本实现说明文档
实现完成时间:2026-02-04 实现人员:pangu