json schema校验json字符串(networknt/json-schema-validator)
学习链接
json-schema官网 - 英文
jsonschemavalidator 可在线校验网站
networknt的json-schema-validator github地址
JSON Schema 入门指南:如何定义和验证 JSON 数据结构
JSON Schema入门 - 比较详细
文章目录
- 学习链接
- 1、JSON Schema 入门指南
- 1、引言
- 2、什么是 JSON Schema?
- 3、JSON Schema 的基本结构
- 3.1 基本关键字
- 3.2 对象属性
- 3.3 数组元素
- 3.4 字符串约束
- 3.5 数值约束
- 4、示例:定义一个简单的 JSON Schema
- java示例
- 1、普通属性校验示例
- pom.xml
- SchemaValidatorExample
- ValidationResult
- schema.json
- json-validator-message.properties
- json-validator-message_zh_CN.properties
- ResourceBundleTest
- 2、嵌套属性校验示例
- SchemaValidatorExample
- schema.json
- json-validator-message.properties
- json-validator-message_zh_CN.properties
- 3、$ref 引用
- 1、内部引用
- resources/user-schema.json
- JsonSchemaValidatorDemo
- 2、外部文件引用
- JsonSchemaValidatorDemo
- CommonSchemaLoader
- ==resources/user-schema.json==
- resources/common/address-schema.json
- resources/user-schema.json

