You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digital-rmb-backend/docs/superpowers/plans/2026-08-04-api-messages-enc...

176 lines
6.8 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 后端中文提示与 UTF-8 响应实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 所有 API 对外提示使用中文,并以 UTF-8 JSON 返回,避免 Swagger 和前端出现乱码。
**Architecture:** 通过 `ApiResponse` 统一成功提示,通过 Spring Security 的异常写入器统一鉴权提示,通过业务服务中文化可回传的校验信息。应用配置与响应写入器共同确保 UTF-8错误码保持不变。
**Tech Stack:** Java 8、Spring Boot 2.7、Spring Security、Springdoc OpenAPI、JUnit 5、MockMvc。
## Global Constraints
- 保持现有 `ErrorCode` 枚举值不变。
- 所有面向前端的 `message` 必须为中文。
- JSON 响应必须使用 UTF-8。
- 保留业务校验的具体中文原因;框架参数校验使用统一中文提示。
---
### Task 1: 统一响应和安全异常提示
**Files:**
- Modify: `src/main/java/com/yau/digitalrmb/shared/api/ApiResponse.java`
- Modify: `src/main/java/com/yau/digitalrmb/security/config/SecurityConfig.java`
- Modify: `src/main/resources/application.yml`
- Test: `src/test/java/com/yau/digitalrmb/security/SecurityConfigTest.java`
**Interfaces:**
- Produces: 成功响应的 `message` 为“操作成功”401、403 响应分别为“未登录或登录已失效”“无访问权限”。
- Produces: 安全异常响应头为 `application/json;charset=UTF-8`
- [ ] **Step 1: 写失败测试**
```java
mockMvc.perform(get("/api/v1/commercial-banks/issuance/inventory"))
.andExpect(status().isUnauthorized())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(content().encoding(StandardCharsets.UTF_8))
.andExpect(jsonPath("$.message").value("未登录或登录已失效"));
```
- [ ] **Step 2: 运行失败测试**
Run: `mvn -B -Dtest=SecurityConfigTest test`
Expected: FAIL当前消息为 `UNAUTHORIZED` 或响应编码不是 UTF-8。
- [ ] **Step 3: 最小实现**
```java
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.getWriter().write(... "未登录或登录已失效" ...);
```
并将 `ApiResponse.success` 的消息改为“操作成功”,在 `application.yml` 添加:
```yaml
server:
servlet:
encoding:
charset: UTF-8
enabled: true
force: true
```
- [ ] **Step 4: 运行测试验证通过**
Run: `mvn -B -Dtest=SecurityConfigTest test`
Expected: PASS。
- [ ] **Step 5: 提交**
```bash
git add src/main/java/com/yau/digitalrmb/shared/api/ApiResponse.java src/main/java/com/yau/digitalrmb/security/config/SecurityConfig.java src/main/resources/application.yml src/test/java/com/yau/digitalrmb/security/SecurityConfigTest.java
git commit -m "fix: return Chinese security messages in UTF-8"
```
### Task 2: 中文化发行模块对外业务提示
**Files:**
- Modify: `src/main/java/com/yau/digitalrmb/issuance/application/service/DenominationPlanService.java`
- Modify: `src/main/java/com/yau/digitalrmb/issuance/application/service/CommercialBankIssuanceApplicationService.java`
- Modify: `src/main/java/com/yau/digitalrmb/issuance/application/service/CentralBankIssuanceQueryService.java`
- Modify: `src/main/java/com/yau/digitalrmb/issuance/interfaces/rest/CommercialBankIssuanceController.java`
- Modify: `src/main/java/com/yau/digitalrmb/security/interfaces/AuthController.java`
- Test: `src/test/java/com/yau/digitalrmb/issuance/interfaces/rest/IssuanceControllerTest.java`
**Interfaces:**
- Produces: 面额总额不一致时 `VALIDATION_ERROR` 消息为“各面额小计之和必须等于申请总金额”。
- Produces: 当前用户审计声明缺失或非法时返回中文未授权提示。
- [ ] **Step 1: 写失败测试**
```java
mockMvc.perform(post("/api/v1/commercial-banks/issuance/denomination-plan/validate")
.with(issuanceJwt()).contentType(MediaType.APPLICATION_JSON)
.content(invalidPlanJson))
.andExpect(jsonPath("$.code").value("VALIDATION_ERROR"))
.andExpect(jsonPath("$.message").value("各面额小计之和必须等于申请总金额"));
```
- [ ] **Step 2: 运行失败测试**
Run: `mvn -B -Dtest=IssuanceControllerTest test`
Expected: FAIL当前消息为 `denomination total must equal totalAmount`
- [ ] **Step 3: 最小实现**
将所有会经 `BusinessException` 或校验转换返回前端的英文文本替换为对应中文,包括申请不存在、申请 ID 为空、库存配置不存在、JWT 缺失 `userId``preferred_username`、金额和面额规则。
- [ ] **Step 4: 运行测试验证通过**
Run: `mvn -B -Dtest=IssuanceControllerTest test`
Expected: PASS。
- [ ] **Step 5: 提交**
```bash
git add src/main/java/com/yau/digitalrmb/issuance src/main/java/com/yau/digitalrmb/security/interfaces/AuthController.java src/test/java/com/yau/digitalrmb/issuance/interfaces/rest/IssuanceControllerTest.java
git commit -m "fix: translate issuance API messages to Chinese"
```
### Task 3: 统一全局校验和验证
**Files:**
- Modify: `src/main/java/com/yau/digitalrmb/shared/web/GlobalExceptionHandler.java`
- Modify: `src/main/java/com/yau/digitalrmb/platformintegration/application/PlatformTokenVerifier.java`
- Test: `src/test/java/com/yau/digitalrmb/shared/GlobalExceptionHandlerTest.java`
**Interfaces:**
- Produces: 框架参数校验统一返回“请求参数校验失败”。
- Produces: 无效平台令牌返回“平台登录凭据无效”。
- [ ] **Step 1: 写失败测试**
```java
mockMvc.perform(post("/api/v1/auth/login").contentType(MediaType.APPLICATION_JSON).content("{}"))
.andExpect(jsonPath("$.code").value("VALIDATION_ERROR"))
.andExpect(jsonPath("$.message").value("请求参数校验失败"));
```
- [ ] **Step 2: 运行失败测试**
Run: `mvn -B -Dtest=GlobalExceptionHandlerTest test`
Expected: FAIL当前返回框架英文校验文本。
- [ ] **Step 3: 最小实现**
```java
return ApiResponse.failure(ErrorCode.VALIDATION_ERROR, "请求参数校验失败", traceId());
```
并把平台令牌异常内部消息改为中文,避免任何异常链的英文文本进入 API 响应。
- [ ] **Step 4: 执行完整验证**
Run: `mvn -B test`
Expected: 全部测试通过;新增中文/UTF-8 断言通过。
- [ ] **Step 5: 重启与人工验证**
Run: `mvn -B package -DskipTests`,重启本地 `8081` 后端;在 Swagger 调用面额校验接口,确认响应体中文且响应头为 UTF-8。
- [ ] **Step 6: 提交**
```bash
git add src/main/java/com/yau/digitalrmb/shared/web/GlobalExceptionHandler.java src/main/java/com/yau/digitalrmb/platformintegration/application/PlatformTokenVerifier.java src/test/java/com/yau/digitalrmb/shared/GlobalExceptionHandlerTest.java
git commit -m "fix: standardize Chinese validation messages"
```