如何在Spring4MVC中使用javax.validation和JSON请求?

如何在Spring4MVC中使用javax.validation和JSON请求?,java,jquery,json,spring,validation,Java,Jquery,Json,Spring,Validation,我正在使用Spring4MVC开发一个Web应用程序。我想知道我是否可以使用javax.validation API验证JSON请求对象。例如,我有我的实体代码块: ... @JsonProperty("cheFecha") @NotNull @Column(name = "che_fecha") @Temporal(TemporalType.DATE) @DateTimeFormat(style = "M-") privat

我正在使用Spring4MVC开发一个Web应用程序。我想知道我是否可以使用javax.validation API验证JSON请求对象。例如,我有我的实体代码块:

    ...       
    @JsonProperty("cheFecha")
    @NotNull
    @Column(name = "che_fecha")
    @Temporal(TemporalType.DATE)
    @DateTimeFormat(style = "M-")
    private Date SsiCheque.cheFecha;

    @JsonProperty("cheMonto")
    @NotNull
    @JsonSerialize(using = CurrencySerializer.class)
    @Column(name = "che_monto", precision = 10, scale = 2)
    private BigDecimal SsiCheque.cheMonto;
    ...
@RequestMapping(value = "/addCheck", method = RequestMethod.POST)
public @ResponseBody SsiCheque addChecks(@Valid SsiCheque ssiCheque, BindingResult result) {

    //ssiCheque.persist();
    System.out.println("add" + result.getErrorCount());// Zero when there are errors
    return ssiCheque;
}
我有控制器代码:

    ...       
    @JsonProperty("cheFecha")
    @NotNull
    @Column(name = "che_fecha")
    @Temporal(TemporalType.DATE)
    @DateTimeFormat(style = "M-")
    private Date SsiCheque.cheFecha;

    @JsonProperty("cheMonto")
    @NotNull
    @JsonSerialize(using = CurrencySerializer.class)
    @Column(name = "che_monto", precision = 10, scale = 2)
    private BigDecimal SsiCheque.cheMonto;
    ...
@RequestMapping(value = "/addCheck", method = RequestMethod.POST)
public @ResponseBody SsiCheque addChecks(@Valid SsiCheque ssiCheque, BindingResult result) {

    //ssiCheque.persist();
    System.out.println("add" + result.getErrorCount());// Zero when there are errors
    return ssiCheque;
}
最后是jQuery代码:

    var formData = $("#formAddChecks :input").serializeArray();
    $.ajax({
        type: "POST",
        url: "addCheck",
        data: formData,
        beforeSend: function ( xhr ) {
            console.log("before Send");
        },
        error: function (request, status, error) {            
            console.log('Error ' + "\n" + status + "\n" + error);
        },
        success: function(data) {
            console.log(data);
        }
    });
JSON对象正确到达控制器,但我想用实体javax.annotations API验证JSON。我所看到的只是使用自定义验证器和“重写”验证代码

这是验证JSON的唯一方法吗

提前谢谢

更新1

我遵循了@James Massey的建议,现在我的代码如下所示:

控制器

@RequestMapping(value = "/addCheck", method = RequestMethod.POST)
@ResponseBody
public SsiCheque addChecks(@Valid @RequestBody SsiCheque ssiCheque, BindingResult result) {

    //ssiCheque.persist();
    System.out.println("agregar " + result.getErrorCount());
    return ssiCheque;
}
@RequestMapping(value = "/addCheck", method = RequestMethod.POST)
@ResponseBody
public SsiCheque addChecks(@Valid @RequestBody SsiCheque ssiCheque, BindingResult result) {

    //ssiCheque.persist();
    System.out.println("agregar " + result.getErrorCount());
    return ssiCheque;
}
Javascript文件

    var ssiCheque = {
            cheNumero : $("#formAddChecks cheNumero").val(),
            cheRecepto : $("#formAddChecks cheReceptor").val(),
            cheMonto : $("#formAddChecks cheMonto").val(),
            cheFecha : $("#formAddChecks cheFecha").val(),
            cheConcepto : $("#formAddChecks cheConcepto").val()
    };


    $.ajax({
        type: "POST",
        contentType: "application/json",
        url: "addCheck",
        data: ssiCheque,
        dataType: "json",
        beforeSend: function ( xhr ) {
            console.log("before Send");
        },
        error: function (request, status, error) {            
            console.log('Error ' /*+ request.responseText*/ + "\n" + status + "\n" + error);
        },
        success: function(data) {
            console.log(data);
        }
    });
但是当我提交表单并执行Ajax函数时,我收到一个400错误(请求不正确)。当json对象格式和控制器规范不兼容时,我曾经遇到过这个错误,但这一次我不知道为什么会出现这个错误


再次感谢

