Springboot中使用ajax提交复杂对象+校验

ajax提交复杂对象

1. 提交的对象类UserDetail

public class User {

         @NotBlank

         private String id;

         @NotBlank

         private String userName

}

 

public class UserDetail {

         @NotNull

         private User user;

         private String details;

}

 

2. controller的代码:

    @RequestMapping(value = "api/user/add", method = { RequestMethod.PUT, RequestMethod.POST })

    @ResponseBody

    public String add(@RequestBodyUserDetail userDetail) {

        System.out.print(userDetail);

        return "success";

    }

 

3. ajax提交的代码,红色部分是关键代码,①处不写对会报400错;②处不这样写,后端无法接收

    var user = {

        userName : $("#userName").val()

    }

 

    var userDetail = {

        user : user,

        detail  : $("#detail").val()

    };

 

    $.ajax({

        type : 'POST',

        dataType : "JSON",

        contentType:"application/json", //

        cache : false,

        url : url,

        data : JSON.stringify(datas),

        async : false,

        success : function(result) {

            alert("成功");

        },

        error : function(result) {

            alert("失败");

        }

    });

后端校验

在做校验的时候踩了几个坑,这里主要是把坑记录下来

1

springboot的校验,首先考虑用@Valid做,于是在Controller代码里加入注解

    public String add(@Valid@RequestBodyUserDetail userDetail) {

        System.out.print(userDetail);

        return "success";

    }

很快发现问题,此处Valid的校验只会对按照UserDetail类里的校验规则做校验,而不会对其引用对象user校验,如User类里要求userName不为空,但此时校验不会校验userName。即没有对嵌套的内层对象做校验。

解决:在UserDetail类的user对象上加上@Valid注解

public class UserDetail {

         @NotNull

         @Valid

         private User user;

         private String details;

}

写个测试方法,测试正常:

publicclass ValidationTest {

    privatestaticfinal Validator validator;

 

    // 获得验证器实例

    static {

        Configuration<?> config = Validation.byDefaultProvider().configure();

        ValidatorFactory factory = config.buildValidatorFactory();

        validator = factory.getValidator();

        factory.close();

    }

 

    publicstaticvoid main(String[] args) throws ParseException {

        User user = new User();

        UserDetail userDetail = new UserDetail ();

        user.setSysUser(user);

 

        Set<ConstraintViolation<UserDetail>> violations = validator.validate(userDetail);

        if (violations.size() == 0) {

            System.out.println("No violations.");

        } else {

            System.out.printf("%s violations:%n", violations.size());

            violations.stream().forEach(ValidationTest::printError);

        }

    }

 

    privatestaticvoid printError(ConstraintViolation<?> violation) {

        System.out.println(violation.getPropertyPath() + " " + violation.getMessage());

    }

}

 

2

加上@Valid之后,前台直接报400错误,后台没有任何异常打印信息,userDetails也没有打印出来。推测此时验证已经生效,但绑定过程异常,并且该异常没有被BindException捕获(简单对象的验证错误是可以用这个异常捕获的)。

几经周折,最后发现这里报的异常是MethodArgumentNotValidException,于是添加对这个异常的全局处理,问题解决

 

改进:考虑了一下,在Controller层使用@Valid来做校验体验不好,直接手动校验逻辑会更加清楚

写一个校验工具类BeanValidators

publicclass BeanValidators {

 

    /**

     * 调用JSR303validate方法, 验证失败时抛出ConstraintViolationException.

     */

    @SuppressWarnings({ "unchecked", "rawtypes" })

    publicstaticvoid validateWithException(Validator validator, Object object, Class<?>... groups)

            throws ConstraintViolationException {

        Set constraintViolations = validator.validate(object, groups);

        if (!constraintViolations.isEmpty()) {

            thrownew ConstraintViolationException(constraintViolations);

        }

    }

 

    /**

     * 辅助方法,

     * 转换ConstraintViolationException中的Set<ConstraintViolations>中为List<message>.

     */

    publicstatic List<String> extractMessage(ConstraintViolationException e) {

        return extractMessage(e.getConstraintViolations());

    }

 

    /**

     * 辅助方法, 转换Set<ConstraintViolation>List<message>

     */

    @SuppressWarnings("rawtypes")

    publicstatic List<String> extractMessage(Set<? extends ConstraintViolation> constraintViolations) {

        List<String> errorMessages = Lists.newArrayList();

        for (ConstraintViolation violation : constraintViolations) {

            errorMessages.add(violation.getMessage());

        }

        returnerrorMessages;

    }

 

    /**

     * 辅助方法,

     * 转换ConstraintViolationException中的Set<ConstraintViolations>Map<property,

     * message>.

     */

    publicstatic Map<String, String> extractPropertyAndMessage(ConstraintViolationException e) {

        return extractPropertyAndMessage(e.getConstraintViolations());

    }

 

    /**

     * 辅助方法, 转换Set<ConstraintViolation>Map<property, message>.

     */

    @SuppressWarnings("rawtypes")

    publicstatic Map<String, String> extractPropertyAndMessage(

            Set<? extends ConstraintViolation> constraintViolations) {

        Map<String, String> errorMessages = Maps.newHashMap();

        for (ConstraintViolation violation : constraintViolations) {

            errorMessages.put(violation.getPropertyPath().toString(), violation.getMessage());

        }

        returnerrorMessages;

    }

 

    /**

     * 辅助方法,

     * 转换ConstraintViolationException中的Set<ConstraintViolations>List<propertyPath

     * message>.

     */

    publicstatic List<String> extractPropertyAndMessageAsList(ConstraintViolationException e) {

        return extractPropertyAndMessageAsList(e.getConstraintViolations(), " ");

    }

 

    /**

     * 辅助方法, 转换Set<ConstraintViolations>List<propertyPath message>.

     */

    @SuppressWarnings("rawtypes")

    publicstatic List<String> extractPropertyAndMessageAsList(

            Set<? extends ConstraintViolation> constraintViolations) {

        return extractPropertyAndMessageAsList(constraintViolations, " ");

    }

 

    /**

     * 辅助方法,

     * 转换ConstraintViolationException中的Set<ConstraintViolations>List<propertyPath

     * +separator+ message>.

     */

    publicstatic List<String> extractPropertyAndMessageAsList(ConstraintViolationException e, String separator) {

        return extractPropertyAndMessageAsList(e.getConstraintViolations(), separator);

    }

 

    /**

     * 辅助方法, 转换Set<ConstraintViolation>List<propertyPath +separator+ message>.

     */

    @SuppressWarnings("rawtypes")

    publicstatic List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations,

            String separator) {

        List<String> errorMessages = Lists.newArrayList();

        for (ConstraintViolation violation : constraintViolations) {

            errorMessages.add(violation.getPropertyPath() + separator + violation.getMessage());

        }

        returnerrorMessages;

    }

}

 

Controller层调用代码(object是需要验证的类):

protected Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

 

 

        try {

            BeanValidators.validateWithException(validator, user);

        } catch (ConstraintViolationException e) {

            List<String> list = BeanValidators.extractPropertyAndMessageAsList(e, ": ");

            list.add(0, "数据验证失败:");

            //处理逻辑

 

        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值