使用json-schema校驗json數(shù)據(jù)

1. 不想看2中具體代碼實現(xiàn)的總結(jié)

  • json-schema本身也是json咽袜,但是可以用來描述另一個json應該符合的格式規(guī)范雏掠;
  • json-schema只是表示出規(guī)范下愈,校驗一個json是否符合這個json-schema的規(guī)范矫钓,需要代碼實現(xiàn)毡琉;
  • 有很多開源的工具铁瞒,可以用來校驗,例如https://github.com/everit-org/json-schemahttps://github.com/java-json-tools/json-schema-validator桅滋;
  • 本文的目的是將這個工具包裝成一個注解慧耍,用來校驗使用Spring的web工程中接口接收到的json參數(shù)身辨。

2. 使用示例

接口接收的json參數(shù)(這里只是舉個例子):

{
  "param1": 37.69437890136598,
  "param2": "enum1",
  "param3": true
}
其中,param1是0~100的數(shù)字芍碧,必填煌珊,默認值為0;param2是枚舉類型泌豆,有三個值enum1定庵、enum2、enum3踪危,默認值為enum1蔬浙,必填;param3是布爾類型贞远,默認值為true畴博,非必填。

用來校驗上面這個json的json-schema(我這里和前端交互蓝仲,接口信息是寫在yapi上俱病,可以直接從yapi里面拷,是yapi根據(jù)接口描述自動生成的):

{
  "type": "object",
  "title": "empty object",
  "properties": {
    "param1": {
      "type": "number",
      "minimum": 0,
      "maximum": 100,
      "default": "0"
    },
    "param2": {
      "type": "string",
      "default": "enum1",
      "enum": [
        "enum1",
        "enum2",
        "enum3"
      ],
      "enumDesc": "枚舉類型杂曲,只有三個值enum1庶艾、enum2袁余、enum3"
    },
    "param3": {
      "type": "boolean",
      "default": true
    }
  },
  "required": [
    "param1",
    "param2"
  ]
}

自定義注解:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.PARAMETER)
@Constraint(validatedBy = JsonConstraintValidated.class)
public @interface JsonValid {

    String value();

    String message() default "Json數(shù)據(jù)校驗失敗";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

實現(xiàn)注解具體功能的類:

import com.alibaba.fastjson.JSONObject;
import com.chinatelecom.ctyun.xlive.common.exception.DataErrorException;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JsonLoader;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.report.LogLevel;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.io.IOException;
import java.util.Optional;

public class JsonConstraintValidated implements ConstraintValidator<JsonValid, JSONObject> {

    /**
     * 校驗規(guī)則
     */
    private String jsonSchemaString;

  /**
   * 初始化方法擎勘,使用注解的地方,需要提供接口中定義好的參數(shù)颖榜,這里可以獲得這些參數(shù)
   */
    @Override
    public void initialize(JsonValid constraintAnnotation) {
        jsonSchemaString = constraintAnnotation.value();
    }

    /**
     * 校驗方法
     *
     * @param value   待校驗的json
     * @param context 將失敗消息帶出到Spring的參數(shù)校驗異常類ConstraintViolationException
     * @return true:校驗成功棚饵,無感知;false:校驗失敗掩完,框架會拋出異常ConstraintViolationException
     */
    @Override
    public boolean isValid(JSONObject value, ConstraintValidatorContext context) {
        try {
            String message = Optional.ofNullable(validJson(value, jsonSchemaString)).orElse("");
            if (StringUtils.isEmpty(message)) {
                return true;
            } else {
                //禁用默認的message的值噪漾,重新添加錯誤提示語句
        //默認的message無法體現(xiàn)具體是哪個json參數(shù)有問題
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                return false;
            }
        } catch (Exception e) {
            throw new DataErrorException("json校驗數(shù)據(jù)異常,請聯(lián)系管理員");
        }
    }

    /**
     * 使用開源工具https://github.com/java-json-tools/json-schema-validator校驗json
     *
     * @param object     被校驗對象
     * @param validParam 校驗規(guī)則
     * @return 返回失敗消息且蓬,為空則校驗成功
     * @throws Exception
     */
    public String validJson(JSONObject object, String validParam) throws IOException, ProcessingException {
        JsonNode schema = JsonLoader.fromString(validParam);
        JsonNode data = JsonLoader.fromString(object.toJSONString());
        final JsonSchema jsonSchema = JsonSchemaFactory.byDefault().getJsonSchema(schema);
        ProcessingReport report = jsonSchema.validate(data);
        StringBuilder sBuilder = new StringBuilder();
        report.forEach(pm -> {
            if (LogLevel.ERROR.equals(pm.getLogLevel())) {
                JsonNode jsonNode = pm.asJson();
                JsonNode key = Optional.ofNullable(jsonNode)
                        .map(o -> o.get("instance"))
                        .map(r -> r.get("pointer"))
                        .orElse(null);
                sBuilder.append("errorKey:")
                        .append(key == null ? "" : key.asText())
                        .append("; errorMessage:")
                        .append(pm.getMessage());
            }
        });
        return sBuilder.toString();
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末欣硼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子恶阴,更是在濱河造成了極大的恐慌诈胜,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冯事,死亡現(xiàn)場離奇詭異焦匈,居然都是意外死亡,警方通過查閱死者的電腦和手機昵仅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門缓熟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事够滑】研矗” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵彰触,是天一觀的道長梯澜。 經(jīng)常有香客問我,道長渴析,這世上最難降的妖魔是什么晚伙? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮俭茧,結(jié)果婚禮上咆疗,老公的妹妹穿的比我還像新娘。我一直安慰自己母债,他們只是感情好午磁,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著毡们,像睡著了一般迅皇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衙熔,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天登颓,我揣著相機與錄音,去河邊找鬼红氯。 笑死框咙,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的痢甘。 我是一名探鬼主播喇嘱,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼塞栅!你這毒婦竟也來了者铜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤放椰,失蹤者是張志新(化名)和其女友劉穎作烟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庄敛,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡俗壹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了藻烤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绷雏。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡头滔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涎显,到底是詐尸還是另有隱情坤检,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布期吓,位于F島的核電站早歇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏讨勤。R本人自食惡果不足惜箭跳,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望潭千。 院中可真熱鬧谱姓,春花似錦、人聲如沸刨晴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狈癞。三九已至茄靠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝶桶,已是汗流浹背慨绳。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留莫瞬,地道東北人儡蔓。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓郭蕉,卻偏偏與公主長得像疼邀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子召锈,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容