戰(zhàn):解析、查詢與避坑指南)
簡介這份資源是一套面向Java初學(xué)者與Web開發(fā)入門者的JSON完整示例工程圍繞JSON語法、解析與生成展開幫助讀者理解鍵值對(duì)、數(shù)組、嵌套對(duì)象等核心結(jié)構(gòu)并掌握在代碼中處理JSON數(shù)據(jù)的常見方式。壓縮包共22個(gè)文件約2.88MB以14個(gè)jar依賴包為主輔以2個(gè)java源碼、2個(gè)class編譯文件及classpath、project等工程配置另附1份json筆記整體構(gòu)成可直接導(dǎo)入運(yùn)行的JsonDemo項(xiàng)目依賴涵蓋json-lib、commons系列等常用庫。目前已有3576人學(xué)習(xí)下載適合需要對(duì)照示例理解JSON序列化與反序列化流程的開發(fā)者。通過源碼與筆記讀者可快速掌握J(rèn)SON對(duì)象構(gòu)建、字符串轉(zhuǎn)換及依賴配置思路為接口數(shù)據(jù)交換與AJAX場景打下基礎(chǔ)。1. 從一份“json完整例子”說起為什么你搜到的 JSON 教程總是跑不通你搜“json完整例子”大概率不是想聽 JSON 是什么——全稱 JavaScript Object Notation一種輕量級(jí)數(shù)據(jù)交換格式這你早知道了。你真正卡住的是拿到一份 JSON 文件不知道用什么打開、怎么解析、字段怎么取、嵌套數(shù)組怎么遍歷、格式錯(cuò)了怎么排查。更具體一點(diǎn)你可能正在做接口聯(lián)調(diào)、配置視頻源、處理大模型返回的 JSON 字段或者被一個(gè) merge conflict 卡了半天。這份“json完整例子”資源的價(jià)值就在這它不是概念科普而是一組可直接運(yùn)行的完整示例覆蓋對(duì)象、數(shù)組、嵌套結(jié)構(gòu)、類型邊界和常見解析場景。適合三類人剛接觸接口開發(fā)的新手需要一份能照著敲的模板做數(shù)據(jù)處理的工程師想快速驗(yàn)證解析邏輯以及被 JSON 格式問題反復(fù)折騰、想搞清邊界的人。下面我按“先看懂結(jié)構(gòu)、再動(dòng)手解析、最后避坑”的順序拆開講。2. JSON 結(jié)構(gòu)拆解對(duì)象、數(shù)組與嵌套到底怎么組織2.1 六種值類型與三種結(jié)構(gòu)形態(tài)JSON 的值類型只有六種字符串、數(shù)字、布爾、null、對(duì)象、數(shù)組。前四種是標(biāo)量后兩種是容器。所有復(fù)雜的 JSON 都是這六種類型嵌套組合出來的。理解這一點(diǎn)后面解析時(shí)遇到任何結(jié)構(gòu)都不會(huì)慌。對(duì)象用花括號(hào){}包裹內(nèi)部是鍵值對(duì)鍵必須是雙引號(hào)字符串值可以是任意類型。數(shù)組用方括號(hào)[]包裹元素可以是任意類型且允許混合。嵌套就是容器里再放容器。常見做法是對(duì)象表示一條記錄數(shù)組表示一批記錄嵌套對(duì)象表示關(guān)聯(lián)信息。{ id: 1001, name: 示例資源, active: true, tags: [json, tutorial, example], meta: { author: engineer, version: 2, published: null }, items: [ { sku: A1, price: 19.9, stock: 3 }, { sku: B2, price: 5.0, stock: 0 } ] }這段結(jié)構(gòu)里tags是字符串?dāng)?shù)組meta是嵌套對(duì)象items是對(duì)象數(shù)組。解析時(shí)最容易出錯(cuò)的地方是把items當(dāng)成對(duì)象去取鍵或者遍歷meta時(shí)忘了它是對(duì)象不是數(shù)組。判斷方法很簡單——看外層是{}還是[]{}用鍵訪問[]用索引或循環(huán)。2.2 用 Python 完整解析一份嵌套 JSONPython 標(biāo)準(zhǔn)庫json就夠用不需要額外裝包。下面這段代碼把上面的結(jié)構(gòu)解析出來并演示三種取值方式。import json raw { id: 1001, name: 示例資源, tags: [json, tutorial], meta: {author: engineer, version: 2}, items: [ {sku: A1, price: 19.9, stock: 3}, {sku: B2, price: 5.0, stock: 0} ] } data json.loads(raw) # 字符串轉(zhuǎn)字典 print(data[name]) # 直接取標(biāo)量 print(data[meta][author]) # 嵌套對(duì)象逐層取 for item in data[items]: # 數(shù)組用循環(huán) if item[stock] 0: print(item[sku], item[price])json.loads()把字符串轉(zhuǎn)成 Python 字典如果是從文件讀就用json.load(open(...))。取值時(shí)data[meta][author]是逐層下鉆中間任何一層鍵不存在都會(huì)拋KeyError。遍歷數(shù)組用for不要用data[items][0]硬編碼索引除非你確定只有一條。item[stock] 0這種判斷在過濾有效數(shù)據(jù)時(shí)很常用比如篩掉無庫存的記錄。參數(shù)上唯一需要注意的是json.loads的parse_float和parse_int默認(rèn)轉(zhuǎn)成 Python 的 float 和 int。如果價(jià)格字段精度要求高可以傳parse_floatDecimal避免浮點(diǎn)誤差。這個(gè)細(xì)節(jié)在處理金額類 JSON 時(shí)是血淚經(jīng)驗(yàn)。2.3 用 JavaScript 解析并處理數(shù)組過濾前端或 Node 環(huán)境里JSON.parse()是標(biāo)配。下面演示解析后過濾出有庫存的商品并轉(zhuǎn)成新數(shù)組。const raw {items:[{sku:A1,price:19.9,stock:3},{sku:B2,price:5.0,stock:0}]}; const data JSON.parse(raw); // 字符串轉(zhuǎn)對(duì)象 const available data.items.filter( // 過濾有庫存的 item item.stock 0 ); available.forEach(item { console.log(${item.sku} 價(jià)格 ${item.price}); });JSON.parse()遇到格式錯(cuò)誤會(huì)直接拋SyntaxError不會(huì)返回部分結(jié)果。filter返回新數(shù)組不改變?cè)瓟?shù)據(jù)。forEach只做遍歷需要返回新數(shù)組時(shí)用map。這里容易翻車的是模板字符串里再嵌 JSON 字符串反引號(hào)和雙引號(hào)混用會(huì)導(dǎo)致解析失敗建議 JSON 部分單獨(dú)用單引號(hào)或轉(zhuǎn)義。3. 從文件到接口JSON 讀取、查詢與轉(zhuǎn)換的完整鏈路3.1 讀取本地 JSON 文件的三種方式不同場景讀文件的方式不一樣。Python 讀本地文件最直接import json with open(data.json, r, encodingutf-8) as f: data json.load(f) # 直接從文件對(duì)象加載 print(type(data)) # dict 或 listencodingutf-8必須顯式寫否則在部分系統(tǒng)上中文會(huì)亂碼。如果文件很大json.load會(huì)一次性讀進(jìn)內(nèi)存幾百 MB 以上建議用ijson流式解析。判斷文件是對(duì)象還是數(shù)組看開頭第一個(gè)非空白字符是{還是[。Node 環(huán)境讀文件const fs require(fs); const data JSON.parse( fs.readFileSync(data.json, utf-8) ); console.log(Array.isArray(data));readFileSync是同步讀適合啟動(dòng)時(shí)加載配置。接口服務(wù)里建議用fs.promises.readFile異步讀避免阻塞。Array.isArray用來判斷頂層是數(shù)組還是對(duì)象決定后續(xù)用循環(huán)還是取鍵。3.2 JSON 查詢按字段篩選與嵌套取值“json查詢函數(shù)”是高頻搜索詞很多人想要的是類似 SQL 的查詢能力。Python 里沒有內(nèi)置 JSON 查詢語法但可以用列表推導(dǎo)和filter組合實(shí)現(xiàn)。import json data json.loads(open(data.json, encodingutf-8).read()) # 查詢 stock 大于 0 且 price 小于 20 的記錄 result [ item for item in data[items] if item[stock] 0 and item[price] 20 ] print(result) # 提取所有 sku 組成新列表 skus [item[sku] for item in data[items]] print(skus)列表推導(dǎo)里if可以寫多個(gè)條件用and連接。提取字段用[item[sku] for item in ...]這是最常用的投影操作。如果嵌套層級(jí)深比如data[meta][author]建議先賦值給中間變量避免重復(fù)下鉆和潛在KeyError。需要更復(fù)雜的查詢時(shí)常見做法是用jmespath或jsonpath-ng語法類似items[?stock \0].sku。但引入第三方庫前先確認(rèn)標(biāo)準(zhǔn)庫能不能滿足多數(shù)篩選場景列表推導(dǎo)就夠了。3.3 JSON 轉(zhuǎn)其他格式CSV、TXT 與掩碼處理“json轉(zhuǎn)txt掩碼”這類需求通常出現(xiàn)在數(shù)據(jù)導(dǎo)出場景。把 JSON 數(shù)組轉(zhuǎn) CSVimport json, csv data json.loads(open(data.json, encodingutf-8).read()) with open(out.csv, w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnames[sku, price, stock]) writer.writeheader() for item in data[items]: writer.writerow(item)DictWriter要求每行是字典fieldnames決定列順序。newline防止 Windows 下多空行。如果 JSON 字段比 CSV 列多只寫fieldnames里列出的鍵多余的自動(dòng)忽略。轉(zhuǎn) TXT 掩碼時(shí)通常是把敏感字段替換成固定字符masked [ {**item, sku: item[sku][:2] ***} for item in data[items] ]{**item, sku: ...}是淺拷貝并覆蓋字段不修改原數(shù)據(jù)。掩碼規(guī)則按業(yè)務(wù)定常見是保留前兩位、其余替換。4. 避坑與排查JSON 解析中最容易翻車的五個(gè)場景4.1 現(xiàn)象解析報(bào)JSONDecodeError但肉眼看著格式?jīng)]錯(cuò)原因通常有三類末尾多了逗號(hào)、用了單引號(hào)、鍵沒加雙引號(hào)。JSON 標(biāo)準(zhǔn)不允許尾逗號(hào)不允許單引號(hào)字符串鍵必須雙引號(hào)。肉眼掃一遍很難發(fā)現(xiàn)尤其是長文件。解決用在線校驗(yàn)工具或命令行python -m json.tool data.json它會(huì)指出具體行號(hào)。VS Code 里裝 JSON 插件也能實(shí)時(shí)標(biāo)紅。養(yǎng)成保存前格式化一次的習(xí)慣能省很多排查時(shí)間。4.2 現(xiàn)象中文顯示成\u4e2d\u6587轉(zhuǎn)義序列原因json.dumps默認(rèn)ensure_asciiTrue會(huì)把非 ASCII 字符轉(zhuǎn)義。讀取時(shí)其實(shí)不影響但直接看文件很痛苦。解決導(dǎo)出時(shí)加ensure_asciiFalse。json.dumps(data, ensure_asciiFalse, indent2)indent2讓輸出帶縮進(jìn)方便人看。讀取時(shí)不需要額外參數(shù)json.load會(huì)自動(dòng)還原轉(zhuǎn)義。4.3 現(xiàn)象大整數(shù)或高精度小數(shù)解析后精度丟失原因JavaScript 的JSON.parse把所有數(shù)字轉(zhuǎn)成雙精度浮點(diǎn)超過 2^53 的整數(shù)會(huì)丟精度。Python 默認(rèn) int 不丟但 float 有浮點(diǎn)誤差。解決金額類字段在 JSON 里用字符串存解析后按需轉(zhuǎn)Decimal。大整數(shù) ID 同樣建議用字符串。這是接口設(shè)計(jì)階段就要定的規(guī)則事后補(bǔ)救很麻煩。4.4 現(xiàn)象merge conflict 時(shí) JSON 文件沖突無法自動(dòng)合并原因JSON 是純文本Git 按行合并兩個(gè)分支同時(shí)改同一段結(jié)構(gòu)就會(huì)沖突。如果格式化風(fēng)格不一致一個(gè)縮進(jìn) 2 空格一個(gè) 4 空格整個(gè)文件都會(huì)沖突。解決團(tuán)隊(duì)統(tǒng)一格式化工具比如 Prettier 配.prettierrc提交前跑一遍。沖突時(shí)不要手動(dòng)刪括號(hào)用git checkout --theirs或--ours先選一邊再手動(dòng)補(bǔ)差異。結(jié)構(gòu)復(fù)雜的 JSON 建議拆成多個(gè)小文件降低沖突概率。4.5 現(xiàn)象接口返回的 JSON 里字段有時(shí)是對(duì)象有時(shí)是數(shù)組原因后端設(shè)計(jì)不一致或者空結(jié)果時(shí)返回{}而非[]。前端按數(shù)組遍歷就會(huì)報(bào)錯(cuò)。解決解析后先判斷類型再處理。const items Array.isArray(data.items) ? data.items : [];這行兜底能避免大部分運(yùn)行時(shí)錯(cuò)誤。更根本的辦法是推動(dòng)接口規(guī)范統(tǒng)一空數(shù)組返回[]空對(duì)象返回{}不要混用。5. 進(jìn)階技巧用 JSON Schema 校驗(yàn)結(jié)構(gòu)把錯(cuò)誤擋在解析之前前面講的都是解析后處理但更高效的做法是解析前先校驗(yàn)。JSON Schema 就是干這個(gè)的——它用一份 JSON 描述另一份 JSON 應(yīng)該長什么樣字段類型、必填項(xiàng)、取值范圍都能約束。常見做法是在接口入口或配置文件加載時(shí)先跑一遍校驗(yàn)不合格直接拒絕避免臟數(shù)據(jù)流到下游。Python 里用jsonschema庫import json from jsonschema import validate, ValidationError schema { type: object, required: [id, name, items], properties: { id: {type: integer}, name: {type: string}, items: { type: array, items: { type: object, required: [sku, price], properties: { sku: {type: string}, price: {type: number, minimum: 0} } } } } } data json.loads(open(data.json, encodingutf-8).read()) try: validate(instancedata, schemaschema) print(校驗(yàn)通過) except ValidationError as e: print(校驗(yàn)失敗:, e.message)required列出必填字段缺一個(gè)就報(bào)錯(cuò)。type約束類型minimum約束數(shù)值下限。items嵌套 schema 可以逐層校驗(yàn)數(shù)組元素。ValidationError的message會(huì)指出具體哪個(gè)字段不滿足排查很快。參數(shù)上validate默認(rèn)遇到第一個(gè)錯(cuò)誤就停想看全部錯(cuò)誤用iter_errors。schema 本身也可以存成獨(dú)立 JSON 文件用json.load讀進(jìn)來方便版本管理。校驗(yàn)項(xiàng)關(guān)鍵字作用必填required字段缺失即報(bào)錯(cuò)類型type限定 string/number/object 等數(shù)值范圍minimum / maximum限定數(shù)字上下限字符串長度minLength / maxLength限定字符數(shù)數(shù)組元素items對(duì)每個(gè)元素套用子 schema這張表覆蓋了日常八成校驗(yàn)需求。更復(fù)雜的還有oneOf、anyOf、pattern按需查文檔即可。我現(xiàn)在的習(xí)慣是任何外部來源的 JSON不管是接口返回還是配置文件進(jìn)業(yè)務(wù)邏輯前先過一遍 schema。有一次線上事故就是配置文件里port寫成了字符串8080解析沒報(bào)錯(cuò)但后續(xù)拼接 URL 時(shí)出了玄學(xué)問題查了兩小時(shí)。從那以后我每次加載 JSON 配置都強(qiáng)制走一遍校驗(yàn)寧可啟動(dòng)時(shí)多花幾毫秒也不讓臟數(shù)據(jù)跑到運(yùn)行時(shí)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取