解决api接口返回多层嵌套的json,在中间的某一层为null的问题

本文讨论了后端API设计中关于null值、默认值及错误处理的重要性,并提出了合理的处理方案,如直接返回错误信息而非默认值,以及使用Lodash等工具简化JSON数据处理。

后端 API 重要的是语义准确而非前端使用方便。null、空对象、空字符串的语义是不一样的,牟然转换容易丢失语义,引发后续维护的困难。我在此基础上补充点更贴近现实的内容。

如果不允许有 null,我建议 API 直接返回错误信息,而不是前端再做错误处理。

到底要不要返回默认值取决于该域的实际用途。如果该域的默认值是为了处理 View 层的问题,那么这个默认值就肯定只能是 View 自己去处理。如果后端服务器为你提供了默认值,一是服务器自己实现了与自己无关的逻辑;二是如果该 API 不只一个用户,这个逻辑就蔓延到其他用户身上;三是如果后续要改 View 的逻辑(例如判断是否为空值),就需要后端开发配合实现,增加额外的沟通合作成本。
如果该域的默认值是系统设计上的(例如用户权限默认为只读),此时就后端就(很显然)应该返回默认值。这就是它要做的事。

针对取值困难的问题,JSON 数据的取值还是比较简单的。使用 Lodash 的 get function(_.get(object, path, [defaultValue])) 或者自己包装一套类似的 API,应该足够解决大部分数据结构的取值,判空,默认值问题。

实在不行,用 Node.js 实现一层中间层用于数据预处理也是非常简单。

