JSON Schema校验数据

参考 JSON Schema 规范(中文版)官方网站JSON Schema


对于数据对接系统来说,接口的数据入参校验尤为重要,使用javax.validation相关注解进行校验对于java对象的关联太大,数据结构变动后必须开发人员调整java对象才能满足校验。为了让数据校验和java对象解耦,研究后发现可以使用JSON Schema来实现,定义好相关的schema文件,这个文件可以放在任意可访问的地方,也不需要关心需要校验的数据是属于那个java对象。只要熟悉JSON和一些schema语法,schema文件甚至可以由非开发人员编写。

JSON Schema学习

JSON Schema是什么?

JSON Schema本身也是JSON,它表现的是数据,是描述数据结的声明性格式,并不是程序。所以,它在表现元素之间的关联关系上一定限制。

Schema声明

使用$schema来声明使用的JSON模式规范是哪个版本: draft-04

{
  "$schema": "http://json-schema.org/draft-04/schema#"
}

关键字

definitions

在definitions中定义的规则可以重复使用
"#"表示JSON的根节点

{
    "definitions": {
        "address": {
            "type": "object",
            "properties": {
                "street_address": { "type": "string" },
                "city":           { "type": "string" },
                "state":          { "type": "string" }
            },
            "required": ["street_address", "city", "state"]
        }
    }"type": "object",
    "properties": {
        "billing_address": { "$ref": "#/definitions/address" },
        "shipping_address": { "$ref": "#/definitions/address" }
    }
}
title

标题

description

详细的说明

type

数据类型,支持:array,object,string,Integer,number, null;

properties

type是object时具有成员属性

required

properties中的必填属性都放在这里

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "attachmentCode": {
        "type": "string"
      },
      "attachmentFileName": {
        "type": "string"
      },
      "md5": {
        "type": "string"
      }
    },
    "required": ["md5"]
  }
}

不同type下校验关键字

array
  • items 数组中的成员属性规则,可以包含不同类型的成员变量规则
{
  "type": "array",
  "items": [
    {
      "type": "object",
      "properties": {
        "attachmentCode": {
          "type": "string"
        },
        "attachmentFileName": {
          "type": "string"
        },
        "fileType": {
          "type": "string"
        },
        "dataTimestamp": {
          "$ref": "#/must_time"
        },
        "md5": {
          "type": "string"
        }
      }
    },
    {
      "type": "string",
      "minLength": 5
    },
    {
      "type": "number",
      "minimum": 10
    },
    {
      "type": "string"
    }
  ]
}
  • additionalItems 表达除了已申明的元素外,剩余的元素需要满足的条件
{
  "type": "array",
  "items": [
    {
      "type": "string",
      "minLength": 5
    },
    {
      "type": "number",
      "minimum": 10
    }
  ],
  "additionalItems": {
    "type": "string",
    "minLength": 2
  }
}

上面的JSON Schema的意思是,待校验JSON数组第一个元素是string类型,且可接受的最短长度为5个字符,第二个元素是number类型,且可接受的最小值为10,剩余的其他元素是string类型,且可接受的最短长度为2。

  • minItems 最少存在的元素数量
  • maxItems 最大存在的元素数量
  • uniqueItems 元素是否唯一
  • contains 包含,只要对数组中的一项或多项进行验证通过即可
{
   "type": "array",
   "contains": {
     "type": "number"
   }
}

["life", "universe", "everything", 42] // OK,包含一个number元素
["life", "universe", "everything", "forty-two"]  // not OK,不包含number元素
[1, 2, 3, 4, 5] // OK
object
  • minProperties, maxProperties

规定最少、最多有几个属性成员。

  • additionaProperties

规定object类型是否允许出现不在properties中规定的属性,只能取true/false。

integer/number
  • **multipleOf: **该关键字的值是一个大于0的number,即可以是大于0的int,也可以是大于0的float。

只有待校验的值能够被该关键字的值整除,才算通过校验。

如果含有该关键字的JSON Schema如下:

{
"type": "integer",
"multipleOf": 2
}

那么,246都是可以通过校验的,但是,357都是无法通过校验的,
当然了,2.04.0也是无法通过校验的。

如果含有multipleOf关键字的JSON Schema如下:
{ "type": "number", "multipleOf": 2.0 }
那么,22.044.0都是可以通过校验的,但是,33.0都是无法通过校验的。
  • maximum:

元素可以通过校验的最大值

  • exclusiveMaximum:

该关键字通常和maximum一起使用,当该关键字的值为true时,表示待校验元素必须小于maximum指定的值;当该关键字的值为false时,表示待校验元素可以小于或者等于maximum指定的值。

  • minimum:

元素可以通过的最小值

  • exclusiveMinimum:

exclusiveMaximum相反

string
  • maxLength:字符串通过校验的最大长度
  • minLength:字符串通过校验的最小长度
  • pattern:正则匹配
  • format:
format只能是以下值:
date-time(时间格式)、email(邮件格式)、hostname(网站地址格式)、
ipv4、ipv6、uri、uri-reference、uri-template、json-pointer。
所有类型都可以用的关键字
  • dependencies

