一、首先有两个开源工具https://github.com/everit-org/json-schema和https://github.com/java-json-tools/json-schema-validator
区别:从性能上来说everit完全是碾压fge,官方说的至少两倍,实际测试过程中,差不多有20倍的差距。虽然fge使用的是jackson json,相对来说学习成本可能较低,但是使用下来发现everit的使用也并不复杂,需要注意的是包需要导入正确(org.json)。fge唯一的优势在于错误信息比较详细。还有一点区别在于,everit验证失败是抛出异常,而fge是判断返回一个boolean类型的值。
二、Spring boot 自定义注解集成jsonSchema
1.首先说一下ConstraintValidator这个类主要是用于验证bean里面的属性与@Valid或者@Validated注解配套使用,如果不加这个注解,那么你自定义的注解也不会生效,这一点很重要。
2.一般项目中controller方法中的参数都bean来接收,那么你就可以用ConstraintValidator来验证字段属性是否合法。那么如果controller传入的参数是Map对象就不能使用这个方法校验字段是否合法,这个时候就需要我们在代码里面写入一堆的if else判断,这样增加了代码的冗余。
三、话不多说,直接上我写的校验代码案例:
第一步:创建注解类
package com.example.demo.config;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.PARAMETER,ElementType.METHOD})
public @interface JsonValid {
String schemaName();
String message() default "Json数据校验失败";
}
第二步:校验规则切面类
package com.example.demo.service;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.config.JsonValid;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.everit.json.schema.Schema;
import org.everit.json.schema.ValidationException;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONTokener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.InputStream;
/**
* @author zhouxiang
* @describe
* @create 2021/10/20 14:47
* @since 1.0.0
*/
@Component
@Aspect
public class JsonValidatedAop {
private final Logger logger = LoggerFactory.getLogger(JsonValidatedAop.class);
@Pointcut("@annotation(com.example.demo.config.JsonValid)")
private void pointcut() {
}
@Before("pointcut() && @annotation(jsonValid)")
public void before(JoinPoint joinPoint, JsonValid jsonValid) {
Object[] args = joinPoint.getArgs();
if(args != null) {
String jsonString = JSONObject.toJSONString(args[0]);
/** 验证的结果,可以返回,也可以写个全局捕捉的异常 */
String validMsg = validJson(jsonString, jsonValid.schemaName());
}
logger.info("数据:"+ JSONObject.toJSONString(args) + jsonValid.schemaName());
}
/**
* 使用开源工具https://github.com/java-json-tools/json-schema-validator校验json
*
* @param jsonString 被校验数据
* @param schemaName 校验schema名称
* @return 返回失败消息,为空则校验成功
*/
public String validJson(String jsonString, String schemaName) {
StringBuilder sBuilder = new StringBuilder();
try {
//InputStream inputStream = getClass().getResourceAsStream("/schema/hello.json");
//org.json.JSONObject rawSchema = new org.json.JSONObject(new JSONTokener(inputStream));
org.json.JSONObject rawSchema = new org.json.JSONObject(jsonString);
InputStream in1 = getClass().getResourceAsStream("/schema/"+schemaName);
org.json.JSONObject sSchema = new org.json.JSONObject(new JSONTokener(in1));
Schema schema = SchemaLoader.load(sSchema);
schema.validate(rawSchema);
} catch (ValidationException e) {
logger.error(e.getMessage());
sBuilder.append(e.getMessage());
}
return sBuilder.toString();
}
}
第三步:controller类
package com.example.demo.controller;
import com.example.demo.config.JsonValid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhouxiang
* @describe
* @create 2021/8/23 11:08
* @since 1.0.0
*/
@RestController
public class ValidatorController {
private final Logger logger = LoggerFactory.getLogger(ValidatorController.class);
@PostMapping("/test1")
@JsonValid(schemaName = "s.json")
public Map<String, Object> test(@RequestBody Map<String,Object> map)
{
logger.info("接收的数据:"+map.toString());
Map<String, Object> responseMap = new HashMap<>();
responseMap.put("ResponseStatusListObject", "success");
return responseMap;
}
}
第四步:测试数据
url:http://ip:8083/demo/test1 POST
json数据:
{
"rectangle" : {
"a" : 6,
"b" : "21"
}
}
Schema测试文件放在resources/schema/s.json:
{
"type" : "object",
"properties" : {
"rectangle" : {"$ref" : "#/definitions/Rectangle" }
},
"definitions" : {
"size" : {
"type" : "number",
"minimum" : 0
},
"Rectangle" : {
"type" : "object",
"properties" : {
"a" : {"$ref" : "#/definitions/size"},
"b" : {"$ref" : "#/definitions/size"}
}
}
}
}