<think> 我们面对的是多层嵌套JSON嵌套Map的需求。 根据引用[1][3][4]提供的思路,核心在于递归处理:当遇到嵌套JSON对象时,递归调用转换函数;遇到JSON数组时,则转换为List(其中可能包含Map或List)。 同时,引用[5]提醒:在解析嵌套JSON时,要注意二次解析时避免转义符问题,应使用JSON库的序列化方法(如JSON.toJSONString)而不是简单的toString。 以下提供两种语言(Java和TypeScript)的实现示例,因为鸿蒙开发常用这两种语言。 ### 📌 Java实现(基于org.json库) 假设使用`org.json`库(鸿蒙也支持类似JSON处理): ```java import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class JsonUtils { public static Map<String, Object> jsonToMap(String jsonStr) { JSONObject jsonObject = new JSONObject(jsonStr); return toMap(jsonObject); } private static Map<String, Object> toMap(JSONObject jsonObject) { Map<String, Object> map = new HashMap<>(); Iterator<String> keys = jsonObject.keys(); while (keys.hasNext()) { String key = keys.next(); Object value = jsonObject.get(key); // 如果是JSONObject,递归转换 if (value instanceof JSONObject) { map.put(key, toMap((JSONObject) value)); } // 如果是JSONArray,则递归处理每个元素 else if (value instanceof JSONArray) { map.put(key, toList((JSONArray) value)); } // 普通值直接放入 else { map.put(key, value); } } return map; } private static List<Object> toList(JSONArray array) { List<Object> list = new ArrayList<>(); for (int i = 0; i < array.length(); i++) { Object value = array.get(i); if (value instanceof JSONObject) { list.add(toMap((JSONObject) value)); } else if (value instanceof JSONArray) { list.add(toList((JSONArray) value)); } else { list.add(value); } } return list; } } ``` 使用示例: ```java String json = "{\"a\":1, \"b\":{\"c\":2}, \"d\":[3, {\"e\":4}]}"; Map<String, Object> map = JsonUtils.jsonToMap(json); ``` ### 📌 TypeScript实现(鸿蒙应用开发常用) ```typescript function jsonToNestedMap(jsonStr: string): any { const obj = JSON.parse(jsonStr); return convertToMap(obj); } function convertToMap(obj: any): any { if (Array.isArray(obj)) { return obj.map(item => convertToMap(item)); } else if (typeof obj === 'object' && obj !== null) { const map = new Map<string, any>(); for (const key in obj) { if (obj.hasOwnProperty(key)) { map.set(key, convertToMap(obj[key])); } } return map; } else { return obj; } } ``` 使用示例: ```typescript const jsonStr = '{"name":"Alice","info":{"age":20,"hobbies":["reading",{"sport":"swimming"}]}}'; const nestedMap = jsonToNestedMap(jsonStr); console.log(nestedMap.get('info').get('hobbies')[1].get('sport')); // 输出:"swimming" ``` ### 🔧 关键要点 1. **递归处理**:遇到对象或数组时递归调用转换函数[^1][^3][^4]。 2. **类型判断**: - Java中需判断`JSONObject`和`JSONArray` - TypeScript中判断`object`和`Array` 3. **避免转义问题**:不要直接调用`toString()`,而是通过JSON库处理嵌套对象(引用[5]的警告)[^5]。 4. **鸿蒙兼容性**:以上代码在鸿蒙API 7+上均可运行。 > ⚠️ 注意:TypeScript版本返回的是嵌套的Map结构,但鸿蒙的Map不支持直接通过`get`链式访问嵌套对象,需逐层获取。 ### 性能优化建议 对于极深嵌套或巨型JSON: - 设置递归深度上限(避免栈溢出) - 使用迭代替代递归(引用[3]提到迭代解决方案)[^3] - 流式解析(如Java的Jackson流式API) 例如迭代替代递归的伪代码(Java): ```java public static Map<String, Object> iterativeJsonToMap(JSONObject root) { Map<String, Object> resultMap = new HashMap<>(); Stack<Pair<JSONObject, Map<String, Object>>> stack = new Stack<>(); stack.push(new Pair<>(root, resultMap)); while (!stack.isEmpty()) { Pair<JSONObject, Map<String, Object>> current = stack.pop(); JSONObject currentObj = current.getKey(); Map<String, Object> currentMap = current.getValue(); Iterator<String> keys = currentObj.keys(); while (keys.hasNext()) { String key = keys.next(); Object value = currentObj.get(key); if (value instanceof JSONObject) { Map<String, Object> newMap = new HashMap<>(); currentMap.put(key, newMap); stack.push(new Pair<>((JSONObject) value, newMap)); } else if (value instanceof JSONArray) { // 处理数组... } else { currentMap.put(key, value); } } } return resultMap; } ``` --- §§相关问题§§ 1. 如何避免递归解析导致的栈溢出? 2. JSON数组在转换时应该如何处理? 3. 转换过程中如何保留原始数据类型(如数字、布尔值)? 4. 鸿蒙系统中是否有内置的JSON嵌套Map的方法? </think> ### 嵌套多层JSON嵌套Map的方法 在鸿蒙系统中处理多层嵌套JSON嵌套Map需使用**递归解析**,核心思路是逐层判断数据结构类型并递归处理。参考引用[1][3][4]的解决方案,具体实现如下: --- #### 📌 TypeScript 实现(鸿蒙推荐) ```typescript function jsonToNestedMap(jsonStr: string): Map<string, any> { const map = new Map<string, any>(); try { const obj = JSON.parse(jsonStr); parseObject(obj, map); } catch (e) { console.error("JSON解析失败: " + e); } return map; } // 递归解析核心逻辑 function parseObject(data: any, targetMap: Map<string, any>): void { for (const key in data) { if (data.hasOwnProperty(key)) { const value = data[key]; if (typeof value === 'object' && value !== null) { // 嵌套对象:递归创建新Map if (value.constructor === Object) { const childMap = new Map<string, any>(); parseObject(value, childMap); targetMap.set(key, childMap); } // 嵌套数组:递归处理数组元素 else if (Array.isArray(value)) { const childArray = value.map(item => { if (typeof item === 'object') { const itemMap = new Map<string, any>(); parseObject(item, itemMap); return itemMap; } return item; }); targetMap.set(key, childArray); } } else { // 基础类型直接存储 targetMap.set(key, value); } } } } // 使用示例 const json = `{ "user": { "name": "Alice", "address": { "city": "北京", "zip": 100000 } }, "skills": ["Java", {"framework": "HarmonyOS"}] }`; const nestedMap = jsonToNestedMap(json); console.log(nestedMap.get("user")?.get("address")?.get("city")); // 输出:北京 console.log(nestedMap.get("skills")?.[1]?.get("framework")); // 输出:HarmonyOS ``` --- #### 🔧 关键技术点解析 1. **递归处理嵌套结构** - 遇到 `object` 类型时,递归创建子 `Map` 对象[^1][^3] - 遇到数组时遍历处理每个元素,保留嵌套结构[^4] 2. **类型安全判断** - 严格区分基础类型 (`string/number/boolean`)、对象 (`Object`) 和数组 (`Array`) - 使用 `value.constructor === Object` 精准识别纯对象[^4] 3. **避免转义问题** - 使用 `JSON.parse()` 自动处理转义符,禁止直接调用 `toString()`(引用[5]警告)[^5] 4. **鸿蒙优化建议** ```typescript // 针对大文件分块解析(伪代码) const chunkedMap = new Map(); for (const chunk of splitLargeJson(jsonString, 1024 * 1024)) { const chunkMap = jsonToNestedMap(chunk); mergeMaps(chunkedMap, chunkMap); // 自定义合并逻辑 } ``` --- #### 💡 处理边界情况 | 数据类型 | 处理方式 | 示例 | |----------------|-----------------------------|---------------------| | **空值** | 保留为 `null` | `"key": null` | | **日期对象** | 转换为字符串 | `Date→"2023-01-01"`| | **循环引用** | 检测引用路径避免栈溢出 | 使用 `WeakMap` 跟踪 | > 注:复杂场景建议使用鸿蒙的 `@ohos.util.JSON` 工具类[^1],或引入 `fast-json` 等高性能库处理百万级数据。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值