java验证json格式是否符合要求
在日常开发过程中,会有这样的需求来验证json是否是我们想要的数据格式。如果判断每个层次,基本上不可能实现。当然,java有开源工具,我们可以直接使用它
JSON SchemaJSON Schema 是用于验证 JSON Schema可以理解为强大的数据结构工具的模式或规则。
Json Schema定义了一套定义Json元数据的词汇和规则,元数据也以Json数据的形式表达。Json元数据定义了Json数据需要满足的规范,包括成员、结构、类型、约束等。
JSON Schema 它是json的格式描述、定义和模板。有了他,任何符合要求的json数据都可以生成
json-schema-validator在java中,使用json数据格式进行验证 json-schema-validator
,具体例子如下:
<dependency> <groupId>com.github.fge</groupId> <artifactId>json-schema-validator</artifactId> <version>2.2.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.3.0</version> </dependency>
jackson-core
和 jackson-core
必须引入,他们是为了 json-schema-validator
必须的
若要验证的数据格式如下:
{ "data": [ { "sex": "男", "name": “王小明”, "age": 18 }, { "sex": "女", "name": “王小红”, "age": 17 } ], "type": "human"}
外面是type和data,里面是一个数组,包括sex、name、age
编写schema文件
{ "type": "object", "properties": { "type": { "type": "string" }, "data": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 3 }, "sex": { "enum": [ "男", "女" ] }, "age": { "type": "number" } }, "required": [ "name", "sex", "age" ] } } }, "required": [ "type", "data" ]}
上述json描述了目标json的数据格式,外层必须字段type、data,内部限制了name的最大长度 maxLength
为3,sex 为枚举值,只能取 男女字符串,age 为number类型。
public Map validatorJsonUnchecked(String body) { Map<String, String> map = new HashMap<>(); String filePath = "validator" + File.separator + "validator.json"; ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNodeSchema = objectMapper.readTree(ResourceUtil.readutf8Str(filePath)); JsonNode jsonNode = objectMapper.readTree(body); ProcessingReport processingReport = JsonSchemaFactory.byDefault().getValidator().validate(jsonNodeSchema, jsonNode, true); if (!processingReport.isSuccess()) { processingReport.forEach(processingMessage -> { JsonNode missing = processingMessage.asJson().get("missing"); String keyword = processingMessage.asJson().get("keyword").asText(); // 若缺失字段 if (!Objects.isNull(missing)) { missing.forEach(miss -> { String text = miss.asText(); map.put(text, text + " 字段缺失”); }); // 假如字段超长 } else if ("maxLength".equals(keyword)) { String field = processingMessage.asJson().get("instance").get("pointer").asText(); String value = processingMessage.asJson().get("value").asText(); field = field.substring(field.lastIndexOf("/") + 1); map.put(field, value + " 字段长度过长”); // 若不在枚举范围内 } else if ("enum".equals(keyword)) { String field = processingMessage.asJson().get("instance").get("pointer").asText(); String value = processingMessage.asJson().get("value").asText(); field = field.substring(field.lastIndexOf("/") + 1); map.put(field, field + “字段值错误," + value + "不在枚举范围内"; } else if ("type".equals(keyword)) { String field = processingMessage.asJson().get("instance").get("pointer").asText(); String found = processingMessage.asJson().get("found").asText(); String expected = processingMessage.asJson().get("expected").toString(); field = field.substring(field.lastIndexOf("/") + 1); map.put(field, field + " 类型错误,现有类型: " + found + ", 预期类型:“ + expected); } }); } } catch (IOException | ProcessingException e) { log.error(“Json格式异常验证”, e); } return map; }
上述代码首先获得 json的标准文件需要验证 validator.json
,然后调用 JsonSchemaFactory.byDefault().getValidator().validate(jsonNodeSchema, jsonNode, true)
方法对传进的json进行json 在这里进行校验 true
这意味着深度检查。如果没有这个参数,在检查json时遇到第一个错误,它将直接返回
接下来,构建测试方法
public static void main(String[] args) { ValidatorService validatorService = new ValidatorServiceImpl(); Map<String, Object> body = new HashMap<>(); HashMap<String, Object> one = new HashMap<String, Object>() {{ put("name", “王小明”); put("sex", "男"); put("age", 18); }}; HashMap<String, Object> two = new HashMap<String, Object>() {{ put("name", "王小明1"; put("sex", "未知"); put("age", "18"); }}; body.put("type", "human"); body.put("data", Arrays.asList(one,two)); Map map = validatorService.validatorJsonUnchecked(JSONUtil.toJsonStr(body)); System.out.println(map); }
4. 执行结果{sex=sex字段值错误,未知不在枚举范围内, name=王小明1 字段长度过长, age=age 类型错误,现有类型: string, 预期类型:["integer","number"]}
5. 整理总结假如schema 在编写列表时,中括号用于列表 []
,然后,当验证时,只会验证数组中的第一个,这是一个坑,如下
{ "type": "object", "properties": { "type": { "type": "string" }, "data": { "type": "array", "items": [ { "type": "object", "properties": { "name": { "type": "string", "maxLength": 3 }, "sex": { "enum": [ "男", "女" ] }, "age": { "type": "number" } }, "required": [ "name", "sex", "age" ] } ] } }, "required": [ "type", "data" ]}
如果是这样的话,只会验证 data 数组第一条数据,其他错误不会报错!!
JSON Schema 功能强大,支持表达式,支持是否允许额外属性,支持逻辑组合等。如果您想了解更新json校验的知识,请参考以下参考文件
参考文档<https://www.tulingxueyuan.cn/d/file/p/20230531/hm3vozp3zuq.html