
本文讲解为何不应使用 string.format 拼接 json 字符串,以及如何通过 jackson 的 objectmapper 安全、可靠地生成符合标准的 json 请求体,彻底避免多余的反斜杠转义。
本文讲解为何不应使用 string.format 拼接 json 字符串,以及如何通过 jackson 的 objectmapper 安全、可靠地生成符合标准的 json 请求体,彻底避免多余的反斜杠转义。
在 Java 开发中,尤其是与 RESTful API 交互时,常需构造结构化 JSON 请求体。一个常见误区是:用 String.format() 手动拼接 JSON 字符串(如 "\"%s\""),尤其当嵌套字段本身已是合法 JSON(例如 extraParams 是一个动态 JSON 数组)时——这会导致双重序列化:ObjectMapper.writeValueAsString(params.getExtraParams()) 先生成带引号的 JSON 字符串,再被 String.format 当作普通字符串插入外层模板,最终导致 extraParams 字段值被错误地转义为 "[{\"hostValue\": \"id1\"}]",而非预期的 "[{"hostValue": "id1"}]"。
根本原因在于:String.format 是纯文本替换工具,不具备 JSON 语义感知能力。它无法识别哪些内容应作为原始 JSON 值嵌入,哪些需转义;而 JSON 标准要求对象/数组必须由 ObjectMapper 等专业库统一序列化,确保类型、引号、嵌套层级和特殊字符(如 "、\、换行符)被严格合规处理。
✅ 正确做法:全程委托 Jackson 序列化,避免任何字符串拼接
推荐两种生产级方案,均能保证输出 100% 合法、无冗余转义的 JSON:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
方案一:使用 Map 构建动态结构(轻量、灵活)
ObjectMapper mapper = new ObjectMapper();
// 构建内层 details 对象(支持任意字段,含未知 key 如 sqlPORTNumber)
Map<string object> details = new HashMap();
details.put("param1", "param1");
details.put("param2", "param2");
details.put("extraParams", params.getExtraParams()); // 直接传入原始 List<map object>> 或 POJO,不预序列化!
// 组装完整请求体
Map<string object> root = Map.of(
"params", Map.of("details", details)
);
String requestBody = mapper.writeValueAsString(root);
// 输出示例:{"params":{"details":{"param1":"param1","param2":"param2","extraParams":[{"hostValue":"id1","portNumber":"name1"}]}}}</string></map></string>
✅ 关键点:params.getExtraParams() 保持为 Java 对象(如 List
方案二:使用强类型 POJO(推荐用于长期维护项目)
定义清晰的数据模型,提升可读性与类型安全:
public class Details {
private String param1;
private String param2;
private List<extraparam> extraParams; // 或 Object,若结构完全动态
// getters & setters...
}
public class Params { private Details details; /* ... */ }
public class MyRequest { private Params params; /* ... */ }
// 构造并序列化
Details details = new Details();
details.setParam1("param1");
details.setParam2("param2");
details.setExtraParams(params.getExtraParams()); // 传入原始对象
MyRequest request = new MyRequest();
request.setParams(new Params().setDetails(details));
String requestBody = new ObjectMapper().writeValueAsString(request);</extraparam>
⚠️ 注意事项
- 绝对禁止对已序列化的 JSON 字符串(如 mapper.writeValueAsString(...) 返回值)再次参与 String.format 或字符串拼接;
- 若 extraParams 来源不可控(如第三方 JSON 字符串),先用 mapper.readTree(jsonStr) 解析为 JsonNode,再注入 POJO/Map,确保 Jackson 全链路控制;
- 使用 ObjectMapper 时建议复用单例实例,并配置 configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, false) 等选项优化输出。
总结:JSON 是结构化数据格式,不是字符串模板。用 String.format 处理 JSON 等同于用记事本写数据库 SQL —— 看似快捷,实则埋下兼容性、安全性与可维护性隐患。始终让 Jackson 这样的专业序列化器承担全部 JSON 生成职责,是构建健壮 API 客户端的基石。










