pangu-user-platform/docs/开放接口实现说明.md

383 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 开放接口实现说明
## 📋 实现概述
已按照方案一(独立 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 工具类**
```java
位置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
}
```
#### 技术亮点
1. **分层清晰**
- Controller 只负责接收请求
- Service 处理业务逻辑(脱敏、转换)
- 复用原有 Service避免重复代码
2. **数据安全**
- 敏感字段脱敏(姓名使用 maskName
- 高敏感字段不返回(身份证、住址等)
- 使用专用 VO与内部数据结构解耦
3. **易于扩展**
- 新增开放接口只需:
- 创建专用 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 调用**
```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 调用**
```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())
```
---
## 🧪 测试建议
### 后端测试
1. **单元测试 DataMaskUtil**
```java
@Test
public void testMaskName() {
assertEquals("张*", DataMaskUtil.maskName("张三"));
assertEquals("李**", DataMaskUtil.maskName("李四五"));
}
```
2. **集成测试 OpenApiStudentService**
- 测试分页查询
- 测试数据脱敏是否生效
- 测试敏感字段是否被过滤
3. **接口测试 OpenApiStudentController**
- 使用 Postman 或 curl 测试
- 验证鉴权是否生效
- 验证返回数据格式
### 前端测试
1. **功能测试**
- 应用列表加载
- 新增应用(含接口授权)
- 编辑应用
- 查看密钥
- 重置密钥
- 删除应用
2. **表单校验**
- 必填项校验
- 手机号格式校验
---
## 📝 后续扩展指南
### 新增开放接口(以教师接口为例)
**步骤一:创建专用 VO**
```java
// 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 接口**
```java
// openapi/service/IOpenApiTeacherService.java
public interface IOpenApiTeacherService {
TableDataInfo<OpenTeacherVo> selectPageList(
String teacherName,
Long schoolId,
PageQuery pageQuery
);
}
```
**步骤三:创建 Service 实现**
```java
// 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**
```java
// 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(...);
}
}
```
**步骤五:添加接口字典**
```sql
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);
```
**步骤六:在应用管理中授权**
前端应用管理页面 -> 编辑应用 -> 勾选"教师列表查询"接口
---
## 🎯 核心优势总结
1. **安全可控**
- 五重验证机制(参数、时间戳、应用状态、签名、接口权限)
- 敏感数据脱敏
- 高敏感字段不返回
2. **易于扩展**
- Service 层可复用
- DataMaskUtil 可复用
- 新增接口遵循统一规范
3. **便于维护**
- 分层清晰
- 代码解耦
- 文档完善
4. **用户友好**
- 前端界面直观
- 接口授权可视化
- 密钥管理便捷
---
## 📞 技术支持
如有问题,请参考:
1. 需求与技术设计方案文档
2. 代码注释
3. 本实现说明文档
---
*实现完成时间2026-02-04*
*实现人员pangu*