1、JSON Schema 入门指南
1、引言
在现代的 Web
开发和数据交换中,JSON
(JavaScript Object Notation)已经成为了一种非常流行的数据格式。它轻量、易读、易于解析,广泛应用于 API
通信、配置文件、数据存储等场景。然而,随着 JSON
数据结构的复杂性增加,如何确保 JSON
数据的有效性和一致性成为了一个挑战。这时,JSON Schema 就派上了用场。
本文将带你入门 JSON Schema,帮助你理解它的基本概念、语法结构,并通过实例演示如何使用 JSON Schema 来定义和验证 JSON
数据结构。
2、什么是 JSON Schema?
JSON Schema
是一种用于描述 JSON
数据结构的规范。它允许你定义 JSON
数据的格式、类型、约束条件等,从而确保 JSON
数据符合预期的结构。通过 JSON Schema
,你可以在数据交换、存储或处理之前,对 JSON
数据进行验证,确保其有效性和一致性。
简单来说,JSON Schema 就像是 JSON
数据的“蓝图”或“合同”,它规定了 JSON
数据应该长什么样子。
3、JSON Schema 的基本结构
一个 JSON Schema 本身也是一个 JSON
对象。它由一系列关键字(keywords)组成,这些关键字用于定义 JSON 数据的结构和约束条件。
3.1 基本关键字
$schema
: 指定使用的 JSON Schema 版本。例如,"$schema": "http://json-schema.org/draft-07/schema#"
表示使用Draft 7
版本的 JSON Schema。$id
: 为 Schema 定义一个唯一的标识符,通常是一个 URL。title
和description
: 分别为 Schema 提供标题和描述信息,便于理解和维护。- type: 定义 JSON 数据的类型。常见的类型有
object、array、string、number、integer、boolean
和null
。
3.2 对象属性
properties
: 定义对象中的各个属性及其对应的 Schema。required
: 指定哪些属性是必须的。additionalProperties
: 控制是否允许对象包含未在properties
中定义的额外属性。
3.3 数组元素
items
: 定义数组中每个元素的 Schema。minItems
和maxItems
: 分别指定数组的最小和最大长度。uniqueItems
: 指定数组中的元素是否必须唯一。
3.4 字符串约束
minLength
和 maxLength: 分别指定字符串的最小和最大长度。pattern
: 使用正则表达式约束字符串的格式。format
: 指定字符串的格式,如 email、date-time 等。
3.5 数值约束
minimum
和 maximum: 分别指定数值的最小和最大值。exclusiveMinimum
和exclusiveMaximum
: 指定数值是否排除最小值和最大值。multipleOf
: 指定数值必须是某个数的倍数。
4、示例:定义一个简单的 JSON Schema
假设我们要定义一个表示用户信息的 JSON 数据结构,要求如下:
- 用户对象必须包含
id
、name
和email
属性。 id
必须是整数。name
必须是字符串,且长度在 1 到 50 之间。email
必须是有效的电子邮件地址。- 用户对象可以包含可选的
age
属性,且必须是正整数。
对应的 JSON Schema 可以这样定义:
{"$schema": "http://json-schema.org/draft-07/schema#","$id": "https://example.com/user.schema.json","title": "User","description": "A user object","type": "object","properties": {"id": {"type": "integer"},"name": {"type": "string","minLength": 1,"maxLength": 50},"email": {"type": "string","format": "email"},"age": {"type": "integer","minimum": 0,"exclusiveMinimum": true}},"required": ["id", "name", "email"],"additionalProperties": false
}
解释
$schema
和$id
分别指定了Schema
的版本和唯一标识符。type
指定了JSON
数据的类型为object
。properties
定义了对象的各个属性及其约束条件。required
指定了id
、name
和email
是必须的属性。additionalProperties
设置为false
,表示不允许对象包含未定义的属性。
java示例
1、普通属性校验示例
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.4</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.zzhua</groupId><artifactId>demo-metrics</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- https://mvnrepository.com/artifact/com.networknt/json-schema-validator --><dependency><groupId>com.networknt</groupId><artifactId>json-schema-validator</artifactId><version>1.5.6</version></dependency><dependency><!-- Used to validate ECMA 262 regular expressions --><!-- Approximately 50 MB in dependencies --><!-- GraalJSRegularExpressionFactory --><groupId>org.graalvm.js</groupId><artifactId>js</artifactId><version>21.3.10</version></dependency><dependency><!-- Used to validate ECMA 262 regular expressions --><!-- Approximately 2 MB in dependencies --><!-- JoniRegularExpressionFactory --><groupId>org.jruby.joni</groupId><artifactId>joni</artifactId><version>2.2.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
SchemaValidatorExample
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.*;
import com.networknt.schema.i18n.ResourceBundleMessageSource;
import com.zzhua.util.ValidationResult;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;public class SchemaValidatorExample {public static void main(String[] args) throws IOException {JsonSchemaFactory schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7);JsonSchema schema = schemaFactory.getSchema(new ClassPathResource("schema/test04/schema.json").getInputStream(),SchemaValidatorsConfig.builder()// 可以去掉JsonNodePath instanceLocation前面的 / 斜线.pathType(PathType.URI_REFERENCE)// 快速失败// .failFast(true)// 自定义消息源(按顺序找指定的文件名。可支持i18n国际化。错误提示中的占位符的值可以看XxxValidator往arguments中设置了哪些值。).messageSource(new ResourceBundleMessageSource(/*"validate/json-validator-message",*/"jsv-messages"))// 自定义消息错误提示属性// (虽然SchemaValidatorsConfig#errorMessageKeyword默认值就是message,// 但是builder中该属性默认是null,所以这里如果不主动设置的话,就会是null).errorMessageKeyword("message").build());ObjectMapper mapper = new ObjectMapper();String jsonStr = """{"age": 5,"sex": true,"email": "haloC","motto": "人心中的成见是一座大山,任你怎么努力使劲,也休想搬动","hobbies": ["java", 666, "spring" ]}""";Set<ValidationMessage> validationMessages = schema.validate(mapper.readTree(jsonStr));List<ValidationResult> results = new ArrayList<>();for (ValidationMessage validationMessage : validationMessages) {results.add(ValidationResult.builder().type(validationMessage.getType()).errMsg(validationMessage.getMessage()).propertyPath(deducePropertyPath(validationMessage)).build());}for (ValidationResult validationResult : results) {System.out.println("-------------------");System.out.println("校验的关键字: " + validationResult.getType());System.out.println("校验的属性: " + validationResult.getPropertyPath());System.out.println("校验的错误提示: " + validationResult.getErrMsg());}}private static String deducePropertyPath(ValidationMessage validationMessage) {// 推断属性名String property = validationMessage.getProperty();if (StringUtils.hasText(property)) {return property;}JsonNodePath instanceLocation = validationMessage.getInstanceLocation();if (instanceLocation != null) {return instanceLocation.toString();}JsonNodePath evaluationPath = validationMessage.getEvaluationPath();if (evaluationPath != null) {return evaluationPath.toString();}return "unknown";}
}
ValidationResult
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ValidationResult {private String type;private String propertyPath;private String errMsg;
}
schema.json
{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","properties": {"name": {"type": "string","message": {"type": "name的类型不对, 这里的优先级高"}},"age": {"type": "integer","minimum": 10,"maximum": 120,"message": {"minimum": "年龄不能小于10岁哦","maximum": "年龄不能大于120岁哦"}},"sex": {"type": "string","enum": ["male", "female"],"message": {"enum": "这是个枚举哦, 它的取值有: {1}, 这里的优先级比外面优先级要高"}},"email": {"pattern": "^\\w{3,8}@\\w{3,8}\\.com$"},"motto": {"type": "string","maxLength": 20,"minLength": 5,"message": {"minLength": "这个字数太短啦, 最少5个字"}},"hobbies": {"type": "array","items": {"type": "string"}}},"required": ["name","age"],"message": {"required": {"name": "没有提供名字name","age": "没有提供age年龄"},"type": "属性 {0} 设置了 {1} 类型不正确,而应当为 {2} ","enum": "这是个枚举值, 取值有: {1}, 这里的优先级较低","pattern": "不符合这个正则表达式咯","maxLength": "这个字数太长啦, 最长20个字,看看哪里的生效~这里的不生效,上面如果要写就要写全了"}
}
json-validator-message.properties
maxLength = ~~~{0}: zzhua~~~长度不得超过 {1} 个字符~~~
json-validator-message_zh_CN.properties
maxLength = ~~~{0}: zzhua-中文~~~长度不得超过 {1} 个字符~~~
ResourceBundleTest
用于加载属性配置文件,并支持i18n国际化
import java.util.Locale;
import java.util.ResourceBundle;public class ResourceBundleTest {public static void main(String[] args) {// 1、ResourceBundle resourceBundle = ResourceBundle.getBundle(baseName, locale)// 2、String val = resourceBundle.getString(key)// 3、文件名:jsv-messages_zh_CN.properties// 4、MessageFormat format = new MessageFormat("{0}: 未知属性{1}", locale)// 5、String result = format.format(arguements, new StringBuffer(), null)// ResourceBundle bundle = ResourceBundle.getBundle("validate/json-validator-message", Locale.ROOT);ResourceBundle bundle = ResourceBundle.getBundle("validate/json-validator-message", Locale.CHINA);String maxLength = bundle.getString("maxLength");System.out.println(maxLength);}}
2、嵌套属性校验示例
SchemaValidatorExample
package com.zzhua.test05;import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.*;
import com.networknt.schema.i18n.ResourceBundleMessageSource;
import com.zzhua.util.ValidationResult;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;import javax.xml.validation.SchemaFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;public class SchemaValidatorExample05 {public static void main(String[] args) throws IOException {JsonSchemaFactory schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7);JsonSchema schema = schemaFactory.getSchema(new ClassPathResource("schema/test05/schema.json").getInputStream(),SchemaValidatorsConfig.builder()// 可以去掉JsonNodePath instanceLocation前面的 / 斜线.pathType(PathType.URI_REFERENCE)// 快速失败// .failFast(true)// 自定义消息源(按顺序找指定的文件名。可支持i18n国际化。错误提示中的占位符的值可以看XxxValidator往arguments中设置了哪些值。).messageSource(new ResourceBundleMessageSource("validate/json-validator-message","jsv-messages"))// 自定义消息错误提示属性// (虽然SchemaValidatorsConfig#errorMessageKeyword默认值就是message,// 但是builder中该属性默认是null,所以这里如果不主动设置的话,就会是null).errorMessageKeyword("message").build());ObjectMapper mapper = new ObjectMapper();String jsonStr = """{"user": {"a": "b","name": 1,"address": {"street": "123 Main St","city": "Beijing","coordinates": {"lat": 39.9042,"lng": 116.4074}},"friends": [{"name": "Bob","hobbies": ["Reading", "Sports"]},{"name": "Charlie","hobbies": ["Music"]}]}}""";Set<ValidationMessage> validationMessages = schema.validate(mapper.readTree(jsonStr));List<com.zzhua.util.ValidationResult> results = new ArrayList<>();for (ValidationMessage validationMessage : validationMessages) {results.add(com.zzhua.util.ValidationResult.builder().type(validationMessage.getType()).errMsg(validationMessage.getMessage()).propertyPath(deducePropertyPath(validationMessage)).build());}for (ValidationResult validationResult : results) {System.out.println("-------------------");System.out.println("校验的关键字: " + validationResult.getType());System.out.println("校验的属性: " + validationResult.getPropertyPath());System.out.println("校验的错误提示: " + validationResult.getErrMsg());}}private static String deducePropertyPath(ValidationMessage validationMessage) {// 推断属性名String property = validationMessage.getProperty();if (StringUtils.hasText(property)) {return property;}JsonNodePath instanceLocation = validationMessage.getInstanceLocation();if (instanceLocation != null) {return instanceLocation.toString();}JsonNodePath evaluationPath = validationMessage.getEvaluationPath();if (evaluationPath != null) {return evaluationPath.toString();}return "unknown";}}
schema.json
{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": ["user"],"properties": {"user": {"type": "object","required": ["name", "age", "address"],"additionalProperties": false,"message": {"required": "{0}中缺少属性{1}","additionalProperties": "{0}中不允许存在额外属性{1}"},"properties": {"name": { "type": "string" },"age": { "type": "number", "minimum": 0 },"address": {"type": "object","required": ["street", "city"],"properties": {"street": { "type": "string" },"city": { "type": "string" },"coordinates": {"type": "object","required": ["lat", "lng"],"properties": {"lat": { "type": "number" },"lng": { "type": "number" }},"additionalProperties": false}}},"friends": {"type": "array","items": {"type": "object","required": ["name"],"properties": {"name": { "type": "string" },"hobbies": {"type": "array","items": { "type": "string" },"minItems": 1}},"additionalProperties": false}}}}}
}
json-validator-message.properties
type = 类型不太对哦{1}-{2}
json-validator-message_zh_CN.properties
type = 中文-类型不太对哦{1}-{2}
3、$ref 引用
1、内部引用
resources/user-schema.json
{"$schema": "http://json-schema.org/draft-07/schema#","$id": "/schemas/user-schema.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"}}
}
JsonSchemaValidatorDemo
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.*;
import com.zzhua.util.ValidationResult;
import org.springframework.util.StringUtils;import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;public class JsonSchemaValidatorDemo {public static void main(String[] args) throws JsonProcessingException {// 1. 加载主 SchemaJsonSchemaFactory schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7);InputStream schemaStream = JsonSchemaValidatorDemo.class.getResourceAsStream("/schemas/user-schema.json");JsonSchema schema = schemaFactory.getSchema(schemaStream,SchemaValidatorsConfig.builder().pathType(PathType.URI_REFERENCE).build());// 2. 准备待校验的 JSON 数据String jsonData = """{"billing_address": {"city":"shenzhen","state": "gd","street_address": "lsydxq48d"}}""";// 3. 执行校验Set<ValidationMessage> validationMessages = schema.validate(new ObjectMapper().readTree(jsonData));List<com.zzhua.util.ValidationResult> results = new ArrayList<>();for (ValidationMessage validationMessage : validationMessages) {results.add(com.zzhua.util.ValidationResult.builder().type(validationMessage.getType()).errMsg(validationMessage.getMessage()).propertyPath(deducePropertyPath(validationMessage)).build());}for (ValidationResult validationResult : results) {System.out.println("-------------------");System.out.println("校验的关键字: " + validationResult.getType());System.out.println("校验的属性: " + validationResult.getPropertyPath());System.out.println("校验的错误提示: " + validationResult.getErrMsg());}}private static String deducePropertyPath(ValidationMessage validationMessage) {// 推断属性名String property = validationMessage.getProperty();if (StringUtils.hasText(property)) {return property;}JsonNodePath instanceLocation = validationMessage.getInstanceLocation();if (instanceLocation != null) {return instanceLocation.toString();}JsonNodePath evaluationPath = validationMessage.getEvaluationPath();if (evaluationPath != null) {return evaluationPath.toString();}return "unknown";}
}
2、外部文件引用
JsonSchemaValidatorDemo
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.*;
import com.networknt.schema.resource.PrefixSchemaMapper;
import com.zzhua.util.ValidationResult;
import org.springframework.util.StringUtils;import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;public class JsonSchemaValidatorDemo {public static void main(String[] args) throws JsonProcessingException {SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().pathType(PathType.URI_REFERENCE).errorMessageKeyword("message").build();JsonSchemaFactory schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7,builder -> {builder.schemaMappers(schemaMapperBuilder -> {schemaMapperBuilder.add(new PrefixSchemaMapper("http://www.example.com", ""));});builder.schemaLoaders(schemaLoaderBuilder -> {schemaLoaderBuilder.add(new CommonSchemaLoader());});});// 1. 加载主 SchemaInputStream schemaStream = JsonSchemaValidatorDemo.class.getResourceAsStream("/schemas/user-schema.json");JsonSchema schema = schemaFactory.getSchema(schemaStream, config);// 2. 准备待校验的 JSON 数据String jsonData = """{"billing_address":{"state": 1},"customer_name": "ab","enum_no_use_name": "zzhua","all_can_use_name": "zz"}""";// 3. 执行校验Set<ValidationMessage> validationMessages = schema.validate(new ObjectMapper().readTree(jsonData));List<com.zzhua.util.ValidationResult> results = new ArrayList<>();for (ValidationMessage validationMessage : validationMessages) {results.add(com.zzhua.util.ValidationResult.builder().type(validationMessage.getType()).errMsg(validationMessage.getMessage()).propertyPath(deducePropertyPath(validationMessage)).build());}for (ValidationResult validationResult : results) {System.out.println("-------------------");System.out.println("校验的关键字: " + validationResult.getType());System.out.println("校验的属性: " + validationResult.getPropertyPath());System.out.println("校验的错误提示: " + validationResult.getErrMsg());}}private static String deducePropertyPath(ValidationMessage validationMessage) {// 推断属性名String property = validationMessage.getProperty();if (StringUtils.hasText(property)) {return property;}JsonNodePath instanceLocation = validationMessage.getInstanceLocation();if (instanceLocation != null) {return instanceLocation.toString();}JsonNodePath evaluationPath = validationMessage.getEvaluationPath();if (evaluationPath != null) {return evaluationPath.toString();}return "unknown";}
}
CommonSchemaLoader
参照 ClasspathSchemaLoader
import com.networknt.schema.AbsoluteIri;
import com.networknt.schema.resource.InputStreamSource;
import com.networknt.schema.resource.SchemaLoader;import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.function.Supplier;public class CommonSchemaLoader implements SchemaLoader {private final Supplier<ClassLoader> classLoaderSource;/*** Constructor.*/public CommonSchemaLoader() {this(CommonSchemaLoader::getClassLoader);}public CommonSchemaLoader(Supplier<ClassLoader> classLoaderSource) {this.classLoaderSource = classLoaderSource;}@Overridepublic InputStreamSource getSchema(AbsoluteIri absoluteIri) {String iri = absoluteIri != null ? absoluteIri.toString() : "";String name = null;if (iri.startsWith("/schemas/common")) {name = iri.substring(1);}if (name != null) {ClassLoader classLoader = this.classLoaderSource.get();String resource = name;return () -> {InputStream result = classLoader.getResourceAsStream(resource);if (result == null) {result = classLoader.getResourceAsStream(resource.substring(1));}if (result == null) {throw new FileNotFoundException(iri);}return result;};}return null;}protected static ClassLoader getClassLoader() {ClassLoader classLoader = Thread.currentThread().getContextClassLoader();if (classLoader == null) {classLoader = SchemaLoader.class.getClassLoader();}return classLoader;}
}
resources/user-schema.json
-
当在一个模式对象中使用$ref时,其他属性会被忽略,因为$ref会完全引用外部模式,取代当前对象。这意味着如果用户在同一个对象里同时使用$ref和其他属性,比如description或type,这些额外的属性可能会被验证器忽略,导致不符合预期的结果。
- 更常用的解决方案是使用allOf来组合引用和本地属性。例如,使用allOf数组,其中一个是$ref引用外部模式,另一个是包含本地属性的对象。这样可以将外部模式和本地属性合并,确保所有约束都被应用。
{"$schema": "http://json-schema.org/draft-07/schema#","$id": "classpath:/schemas/address-schema.json","type": "object","definitions": {"address": {"type": "object","properties": {"street_address": {"type": "string"},"city": {"type": "string"},"state": {"type": "string"}},"required": ["street_address","city","state"]}},"properties": {"billing_address": {"$ref": "http://www.example.com/schemas/common/address-schema.json#/properties/address"},"customer_name": {"$ref": "http://www.example.com/schemas/common/nickname-schema.json"},"enum_no_use_name": {"$ref": "http://www.example.com/schemas/common/nickname-schema.json","enum": ["mike","jerry"]},"all_can_use_name": {"allOf": [{"$ref": "http://www.example.com/schemas/common/nickname-schema.json"},{"enum": ["mike","jerryyyyyyyyyyyyyyyy"],"message": {"enum": "all_can_use_name枚举值会和$ref引入的内容合并吗?会合并!"}}]},"shipping_address": {"$ref": "#/definitions/address"}},"required": ["customer_name"]
}
resources/common/address-schema.json
{"$schema": "http://json-schema.org/draft-07/schema#","$id": "/schemas/nickname-schema.json","type": "string","minLength": 3,"maxLength": 8,"message": {"minLength": "~minLength~昵称长度必须在3-8个字符之间","maxLength": "~maxLength~昵称长度必须在3-8个字符之间"}
}
resources/user-schema.json
{"$schema": "http://json-schema.org/draft-07/schema#","$id": "classpath:/schemas/address-schema.json","type": "object","definitions": {"address": {"type": "object","properties": {"street_address": {"type": "string"},"city": {"type": "string"},"state": {"type": "string"}},"required": ["street_address","city","state"]}},"properties": {"billing_address": {"$ref": "http://www.example.com/schemas/common/address-schema.json#/properties/address"},"customer_name": {"$ref": "http://www.example.com/schemas/common/nickname-schema.json"},"shipping_address": {"$ref": "#/definitions/address"}},"required": ["customer_name"]
}