4. 接口映射关系定义
好,我们到了第四节课。这节课要聊的东西,是适配改造里最核心的“翻译官”——接口映射关系。
说白了,SDK适配改造,本质就是一场“翻译工程”。
你把旧接口的“方言”翻译成新接口的“普通话”。翻译得准不准,全看映射关系定义得细不细。我见过太多项目,前期映射没做好,后期联调时天天在修数据,那叫一个痛苦。
4.1 映射表设计
我个人习惯,在写任何代码之前,先画一张映射表。这张表就是你的“作战地图”。
映射表不仅记录字段名,还要记录值、类型、行为。别嫌麻烦,你节省的每一分钟规划,都会在后期联调时省回一小时。
一个标准的映射表,至少包含以下维度:
| 维度 | 说明 | 示例 |
|---|---|---|
| 源字段路径 | 旧接口中的字段位置 | request.user.name |
| 目标字段路径 | 新接口中的字段位置 | newRequest.userInfo.nickName |
| 源数据类型 | 旧字段的类型 | int |
| 目标数据类型 | 新字段的类型 | string |
| 转换规则 | 如何从源变成目标 | toString() |
| 默认值 | 源字段为空时的兜底 | "未知用户" |
| 备注 | 边界情况或特殊处理 | 注意:name 可能含特殊字符 |
你想想看,设计这张表时,最关键的是什么?是字段路径的准确性。我记得有一次,老接口的订单号是 order_id,新接口变成了 transactionNo,看起来就是改了个名字,但新接口还要求订单号必须是大写。如果你只配了字段名,没配转换规则,那上线后就是一堆报错。
items[0].id,新接口是 products[0].productId。光改名字没用,索引的映射也必须清晰。否则,有时候数据对,有时候空,排查起来极其崩溃。
4.2 请求参数映射
请求参数的映射,是适配改造的第一道坎。它解决的是“怎么把旧的数据结构,装进新接口的请求里”。
我这里有一个常用的映射模板,你可以直接拿来用。
public class RequestMapper {
public NewRequest map(OldRequest oldReq) {
// 你看到的每个字段,都对应映射表中的一行
NewRequest newReq = new NewRequest();
// 字段重命名 + 默认值处理
newReq.setTransactionNo(
oldReq.getOrderId() != null ?
oldReq.getOrderId().toUpperCase() :
"DEFAULT_ORDER"
);
// 子对象嵌套映射
UserInfo info = new UserInfo();
info.setNickName(oldReq.getUserName());
newReq.setUserInfo(info);
// 列表映射
List<Product> products = oldReq.getItems()
.stream()
.map(item -> {
Product p = new Product();
p.setProductId(item.getId());
return p;
})
.collect(Collectors.toList());
newReq.setProducts(products);
return newReq;
}
}
这里有个容易被忽略的点:参数校验时机。
是映射前校验旧参数?还是映射后校验新参数?我建议双校验。映射前保证旧数据完整,映射后保证新接口不报错。
参数映射三步法:
- 解构:把旧请求拆解成最小原子字段
- 转换:按映射表逐一处理(改名、改值、改类型)
- 重组:按新接口结构重新组装成新请求
4.3 响应结果映射
响应映射比请求映射更复杂。因为返回的数据结构,往往千奇百怪。
你拿到旧接口的响应,要把它变成新接口格式返回给调用方。这个过程,核心是容忍旧、适配新。
我举个例子。旧接口成功了返回 {"status": 1},失败了返回 {"status": 0, "msg": "error"};新接口期望的是 {"code": "SUCCESS", "data": null}。
这时候,映射不能只改字段名,你得把业务逻辑也带进去。
public NewResponse map(OldResponse oldResp) {
NewResponse newResp = new NewResponse();
// 状态码映射——这是纯业务逻辑
if (oldResp.getStatus() == 1) {
newResp.setCode("SUCCESS");
} else if (oldResp.getStatus() == 0) {
newResp.setCode("FAILED");
newResp.setMessage(oldResp.getMsg());
} else {
// 你永远要留一手
newResp.setCode("UNKNOWN");
newResp.setMessage("未识别的状态码: " + oldResp.getStatus());
}
// 数据映射——注意空指针
if (oldResp.getData() != null) {
newResp.setData(convertData(oldResp.getData()));
}
return newResp;
}
4.4 字段类型转换规则
终于到这里了。类型转换,是映射里的“最后一公里”。很多Bug,就出在类型不对上。
下面这张表格,汇总了我在项目中遇到过的最常见的类型转换场景。
| 源类型 | 目标类型 | 转换规则 | 注意点 |
|---|---|---|---|
int |
String |
String.valueOf() |
注意科学计数法?不会,valueOf 不会。但 toString 会受对象影响,建议显式用 valueOf。 |
String |
int |
Integer.parseInt() |
字符串必须数字,否则抛异常。建议用正则 \d+ 预校验。 |
long |
int |
(int) value |
强转。注意溢出。我曾经因为订单ID从long转int,直接截断了。 |
boolean |
String |
value ? "Y" : "N" |
别直接 Boolean.toString(),那是小写true/false,很多系统不接受。 |
String |
Date |
new SimpleDateFormat("yyyy-MM-dd").parse() |
格式必须严格匹配。我建议用 LocalDate 替代老旧的 SimpleDateFormat。 |
List<String> |
String |
String.join(",", list) |
注意特殊字符。如果列表里有逗号,就乱了,建议用分号或其他分隔符。 |
null 的 Integer 转成 int 会报 NullPointerException。我习惯在映射层统一做一层 if (value == null) return defValue 的处理,别指望上一层或下一层帮你兜底。
为什么类型转换这么容易出错?因为很多开发觉得“大概差不多就行了”。结果就是线上出现NaN、null、空对象、格式不对。
我个人的做法是:每种转换都写单元测试。边界值、null值、超长值、特殊符号,全覆盖。这招帮我挡掉了很多线上事故。
嗯,映射关系这块,内容不少。但你看下来会发现,核心就是一张表、一套代码、几个测试。把这三点做好,适配改造就稳了一大半。