规定某些成员的依赖成员,不能在依赖成员缺席的情况下单独出现,属于数据完整性方面的约束。
有"credit_card"属性,则"billing_address" 属性不能缺席:

{
    "type": "object",
    "dependencies": {
        "credit_card": ["billing_address"]
    }
}
  • enum、

该关键字的值是一个数组,该数组至少要有一个元素,且数组内的每一个元素都是唯一的。
如果待校验的JSON元素和数组中的某一个元素相同,则通过校验。否则,无法通过校验。
该数组中的元素值可以是任何值,包括null。

  • const、

元素被限定为一个常量值

  • allOf、

必须满足全部的检验才能通过

  • anyOf、

满足一个或多个校验可以通过

  • oneOf、

只能满足一个校验才能通过

  • not、

不满足这个校验才能通过

  • default、

关键字指定一个默认值

JSON Schema编写

java对象生成schema工具reinert

<dependency>
    <groupId>com.github.reinert</groupId>
    <artifactId>jjschema</artifactId>
    <version>1.16</version>
</dependency>

实际应用场景中,重复引用的情况比较多,这里说明下引用的使用

  1. 将公共的校验规则提取出来成独立的schema文件
  2. 两种引用方式:
    1. 先用 i d 定 义 , 在 使 用 id定义,在使用 id使ref引用

在draft 4 中, i d 只 是 i d ( 没 有 id 只是 id(没有 idid符号)

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "description": "定义时间字段的匹配规则",
    "must_time": {
      "description": "必填时间字段规则",
      "oneOf": [
        {
          "type": "string",
          "pattern": "(\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2})|(\\d{4}-\\d{1,2}-\\d{1,2})$|^\\d{1,13}$"
        },
        {
          "type": "number"
        }
      ]
    },
    "not_time": {
      "description": "非必填时间字段",
      "oneOf": [
        {
          "type": "string",
          "pattern": "(\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2})|(\\d{4}-\\d{1,2}-\\d{1,2})$|^\\d{1,13}$"
        },
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ]
    }
  }
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "id": "file:/E:/Time.json", //定义引用
  "items": {
    "type": "object",
    "properties": {
      "attachmentCode": {
        "type": "string"
      },
      "attachmentFileName": {
        "type": "string"
      },
      "fileType": {
        "type": "string"
      },
      "dataTimestamp": {
        "$ref": "#/must_time" //直接使用引用中的规则,对于重复引用的书写较为友好
      },
      "md5": {
        "type": "string"
      }
    }
  }
}
  1. 直接$ref引用文件:
{
  "attachment": {
     "$ref": "file:/E:/Attachment.json" //使用整个schema文件的校验规则
    "$ref": "file:/E:/Attachment.json#/age" //使用文件根节点下的age的校验规则
     "$ref": "file:///Attachment.json#/age" //linux环境使用文件根节点下的age的校验规则
  }
}

JSON Schema使用

因为需要使用校验的结果,所以使用了fge这个库,性能上会差一点,支持草案draft-04 draft-03
官方也提供了一些开源工具schema工具http://json-schema.org/implementations.html

<dependency>
    <groupId>com.github.java-json-tools</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>2.2.14</version>
</dependency>

代码实现

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fzzn.water.check.core.factory.CheckBuildFactory;
import com.github.fge.jackson.JsonLoader;
import com.github.fge.jackson.JsonNodeReader;
import com.github.fge.jsonschema.core.report.ProcessingMessage;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchemaFactory;

import java.io.FileReader;
import java.util.Iterator;

sonNode schemaJson = new JsonNodeReader().fromReader(new FileReader("schema文件路径"));
JsonNode dataNoe = JsonLoader.fromString("待校验的JSON字符串");
ProcessingReport processingMessages = JsonSchemaFactory.byDefault().getValidator()
    .validate(schemaJson, dataNoe, true);//true: 全部校验完再返回
System.out.println(processingMessages.isSuccess());
Iterator<ProcessingMessage> iterator = processingMessages.iterator();
JSONObject jsonNode;
while (iterator.hasNext()) {
    ProcessingMessage message = iterator.next();
    jsonNode = JSONUtil.parseObj(message.asJson().toString());
    System.out.println("------>" + jsonNode.toString());
    System.out.println("======>" + message);
}

输出示例:

------>{"schema":{"pointer":"/items/properties/md5","loadingURI":"#"},"instance":{"pointer":"/0/md5"},"level":"error","expected":["string"],"message":"instance type (null) does not match any allowed primitive type (allowed: [\"string\"])","found":"null","domain":"validation","keyword":"type"}
======>error: instance type (null) does not match any allowed primitive type (allowed: ["string"])
    level: "error"
    schema: {"loadingURI":"#","pointer":"/items/properties/md5"}
    instance: {"pointer":"/0/md5"}
    domain: "validation"
    keyword: "type"
    found: "null"
    expected: ["string"]

