简介:这份资源是一套面向Java初学者与Web开发入门者的JSON实战示例包,围绕JSON这一轻量级数据交换格式,帮助读者理解键值对结构、数据类型、语法规则以及解析与生成的基本用法。压缩包共22个文件,以14个jar依赖库为主,辅以2个java源码、2个class编译文件,以及classpath、project、prefs等Eclipse工程配置和一份json笔记,整体约2.88MB,可直接导入IDE运行调试。内容覆盖JSON对象、数组、嵌套结构及AJAX请求中JSON.parse()等典型场景,并借助json-lib、commons系列等库演示不同解析方式。目前已有3576人学习下载,适合希望快速上手JSON、对照示例代码查漏补缺的开发者参考。
1. 从一份“能跑通”的 json 完整例子说起:为什么你抄的示例总在真实场景翻车
很多人第一次搜「json完整例子」,想要的东西其实很朴素:一份能直接复制、字段齐全、嵌套结构清晰、最好还带点真实业务味道的 JSON 样本。但真正落到项目里,你会发现网上那些{"name":"张三","age":18}级别的例子根本不够用——接口返回的是三层嵌套加数组,配置文件里混着注释和转义,日志里一行 JSON 被压成了 8KB 的单行文本。json 格式本身不复杂,难的是它在真实工程里的形态千奇百怪:json 数组套对象、对象里再塞 json 字符串、时间戳和枚举混用、null 和空字符串语义不同。这篇笔记不打算给你一份“标准答案”,而是把一份完整 JSON 例子从设计、生成、解析、校验到排错的全链路拆开讲。适合谁看?后端写接口的、前端对接字段的、测试做数据构造的、运维改配置的,只要你每天要跟 json 文件打交道,这里面的参数和坑都用得上。
2. 一份完整 JSON 例子该长什么样:字段设计、嵌套层级与类型约定
2.1 先定结构再写值:对象、数组、嵌套的三层组织法
一份“完整”的 JSON 例子,完整不体现在字段多,而体现在结构能覆盖你业务里所有形态。我一般按三层来组织:最外层是元信息(版本、时间、状态),中间层是主体数据(对象或数组),最内层是明细项。以电商订单为例,外层放orderId、createdAt、status,中间层放items数组,数组每个元素再嵌套sku对象。这样一份例子既能演示 json 数组,又能演示对象嵌套,还能演示类型混用。
{ "orderId": "ORD-20260115-0001", "createdAt": "2026-01-15T10:23:45+08:00", "status": "PAID", "totalAmount": 299.00, "items": [ { "sku": { "id": "SKU-1001", "name": "无线键盘", "spec": "87键/青轴" }, "quantity": 1, "unitPrice": 199.00, "tags": ["数码", "外设"] }, { "sku": { "id": "SKU-2003", "name": "鼠标垫", "spec": "900x400mm" }, "quantity": 2, "unitPrice": 50.00, "tags": [] } ], "address": null, "remark": "" }这段例子里有几个刻意设计:createdAt用带时区的 ISO 8601 而不是时间戳,address用null表示“未填写”,remark用空字符串表示“填了但为空”,tags有一个是空数组。这四种状态在真实接口里语义完全不同,如果你的例子只写有值的情况,对接方一定会来问你“这个字段没值的时候传什么”。
2.2 类型约定表:哪些字段必须固定,哪些允许 null
写例子之前先把类型约定列成表,比事后改字段省事得多。下面是我做接口文档时常用的约定模板:
| 字段 | 类型 | 是否必填 | 允许 null | 说明 |
|---|---|---|---|---|
| orderId | string | 是 | 否 | 业务主键,格式 ORD-日期-序号 |
| createdAt | string | 是 | 否 | ISO 8601,必须带时区 |
| status | string | 是 | 否 | 枚举:CREATED/PAID/SHIPPED/CLOSED |
| totalAmount | number | 是 | 否 | 两位小数,单位元 |
| items | array | 是 | 否 | 至少一个元素 |
| address | object | 否 | 是 | null 表示未填写 |
| remark | string | 否 | 否 | 空字符串表示无备注 |
这张表的价值在于:它把“例子”升级成了“契约”。你给对接方的不是一段 JSON,而是一份带约束的 JSON。后面无论用 json 转换工具、写校验脚本还是做 mock 数据,都从这张表出发。
2.3 用 Python 生成可复现的完整例子
手写 JSON 容易漏字段、错逗号,我一般用脚本生成,保证每次结构一致。
import json from datetime import datetime, timezone, timedelta def build_order(order_id: str) -> dict: tz = timezone(timedelta(hours=8)) return { "orderId": order_id, "createdAt": datetime.now(tz).isoformat(), "status": "PAID", "totalAmount": 299.00, "items": [ { "sku": {"id": "SKU-1001", "name": "无线键盘", "spec": "87键/青轴"}, "quantity": 1, "unitPrice": 199.00, "tags": ["数码", "外设"], } ], "address": None, "remark": "", } # ensure_ascii=False 保留中文,indent=2 便于人读 print(json.dumps(build_order("ORD-20260115-0001"), ensure_ascii=False, indent=2))ensure_ascii=False是关键参数,不加的话中文会变成\u65e0\u7ebf这种转义,人看着累。indent=2控制缩进,生产环境传输时反而要去掉缩进省带宽,所以生成和传输要用两套参数。datetime.now(tz)带时区,避免服务器时区不一致导致时间字段对不上。
3. 解析与查询:从 json 文件读取到 json 查询函数的实战路径
3.1 读取本地 json 文件的三种姿势与编码坑
json 文件最常见的翻车点不是语法,是编码。Windows 上记事本另存为 UTF-8 可能带 BOM,读出来第一个字符是\ufeff,json.loads直接报Expecting value: line 1 column 1。我一般统一用utf-8-sig读,它能自动吃掉 BOM。
import json # 方式一:一次性读入,适合小文件 with open("order.json", "r", encoding="utf-8-sig") as f: data = json.load(f) # 方式二:逐行读 JSON Lines,适合日志类大文件 def read_jsonl(path): with open(path, "r", encoding="utf-8-sig") as f: for line in f: line = line.strip() if line: yield json.loads(line) # 方式三:流式解析超大文件,避免一次性吃内存 # 常见做法是用 ijson 这类库做增量解析方式一适合配置文件,方式二适合每行一个 JSON 的日志,方式三适合几百 MB 以上的导出文件。选错方式最典型的后果就是内存爆掉,进程被系统杀掉,日志里只留一个Killed,查半天查不到原因。
3.2 json 查询函数怎么写:路径取值与容错
从嵌套 JSON 里取值,新手常写data["a"]["b"]["c"],中间任何一层缺失就抛KeyError。我一般封装一个带默认值的取值函数,这也是很多 json 查询函数库的核心思路。
def jget(data, path, default=None): """按 a.b.0.c 的路径取值,数组用数字下标""" cur = data for key in path.split("."): if isinstance(cur, list): try: cur = cur[int(key)] except (ValueError, IndexError): return default elif isinstance(cur, dict): if key not in cur: return default cur = cur[key] else: return default return cur # 用法 print(jget(data, "items.0.sku.name")) # 无线键盘 print(jget(data, "address.city", "未知")) # 未知这个函数把“路径不存在”和“类型不对”都收敛成返回默认值,调用方不用写一堆 try。参数path用点号分隔,数组下标直接写数字,default决定缺失时的兜底。生产环境里我还会加一层类型校验,比如期望是数字却拿到字符串时打警告日志,避免脏数据静默流过。
3.3 用 jq 在命令行里查 JSON:比写脚本快
排查线上问题时,我经常直接拿 jq 在终端里查,比开编辑器写脚本快得多。
# 取所有商品的名称 jq '.items[].sku.name' order.json # 过滤数量大于 1 的项 jq '.items[] | select(.quantity > 1)' order.json # 把嵌套字段拍平成一行 jq -r '.items[] | [.sku.id, .quantity, .unitPrice] | @tsv' order.json-r去掉输出里的引号,@tsv转成制表符分隔,方便直接喂给其他命令。jq 的select相当于 where 条件,[]表示遍历数组。这几个组合能覆盖八成日常查询需求,不用每次都写 Python。
4. 校验、转换与合并:json 格式校验和 json merge conflict 的处理
4.1 用 JSON Schema 做格式校验,把错误挡在入口
光靠json.loads只能校验语法,校验不了“status 必须是枚举值”“totalAmount 必须是数字”。这时候要用 JSON Schema。
from jsonschema import validate, ValidationError schema = { "type": "object", "required": ["orderId", "createdAt", "status", "items"], "properties": { "orderId": {"type": "string", "pattern": "^ORD-\\d{8}-\\d{4}$"}, "status": {"enum": ["CREATED", "PAID", "SHIPPED", "CLOSED"]}, "totalAmount": {"type": "number", "minimum": 0}, "items": {"type": "array", "minItems": 1}, }, } try: validate(instance=data, schema=schema) except ValidationError as e: print("校验失败:", e.message, "路径:", list(e.path))required列出必填字段,pattern用正则约束格式,enum限定取值范围,minItems保证数组非空。校验失败时e.path会告诉你具体哪个字段出问题,比笼统报“格式错误”好排查得多。这套东西放在接口入口,脏数据根本进不了业务逻辑。
4.2 json 转换:对象转字符串、字符串转对象的边界
json 转换里最容易出事的是“JSON 字符串嵌在 JSON 里”。比如某个字段的值本身是一段 JSON 文本,解析出来是字符串,还得再解析一次。
import json raw = '{"payload": "{\\"userId\\": 1001, \\"action\\": \\"click\\"}"}' outer = json.loads(raw) inner = json.loads(outer["payload"]) # 二次解析 print(inner["userId"]) # 1001判断一个字符串是不是 JSON,不能只看开头是不是{,因为普通文本也可能以{开头。稳妥做法是 try 一次json.loads,失败就当普通字符串。另外对象转字符串时,json.dumps默认会把中文转义,跨系统传输前确认对方能不能正确解码。
4.3 json merge conflict:配置合并时谁覆盖谁
多人维护同一份 JSON 配置,合并冲突几乎是必然。Git 的冲突标记会直接插进 JSON 里,导致文件语法都不合法。
# 冲突后的文件里会出现这种标记,json.loads 必然失败 # <<<<<<< HEAD # "timeout": 30 # ======= # "timeout": 60 # >>>>>>> feature-branch处理原则是先解决语法,再解决语义。语法层面把<<<<<<<、=======、>>>>>>>三行删掉,选一个值。语义层面要定规则:数组是追加还是替换,对象是深合并还是浅覆盖。我一般约定对象深合并、数组整体替换,避免出现“两个分支各加了一个元素,合并后重复”的情况。合并完必须跑一次校验,确认没有残留冲突标记。
5. 避坑与排查:json 完整例子落地时最常见的 5 个翻车现场
5.1 现象:解析报 “Expecting value: line 1 column 1”,原因:BOM 或空文件
这个报错几乎全发生在文件开头。要么是 UTF-8 BOM,要么文件根本是空的,要么开头有不可见字符。解决:读文件统一用utf-8-sig,读之前先判断文件大小是否为 0,必要时打印前 10 个字节的十六进制看有没有ef bb bf。
5.2 现象:数字精度丢失,原因:大整数或高精度小数被浮点吃掉
JSON 本身不区分整数和浮点,但很多语言解析时默认转成 double。订单号如果是 19 位纯数字,解析后末几位会变。解决:ID 类字段一律用字符串,金额用字符串或定点数库,别用原生 float。
5.3 现象:中文变乱码或转义,原因:编码参数没统一
写入时用了ensure_ascii=True,读出来就是\uXXXX;文件是 GBK 编码却按 UTF-8 读,就是乱码。解决:全链路统一 UTF-8,生成时ensure_ascii=False,读文件时显式指定encoding,不要依赖系统默认。
5.4 现象:嵌套太深取值取不到,原因:路径写错或中间层是数组
data["items"]["sku"]这种写法在items是数组时必然失败,因为数组要用下标。解决:用前面封装的jget函数,或者先用type()确认每一层的实际类型,别凭记忆写路径。
5.5 现象:合并后 JSON 语法合法但数据重复,原因:数组被深合并
两个分支各往同一个数组里加了一个元素,深合并后变成两个都在。解决:明确数组用替换策略,合并后写脚本检查关键数组长度是否符合预期,别只看语法校验通过就放心。
6. 进阶技巧:用大模型辅助生成和翻译 json 字段时的可控做法
现在很多人用大模型帮忙生成 JSON 例子或者翻译字段值,效率确实高,但直接让它输出整段 JSON 经常翻车——多一个逗号、少一个引号、把数字写成字符串。我的做法是分两步:先让模型输出字段结构(字段名、类型、说明),我自己用脚本生成 JSON;或者让模型只翻译值,结构由代码保证。
# 让模型只返回翻译结果,结构自己拼 def translate_values(data, translate_fn): if isinstance(data, dict): return {k: translate_values(v, translate_fn) for k, v in data.items()} if isinstance(data, list): return [translate_values(v, translate_fn) for v in data] if isinstance(data, str): return translate_fn(data) return data # translate_fn 可以是调用大模型的函数,只处理字符串这样模型只负责它擅长的文本转换,JSON 的语法和结构由代码兜底,不会因为模型多输出一句话就整个解析失败。另一个技巧是让模型输出 JSON Lines 而不是单个大 JSON,每行独立解析,一行坏了不影响其他行。
验证生成结果是否可靠,我一般做三件事:跑一次json.loads确认语法,跑一次 Schema 校验确认结构,再抽样几条人工核对值是否符合业务语义。三步都过,才敢放进测试环境。
最后说个我自己的习惯:每次写完一份 JSON 例子,我都会把它丢进 jq 里跑一遍.,看能不能正常格式化输出。这个动作花不了三秒,但能挡掉八成的低级语法错误。血泪经验就是,别太相信自己的眼睛,逗号和引号这种东西,机器比人靠谱。希望帮到你。
本文还有配套的精品资源,点击获取