JSON解析器之jsonschema校验及代码实现
项⽬有个业务需要对JSON格式的数据校验,需要⼀些必要字段的验证,实现⼀个JSON解析器。所以学习了json schema的语法和解析器的实现。
本篇是先说通⽤的JSON验证,也就是json schema和在java代码中的校验使⽤。
json schema是什么
json schema实际上就是⼀个JSON⽂件,⽂件内容是对JSON数据的结构及内容的约束,就像是xml⽂件的xsd⽂件对xml的验证。
先看⼀下简单的schema内容
1 {
2 "$schema": "/draft-07/schema#",
3 "title": "这是个标题",
4 "description": "校验模板内容json格式",
5 "type": "object",
6 "properties": {
7 "name": { "type": "string" },
8 "credit_card": { "type": "number" },
9 "job_arr": {
10 "type": "array",
11 "items": {
12 "type": "string"
13 }
14 },
15 "billing_address": {
16 "type": "object",
17 "properties": {
18 "selfId": {
19 "type": "string"
20 }
21 }
22 }
23 },
24 "dependencies": {
25 "credit_card": ["billing_address"]
26 },
27 "required": ["name"]
28 }
json schema关键字
关键字描述
$schema表⽰该JSON Schema使⽤的版本规范,⾮必填,⽬前最新⼀版“Draft-07”是2019.09发布的。每个版本的语法可能有出⼊,⽅便以后⼈员维护建议使⽤
title JSON Schema⽂件的标题,⾮必填
description JSON Schema⽂件的描述信息,⾮必填
json值的类型有哪些type待校验元素的类型(例如,最外层的type表⽰待校验的是⼀个JSON对象,内层type分别表⽰待校验的元素类型为,number,string,array,object)
properties JSON对象中,各个key-value对中value的限制条件
required校验的JSON对象中,必须存在的key,不存在则校验失败
typele类型常见的取值
string,object,array,integer(只能是int),number(float或者int),null,boolean
string
maxLength: 校验string字符串的最⼤长度。超出长度校验失败。
minLength: 校验string字符串的最⼩长度。⼩于长度校验失败。
pattern: 字符串满⾜指定的正则表达式,才算通过校验。
format: 不常⽤,值只能是以下的取值date-time(时间格式)、email(邮件格式)、hostname(⽹站地址格式)、ipv4、ipv6、uri、uri-reference、uri-template、json-pointer。假如要校验的字符串是邮箱格式的可以使⽤"forma"t:"email",⽽不⽤pattern⾃⼰去指定正则表达式。
object
properties: 每个key对应的值,都是⼀个json schema,则待校验JSON对象通过校验。从这⾥,我们可以看到,json schema的校验检测,这个对象才算是通过校验。
required: 值是个字符串数组,数组元素是本级的属性key。该关键字限制了JSON对象中必须包含哪些本级key。如果当然json不包含数组中的key则校验失败。
dependencies: 设置属性依赖,值是⼀个json schema。例如
"dependencies": {"credit_card":["billing_address"]},
表⽰有字段"credit_card"就必须有"billing_address"字段。但是这个依赖是单向的。有"billing_address"字段可以没
有"credit_card"。
array
items: 值是⼀个有效的JSON Schema或者⼀组有效的JSON Schema。只有待校验JSON数组中的所有元素均通过校验,整个数组才算通过校验。
例如:{"type": "array","items": { "type": "string", "minLength": 5 }} 这个数组只有满⾜长度⼤于5才会通过校验
uniqueItems: 值是⼀个布尔值,即boolean(true、false)。当该关键字的值为true时,只有待校验JSON数组中的所有元素都具有唯⼀性时,才能通过校验。
这⾥只是简单的列举了⼀些常⽤的关键字,如果想要学习更多的使⽤⽅法,可以去看下官⽅⽂档⾥⾯会有更详细的⽤例。
再分享两个链接
在程序中实现对json数据的校验
中java语⾔对json schema的实现⽅式有三种
everit-org/json-schema draft-07, -06, -04 (Apache License 2.0)
Justify draft-07, -06, -04 (Apache License 2.0)
networknt/json-schema-validator draft-07, -06, -04 Support OpenAPI 3.0 with Jackson parser (Apache License 2.0)
本篇介绍的是第三种---第三⽅⼯具feg
导⼊依赖fge包,因为fge的⽅法要⽤到jsonNode,所以也就需要导⼊jackson的包
1 <!-- fge -->
2 <dependency>
3 <groupId>com.github.fge</groupId>
4 <artifactId>json-schema-validator</artifactId>
5 <version>2.2.6</version>
6 </dependency>
7 <!-- fasterxml -->
8 <dependency>
9 <groupId>com.</groupId>
10 <artifactId>jackson-core</artifactId>
11 <version>2.3.0</version>
12 </dependency>
13 <dependency>
14 <groupId>com.</groupId>
15 <artifactId>jackson-databind</artifactId>
16 <version>2.3.0</version>
17 </dependency>
将JSON数据转成jsonNode:
1/**
2 * @param jsonStr 验证json字符串
3*/
4private static JsonNode strToJsonNode(String jsonStr) {
5 JsonNode jsonNode = null;
6try {
7 jsonNode = JsonLoader.fromString(jsonStr);
8 } catch (IOException e) {
9 e.printStackTrace();
10 }
11return jsonNode;
12 }
获取本地的josn schema⽂件:
基于springboot项⽬,schema.json约束⽂件放在了resources/static/ ⽂件夹下
String jsonFilePath = "classpath:static/schema.json";
通过spring的⼯具类File(jsonFilePath)获取到⽂件的绝对路径
使⽤classpath:⽅法的好处就是不⽤在代码中写绝对路径。部署项⽬时不需要关⼼⽂件的位置。只要项⽬中的static⽂件中有schema.json⽂件就能获取到
1/**
2 * @param jsonFilePath jsonSchema⽂件路径
3*/
4private static JsonNode schemaToJsonNode(String jsonFilePath) {
5 JsonNode jsonSchemaNode=null;
6try {
7 jsonSchemaNode= new JsonNodeReader().fromReader(new File(jsonFilePath)));
8 } catch (IOException e) {
9 e.printStackTrace();
10 }
11return jsonSchemaNode;
12 }
schema校验代码实例:
1/**
2 * @param jsonNode json数据node
3 * @param schemaNode jsonSchema约束node
4*/
5private static boolean getProcessingReport(JsonNode jsonNode, JsonNode schemaNode) {
6//fge验证json数据是否符合json schema约束规则
7 ProcessingReport report = JsonSchemaFactory.byDefault().getValidator().validateUnchecked(schemaNode, jsonNode);
8if (report.isSuccess()) {
9// 校验成功
10return true;
11 } else {
12 Iterator<ProcessingMessage> it = report.iterator();
13 StringBuilder ms = new StringBuilder();
14 ms.append("json格式错误: ");
15while (it.hasNext()) {
16 ProcessingMessage pm = it.next();
17if (!LogLevel.WARNING.LogLevel())) {
18 ms.append(pm);
19 }
20 }
21 println(ms);
22return false;
23 }
24 }
写在最后
本篇⽂章只为了记录和分享⾃⼰学习的成果,能够帮助更多的⼩伙伴当然是更好了,如果有错误欢迎指出。谢谢!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论