这里似乎有一些问题:

  • 你的对象结构看起来很奇怪。为什么字段引用对象类型<代码>私人日期。cheFecha似乎是一个完全没有意义的字段

  • 您通常将UI设计为通过可以直接映射到Java对象的JSON对象发送。如果你的物体看起来像这样:

    public class Example { 
        @NotNull
        @Digits(fraction = 2, integer = 10)
        private Integer foo;
        @NotEmpty
        private String bar;
        @NotEmpty
        private String[] baz;
    }
    
    那么您的JSON结构应该是这样的:

    {
    “示例”:{
    “福”:1,
    “酒吧”:“菠萝”,
    “baz”:[
    “这是一个字符串”,
    “这也是”
    ]
    }
    }
    
  • Jackson可以使用它直接映射到您的对象中

    然后,假设项目类路径中包含了Jackson JAR,您可以这样编写控制器方法:

    @RequestMapping(value = "/example", method = RequestMethod.POST)
    @ResponseBody
    public Example(@Valid @RequestBody Example example, BindingResult result) {
         if(result.hasErrors()){
             //A validation has failed, return an error response to the UI
         } else {
             exampleService.createOrUpdate(example);
             return example;
         }
    }
    
    重要的一点是,您的对象是请求主体,您使用
    @RequestBody
    注释,因为Jackson使用此注释作为信号,使用HTTP请求主体中的JSON构建您的对象。这种方法的唯一缺点是,您可能必须以编程方式构造请求JSON。然而,这对于JavaScript来说是微不足道的。 (这里我将假设一些合理的输入id默认值,并且您熟悉jQuery DOM操作/选择语法)

    var-bazArray=[];
    $.forEach($(“#bazContainer”),函数(baz,i){
    推(baz);
    });
    变量示例={
    foo:$(“#fooint”).val(),
    条形图:$(“#barInput”).val(),
    baz:baz阵列
    };
    
    在数据字段中将示例对象传递给请求,如果指定它的类型为
    application/json
    ,那么jQuery将自动调用示例对象上的
    json.stringify
    。 希望这一切都有意义。

    解决方案(由提问者Jessai更新)

    我检查了这个问题:

    总之,我所做的是:

  • 创建一个要用JSON.stringify解析的对象,并将其发送给控制器

  • 在控制器中,我使用@ResponseBody和@RequestBody设置方法,正如@jamesmassey所说的那样

  • 在实体中,我向字段添加了@JSONProperty(我已经有了这些)和@JSONIgnore(我添加到cheId字段)注释

  • Javascript:

        var ssiCheque = {
                cheNumero : $("#formAddChecks #cheNumero").val(),
                cheRecepto : $("#formAddChecks #cheReceptor").val(),
                cheMonto : $("#formAddChecks #cheMonto").val(),
                cheFecha : $("#formAddChecks #cheFecha").val(),
                cheConcepto : $("#formAddChecks #cheConcepto").val()
        };
    
    
        $.ajax({
            type: "POST",
            contentType: "application/json",
            url: "addCheck",
            data: JSON.stringify(ssiCheque),
            dataType: "json",
            beforeSend: function ( xhr ) {
                console.log("before Send");
            },
            error: function (request, status, error) {            
                console.log('Error ' /*+ request.responseText*/ + "\n" + status + "\n" + error);
            },
            success: function(data) {
                console.log(data);
            }
        });
    
    控制器

    @RequestMapping(value = "/addCheck", method = RequestMethod.POST)
    @ResponseBody
    public SsiCheque addChecks(@Valid @RequestBody SsiCheque ssiCheque, BindingResult result) {
    
        //ssiCheque.persist();
        System.out.println("agregar " + result.getErrorCount());
        return ssiCheque;
    }
    
    @RequestMapping(value = "/addCheck", method = RequestMethod.POST)
    @ResponseBody
    public SsiCheque addChecks(@Valid @RequestBody SsiCheque ssiCheque, BindingResult result) {
    
        //ssiCheque.persist();
        System.out.println("agregar " + result.getErrorCount());
        return ssiCheque;
    }
    

    谢谢

    我用另一种方式解决了验证问题。假设我有代理和对象:

    public class Agent {
        public int userID;
        public String name;
        public boolean isVoiceRecorded;
        public boolean isScreenRecorded;
        public boolean isOnCall;
    }
    
    我想确认: (1) 用户ID>0 (2) 名字是必须的 (3) isVoiceRecorded和isScreenRecorded只能在isOnCall为true时为true

    @Documented
    @Constraint(validatedBy = MyConstraintValidator.class)
    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    public @interface CheckBools {
        String message() default "'isVoiceRecorded' or 'isScreenRecorded' can be true only if you are on call";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    
    为此,我需要添加依赖项:

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
    </dependency>
    
    (1) @Min(0)-userID>0 (2) @NotNull(message=“Name不能为null”)-解析名称是必需的,并且您有如何指定错误消息的示例 (3) @CheckBools注释由我定义,在类级别上检查isVoiceRecorded和isScreenRecorded只能在isOnCall为true时为true

    @Documented
    @Constraint(validatedBy = MyConstraintValidator.class)
    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    public @interface CheckBools {
        String message() default "'isVoiceRecorded' or 'isScreenRecorded' can be true only if you are on call";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    
    @已记录
    @约束(validatedBy=MyConstraintValidator.class)
    @目标({TYPE,ANNOTATION\u TYPE})
    @保留(运行时)
    public@interface CheckBools{
    String message()默认值“'isVoiceRecorded'或'isScreenRecorded'只能在您正在通话时为true”;
    类[]组()默认值{};
    
    类使用Jackson有什么问题(类似)要将JSON映射到对象中,然后正常调用验证?问题是当您传递无效数据时,绑定结果中没有任何错误吗?我在cheFecha字段中放置了@NotNull注释,当我测试时,我发送cheFecha null,它似乎跳过了验证部分,因为我在getErrorCount()中有零方法我认为它会被你奇怪的对象组成弄糊涂。从日期字段中删除
    ssicheck
    ,基本上是因为你的
    ssicheck
    对象不是空的,满足约束,它不会深入对象。我忘了说我的实体是由Spring Roo生成的,所以代码SsiChcheFecha是生成代码的一部分。我不太了解,但我读过面向方面编程(AOP)