拿到JSON格式的校验的结果,就可以针对性的处理了。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用 Java 语言编写程序来校验 JSON Schema 是非常容易的,可以使用许多库和框架来帮助您实现它。有许多第三方库和框架可以用于校验 JSON 格式,这些库和框架包括:Jackson,Gson,Genson,Apache Commons,Hibernate Validator,JsonSchemaJsonPath 和 FastJSON。 ### 回答2: 在Java中,可以使用现有的库来编写代码,使用jsonSchema校验数据。下面是使用Java编写的示例代码: 首先,需要导入相关的依赖库,例如使用Jackson库来处理JSON数据和使用json-schema-validator库来执行jsonSchema校验。可以通过Maven或Gradle等构建工具来管理依赖。 接下来,创建一个方法来执行校验操作。首先,需要定义jsonSchema的规则,可以使用JSON字符串或从外部文件中加载。然后,需要将待校验数据转换为JSON对象,可以使用Jackson库将字符串解析为JSON对象。 然后,使用json-schema-validator库中的JsonSchemaFactory类来创建JsonSchema实例。使用JsonSchema的validate方法对JSON数据进行校验,该方法会返回校验结果。 最后,根据校验结果进行相应的处理,可以输出校验失败的原因或执行其他操作。 以下是一个简单的示例代码: ```java import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.fge.jsonschema.core.exceptions.ProcessingException; import com.github.fge.jsonschema.core.report.ProcessingReport; import com.github.fge.jsonschema.main.JsonSchema; import com.github.fge.jsonschema.main.JsonSchemaFactory; public class JsonValidator { public static void main(String[] args) { String schema = "{ \"type\": \"object\", \"properties\": { \"name\": { \"type\": \"string\" } } }"; String data = "{ \"name\": \"John\" }"; boolean isValid = validateData(schema, data); if (isValid) { System.out.println("Data is valid."); } else { System.out.println("Data is invalid."); } } public static boolean validateData(String schemaString, String dataString) { ObjectMapper objectMapper = new ObjectMapper(); JsonNode schemaNode, dataNode; try { schemaNode = objectMapper.readTree(schemaString); dataNode = objectMapper.readTree(dataString); } catch (Exception e) { e.printStackTrace(); return false; } JsonSchemaFactory schemaFactory = JsonSchemaFactory.byDefault(); try { JsonSchema schema = schemaFactory.getJsonSchema(schemaNode); ProcessingReport report = schema.validate(dataNode); return report.isSuccess(); } catch (ProcessingException e) { e.printStackTrace(); return false; } } } ``` 以上代码使用了Jackson库将schema数据解析为JSON节点,然后使用json-schema-validator库来创建JsonSchema对象,并使用validate方法进行校验。最后根据校验结果输出相应的信息。 当运行以上代码时,如果数据满足schema的定义,会输出"Data is valid.",否则输出"Data is invalid."。这个示例中使用了简单的schema数据进行校验,实际使用中可以根据需要定义更复杂的schema,并使用更复杂的校验逻辑。 ### 回答3: 使用Java编写可以使用以下步骤来使用jsonSchema校验数据。 首先,你需要引入json-schema-validator库。你可以在Maven或Gradle中添加以下依赖项: 对于Maven: ```xml <dependency> <groupId>org.everit.json</groupId> <artifactId>org.everit.json.schema</artifactId> <version>1.12.1</version> </dependency> ``` 对于Gradle: ```groovy implementation 'org.everit.json:org.everit.json.schema:1.12.1' ``` 接下来,你需要创建一个json schema的字符串或从文件中读取json schema。假设你有以下的json schema字符串: ```json String schemaStr = "{\n" + " \"type\": \"object\",\n" + " \"properties\": {\n" + " \"name\": {\n" + " \"type\": \"string\"\n" + " },\n" + " \"age\": {\n" + " \"type\": \"integer\"\n" + " }\n" + " },\n" + " \"required\": [\"name\", \"age\"]\n" + "}"; ``` 然后你可以使用下面的代码来校验数据: ```java import org.everit.json.schema.Schema; import org.everit.json.schema.ValidationException; import org.everit.json.schema.loader.SchemaLoader; import org.json.JSONObject; import org.json.JSONTokener; class Main { public static void main(String[] args) { String dataStr = "{\"name\":\"John\", \"age\":30}"; try { JSONObject jsonSchema = new JSONObject(new JSONTokener(schemaStr)); JSONObject jsonData = new JSONObject(new JSONTokener(dataStr)); Schema schema = SchemaLoader.load(jsonSchema); schema.validate(jsonData); System.out.println("数据是有效的"); } catch (ValidationException e) { System.out.println("数据无效:" + e.getMessage()); } } } ``` 以上代码将创建一个Schema对象,并使用Schema.validate方法来验证数据。如果数据有效,将输出“数据是有效的”,否则将输出"数据无效"及详细错误信息。 这就是使用Java编写jsonSchema校验数据的基本步骤。你可以根据自己的需求修改json schema数据,并在代码中进行相应的处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值