SpringBoot使用Validation校验参数

       JSR(Java Specification Requests)是Java界的重要标准;JSR又细分很多标准,其中JSR303就代表Bean Validation。更多细节可参考:https://jcp.org/en/jsr/detail?id=303。

目录

准备工作

约束性注解(简单)说明

@Validated的使用时机

@Validated与@Valid的简单对比说明

自定义注解

对注解抛出的异常进行处理

欢迎来到JustryDeng的博客!正文start!

准备工作

引入相关依赖:

        
            org.springframework.boot
            spring-boot-starter-validation
        

注:本人测试时,还引入了lombok、SpringBoot的web、test等基础依赖,这里就不一一给出了。

 

约束性注解(简单)说明

注解

功能

@AssertFalse

可以为null,如果不为null的话必须为false

@AssertTrue

可以为null,如果不为null的话必须为true

@DecimalMax

设置不能超过最大值

@DecimalMin

设置不能超过最小值

@Digits

设置必须是数字且数字整数的位数和小数的位数必须在指定范围内

@Future

日期必须在当前日期的未来

@Past

日期必须在当前日期的过去

@Max

最大不得超过此最大值

@Min

最大不得小于此最小值

@NotNull

不能为null,可以是空

@Null

必须为null

@Pattern

必须满足指定的正则表达式

@Size

集合、数组、map等的size()值必须在指定范围内

@Email

必须是email格式

@Length

长度必须在指定范围内

@NotBlank

字符串不能为null,字符串trin()后也不能等于“”

@NotEmpty

不能为null,集合、数组、map等size()不能为0;字符串trin()后可以等于“”

@Range

值必须在指定范围内

@URL

必须是一个URL

注:此表格只是简单的对注解功能的说明,并没有对每一个注解的属性进行说明;可详见源码。

下面简单测试一下上述各注解:

测试所用模型为:

import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;

import javax.validation.constraints.*;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Validation注解
 *
 * @author JustryDeng
 * @date 2019/1/15 0:43
 */

public class ValidationBeanModel {

    @Setter
    @Getter
    public class AbcAssertFalse {

        @AssertFalse
        private Boolean myAssertFalse;
    }

    @Setter
    @Getter
    public class AbcAssertTrue {

        @AssertTrue
        private Boolean myAssertTrue;
    }

    @Setter
    @Getter
    public class AbcDecimalMax {

        @DecimalMax(value = "12.3")
        private String myDecimalMax;
    }

    @Setter
    @Getter
    public class AbcDecimalMin {

        @DecimalMin(value = "10.3")
        private String myDecimalMin;
    }

    @Setter
    @Getter
    public class AbcDigits {

        @Digits(integer = 5, fraction = 3)
        private Integer myDigits;
    }

    @Setter
    @Getter
    public class AbcEmail {

        @Email
        private String myEmail;
    }

    @Setter
    @Getter
    public class AbcFuture {

        @Future
        private Date myFuture;
    }

    @Setter
    @Getter
    public class AbcLength {

        @Length(min = 5, max = 10)
        private String myLength;
    }

    @Setter
    @Getter
    public class AbcMax {

        @Max(value = 200)
        private Long myMax;
    }

    @Setter
    @Getter
    public class AbcMin {

        @Min(value = 100)
        private Long myMin;
    }

    @Setter
    @Getter
    public class AbcNotBlank {

        @NotBlank
        private String myStringNotBlank;

        @NotBlank
        private String myObjNotBlank;
    }

    @Setter
    @Getter
    public class AbcNotEmpty {

        @NotEmpty
        private String myStringNotEmpty;

        @NotEmpty
        private String myNullNotEmpty;

        @NotEmpty
        private Map myMapNotEmpty;

        @NotEmpty
        private List myListNotEmpty;

        @NotEmpty
        private Object[] myArrayNotEmpty;
    }

    @Setter
    @Getter
    public class AbcNotNull {

        @NotNull
        private String myStringNotNull;

        @NotNull
        private Object myNullNotNull;

        @NotNull
        private Map myMapNotNull;
    }

    @Setter
    @Getter
    public class AbcNull {

        @Null
        private String myStringNull;

        @Null
        private Map myMapNull;
    }

    @Setter
    @Getter
    public class AbcPast {

        @Past
        private Date myPast;
    }

    @Setter
    @Getter
    public class AbcPattern {

        @Pattern(regexp = "\\d+")
        private String myPattern;
    }

    @Setter
    @Getter
    public class AbcRange {

        @Range(min = 100, max = 100000000000L)
        private Double myRange;
    }

    @Setter
    @Getter
    public class AbcSize {

        @Size(min = 3, max = 5)
        private List mySize;
    }

    @Setter
    @Getter
    public class AbcURL {

        @URL
        private String myURL;
    }
} 
  

测试方法为:

import com.aspire.model.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ValidationDemoApplicationTests {

    private Validator validator;


    @Before
    public void initValidator() {
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        validator = validatorFactory.getValidator();
    }

    /**
     * 在myAssertTrue属性上加@AssertTrue注解
     * 

* 程序输出: com.aspire.model.ValidationBeanModel$AbcAssertTrue类的myAssertTrue属性 -> 只能为true */ @Test public void testAssertTrue() { ValidationBeanModel.AbcAssertTrue vm = new ValidationBeanModel().new AbcAssertTrue(); vm.setMyAssertTrue(false); fa(vm); } /** * 在myAssertFalse属性上加@AssertFalse注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcAssertFalse类的myAssertFalse属性 -> 只能为false */ @Test public void testAssertFalse() { ValidationBeanModel.AbcAssertFalse vm = new ValidationBeanModel().new AbcAssertFalse(); vm.setMyAssertFalse(true); fa(vm); } /** * 在myDecimalMax属性上加@DecimalMax(value = "12.3")注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcDecimalMax类的myDecimalMax属性 -> 必须小于或等于12.3 */ @Test public void testDecimalMax() { ValidationBeanModel.AbcDecimalMax vm = new ValidationBeanModel().new AbcDecimalMax(); vm.setMyDecimalMax("123"); fa(vm); } /** * 在myDecimalMin属性上加@DecimalMin(value = "10.3")注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcDecimalMin类的myDecimalMin属性 -> 必须大于或等于10.3 */ @Test public void testDecimalMin() { ValidationBeanModel.AbcDecimalMin vm = new ValidationBeanModel().new AbcDecimalMin(); vm.setMyDecimalMin("1.23"); fa(vm); } /** * 在myDigits属性上加@Digits(integer = 5, fraction = 3)注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcDigits类的myDigits属性 -> 数字的值超出了允许范围(只允许在5位整数和3位小数范围内) */ @Test public void testDigits() { ValidationBeanModel.AbcDigits vm = new ValidationBeanModel().new AbcDigits(); vm.setMyDigits(1000738); fa(vm); } /** * 在myEmail属性上加@Email注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcEmail类的myEmail属性 -> 不是一个合法的电子邮件地址 */ @Test public void testEmail() { ValidationBeanModel.AbcEmail vm = new ValidationBeanModel().new AbcEmail(); vm.setMyEmail("[email protected]"); fa(vm); } /** * 在myFuture属性上加@Future注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcFuture类的myFuture属性 -> 需要是一个将来的时间 */ @Test public void testFuture() { ValidationBeanModel.AbcFuture vm = new ValidationBeanModel().new AbcFuture(); vm.setMyFuture(new Date(10000L)); fa(vm); } /** * 在myLength属性上加@Length(min = 5, max = 10)注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcLength类的myLength属性 -> 长度需要在5和10之间 */ @Test public void testLength() { ValidationBeanModel.AbcLength vm = new ValidationBeanModel().new AbcLength(); vm.setMyLength("abcd"); fa(vm); } /** * 在myMax属性上加@Max(value = 200)注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcMax类的myMax属性 -> 最大不能超过200 */ @Test public void testMax() { ValidationBeanModel.AbcMax vm = new ValidationBeanModel().new AbcMax(); vm.setMyMax(201L); fa(vm); } /** * 在myMin属性上加@Min(value = 200)注解 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcMin类的myMin属性 -> 最小不能小于100 */ @Test public void testMin() { ValidationBeanModel.AbcMin vm = new ValidationBeanModel().new AbcMin(); vm.setMyMin(99L); fa(vm); } /** * 在myStringNotBlank属性上加@NotBlank注解 * 在myObjNotBlank属性上加@NotBlank注解 * * 注:如果属性值为null 或者 .trim()后等于"",那么会提示 不能为空 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcNotBlank类的myObjNotBlank属性 -> 不能为空 * com.aspire.model.ValidationBeanModel$AbcNotBlank类的myStringNotBlank属性 -> 不能为空 */ @Test public void testNotBlank() { ValidationBeanModel.AbcNotBlank vm = new ValidationBeanModel().new AbcNotBlank(); vm.setMyObjNotBlank(null); vm.setMyStringNotBlank(" "); fa(vm); } /** * 在myStringNotEmpty属性上加@NotEmpty注解 * 在myNullNotEmpty属性上加@NotEmpty注解 * 在myMapNotEmpty属性上加@NotEmpty注解 * 在myListNotEmpty属性上加@NotEmpty注解 * 在myArrayNotEmpty属性上加@NotEmpty注解 * * 注:String可以是.trim()后等于""的字符串,但是不能为null * 注:MAP、Collection、Array既不能是空,也不能是null * *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcNotEmpty类的myNullNotEmpty属性 -> 不能为空 * com.aspire.model.ValidationBeanModel$AbcNotEmpty类的myListNotEmpty属性 -> 不能为空 * com.aspire.model.ValidationBeanModel$AbcNotEmpty类的myArrayNotEmpty属性 -> 不能为空 * com.aspire.model.ValidationBeanModel$AbcNotEmpty类的myMapNotEmpty属性 -> 不能为空 */ @Test public void testNotEmpty() { ValidationBeanModel.AbcNotEmpty vm = new ValidationBeanModel().new AbcNotEmpty(); vm.setMyStringNotEmpty(" "); vm.setMyNullNotEmpty(null); vm.setMyMapNotEmpty(new HashMap<>(0)); vm.setMyListNotEmpty(new ArrayList<>(0)); vm.setMyArrayNotEmpty(new String[]{}); fa(vm); } /** * 在myStringNotNull属性上加@NotNull注解 * 在myNullNotNull属性上加@NotNull注解 * 在myMapNotNull属性上加@NotNull注解 * * 注:属性值可以是空的, 但是就是不能为null *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcNotNull类的myNullNotNull属性 -> 不能为null */ @Test public void testNotNull() { ValidationBeanModel.AbcNotNull vm = new ValidationBeanModel().new AbcNotNull(); vm.setMyStringNotNull(" "); vm.setMyNullNotNull(null); vm.setMyMapNotNull(new HashMap<>(0)); fa(vm); } /** * 在myStringNull属性上加@Null注解 * 在myMapNotNull属性上加@Null注解 * * 注:属性值必须是null, 是空都不行 *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcNull类的myMapNull属性 -> 必须为null * com.aspire.model.ValidationBeanModel$AbcNull类的myStringNull属性 -> 必须为null */ @Test public void testNull() { ValidationBeanModel.AbcNull vm = new ValidationBeanModel().new AbcNull(); vm.setMyStringNull(" "); vm.setMyMapNull(new HashMap<>(0)); fa(vm); } /** * 在myPast属性上加@Past注解 * *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcPast类的myPast属性 -> 需要是一个过去的时间 */ @Test public void testPast() { ValidationBeanModel.AbcPast vm = new ValidationBeanModel().new AbcPast(); vm.setMyPast(new Date(20000000000000000L)); fa(vm); } /** * 在myPattern属性上加@Pattern(regexp = "\\d+")注解 * *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcPattern类的myPattern属性 -> 需要匹配正则表达式"\d" */ @Test public void testPattern() { ValidationBeanModel.AbcPattern vm = new ValidationBeanModel().new AbcPattern(); vm.setMyPattern("ABC"); fa(vm); } /** * 在myRange属性上加@Range(min = 100, max = 100000000000L)注解 * *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcRange类的myRange属性 -> 需要在100和100000000000之间 */ @Test public void testRange() { ValidationBeanModel.AbcRange vm = new ValidationBeanModel().new AbcRange(); vm.setMyRange(32222222222222222222222222222222.323); fa(vm); } /** * 在mySize属性上加@Size(min = 3, max = 5)注解 * *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcSize类的mySize属性 -> 个数必须在3和5之间 */ @Test public void testSize() { ValidationBeanModel.AbcSize vm = new ValidationBeanModel().new AbcSize(); List list = new ArrayList<>(4); list.add(0); list.add(1); vm.setMySize(list); fa(vm); } /** * 在myURL属性上加@URL注解 * *

* 程序输出: com.aspire.model.ValidationBeanModel$AbcURL类的myURL属性 -> 需要是一个合法的URL */ @Test public void testURL() { ValidationBeanModel.AbcURL vm = new ValidationBeanModel().new AbcURL(); vm.setMyURL("www.baidu.xxx"); fa(vm); } private void fa(T obj) { Set> cvSet = validator.validate(obj); for (ConstraintViolation cv : cvSet) { System.err.println(cv.getRootBean().getClass().getName() + "类的" + cv.getPropertyPath() + "属性 -> " + cv.getMessage()); } } }

 

@Validated的使用时机

@Validated的使用位置较多(可详见源码),但其主流的使用位置却是以下两种:

◎在Controller层中,放在模型参数对象前。
          当Controller层中参数是一个对象模型时,只有将@Validated直接放在该模型前,该模型内部的字段才会被
   校验(如果有对该模型的字段进行约束的话)。

◎在Controller层中,放在类上。
           当一些约束是直接出现在Controller层中的参数前时,只有将@Validated放在类上时,参数前的约束才会生效。

以下是简单的测试代码:

import com.aspire.model.ValidationBeanModel;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.DecimalMax;

/**
 * Controller层 --- 初步简单测试 @Validated 的使用位置
 *
 * 对比测试过程:
 *    方案一 : 不在类上加@Validated注解,访问这六个接口
 *    方案二 : 在类上加@Validated注解,再次访问这六个接口
 *
 *    对比方案一和方案二,可初步得出@Validated的使用时机:
 *        1.当我们是在模型里面对模型字段添加约束注解,在Controller中使用模型接收数
 *          据时,@Validated要直接放在该模型参数前才有效。 如: "/test/one"
 *        2.当我们是直接在Controller层中的参数前,使用约束注解时,@Validated要直接放在类上,
 *          才会有效。如: /test/six
 *
 *
 * @author JustryDeng
 * @date 2019/1/18 22:22
 */
@RestController
@Validated
public class JustryDengController {


    @RequestMapping(value = "/test/one")
    public String validatioOne(@Validated ValidationBeanModel.AbcDecimalMax myDecimalMax) {
        System.out.println(myDecimalMax.getMyDecimalMax());
        return "one pass!";
    }

    @RequestMapping(value = "/test/two")
    @Validated
    public String validatioTwo(ValidationBeanModel.AbcDecimalMax myDecimalMax) {
        System.out.println(myDecimalMax.getMyDecimalMax());
        return "two pass!";
    }

    @RequestMapping(value = "/test/three")
    public String validatioThree(ValidationBeanModel.AbcDecimalMax myDecimalMax) {
        System.out.println(myDecimalMax.getMyDecimalMax());
        return "three pass!";
    }

    @RequestMapping(value = "/test/four")
    public String validatioFour(@Validated  @DecimalMax(value = "12.3") String myDecimalMax) {
        System.out.println(myDecimalMax);
        return "four pass!";
    }

    @RequestMapping(value = "/test/five")
    @Validated
    public String validatioFive(@DecimalMax(value = "12.3") String myDecimalMax) {
        System.out.println(myDecimalMax);
        return "five pass!";
    }

    @RequestMapping(value = "/test/six")
    @Validated
    public String validatioSix(@DecimalMax(value = "12.3") String myDecimalMax) {
        System.out.println(myDecimalMax);
        return "six pass!";
    }
}

 

@Validated与@Valid的简单对比说明

        @Valid注解与@Validated注解功能大部分类似;两者的不同主要在于:@Valid属于javax下的,而@Validated属于spring下;@Valid支持嵌套校验、而@Validated不支持,@Validated支持分组,而@Valid不支持。笔者这里只简单介绍@Validated的使用时机。

 

自定义注解

        虽然Bean Validation和Hibernate Validator已经提供了非常丰富的校验注解,但是在实际业务中,难免会碰到一些现有注解不足以校验的情况;这时,我们可以考虑自定义Validation注解。

示例:

第一步:创建自定义注解

import com.aspire.constraints.impl.JustryDengValidator;

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

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 自定义校验注解
 * 提示:
 *     1、message、contains、payload是必须要写的
 *     2、还需要什么方法可根据自己的实际业务需求,自行添加定义即可
 *
 * @author JustryDeng
 * @date 2019/1/15 1:17
 */
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
@Documented
// 指定此注解的实现,即:验证器
@Constraint(validatedBy ={JustryDengValidator.class})
public @interface ConstraintsJustryDeng {

    // 当验证不通过时的提示信息
    String message() default "JustryDeng : param value must contais specified value!";

    // 根据实际需求定的方法
    String contains() default "";

    // 约束注解在验证时所属的组别
    Class[] groups() default { };

    // 负载
    Class[] payload() default { };
}

第二步:编写(第一步中的校验器实现类)该注解

import com.aspire.constraints.anno.ConstraintsJustryDeng;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * ConstraintsJustryDeng注解 校验器 实现
 * 

* 注:验证器需要实现ConstraintValidator, 其中 U为对应的注解类, V为该注解的@Target指向的类型 * * @author JustryDeng * @date 2019/1/15 1:19 */ public class JustryDengValidator implements ConstraintValidator { /** 错误提示信息 */ private String contains; /** * 初始化方法, 在执行isValid 方法前,会先执行此方法 * * @param constraintAnnotation * 注解信息模型,可以从该模型中获取注解类中定义的一些信息,如默认值等 * @date 2019/1/19 11:27 */ @Override public void initialize(ConstraintsJustryDeng constraintAnnotation) { System.out.println(constraintAnnotation.message()); this.contains = constraintAnnotation.contains(); } /** * 校验的具体逻辑实现 *

* 注: 此方法可能会并发执行,需要根据实际情况看否是需要保证 线程安全 * * @param value * 被自定义注解所标注的对象的 值 * @param context * Provides contextual data and operation when applying a given constraint validator. * @return 校验是否通过 * @date 2019/1/19 11:30 */ @Override public boolean isValid(Object value, ConstraintValidatorContext context) { if (value == null) { return false; } if (value instanceof String) { String strMessgae = (String) value; return strMessgae.contains(contains); } else if (value instanceof Integer) { return contains.contains(String.valueOf(value)); } return false; } }

第三步:自定义注解简单使用测试

Controller层中是这样的:

SpringBoot使用Validation校验参数_第1张图片

访问一下这个接口(当参数值符合要求时):

SpringBoot使用Validation校验参数_第2张图片

访问一下这个接口(当参数值不符合要求时):

SpringBoot使用Validation校验参数_第3张图片

 

对注解抛出的异常进行处理

说明:当注解校验不通过时,直接将异常信息返回给前端其实并不友好,我们可以将异常包装一下,返回给前端。

情况一:使用BindingResult类来容纳错误信息,当校验不通过时,不影响正常程
              序往下走

描述:当我们将@Validated注解放在参数模型前时,会校验该参数模型内的被标注了的字段。当校验不通过时
           会抛出MethodArgumentNotValidException异常。

处理前:

参数模型是这样的:

SpringBoot使用Validation校验参数_第4张图片

Controller是这样的:

SpringBoot使用Validation校验参数_第5张图片

使用postman测试,当校验不通过时显示如下:

SpringBoot使用Validation校验参数_第6张图片

处理后:

参数模型是这样的(没有变):

SpringBoot使用Validation校验参数_第7张图片

Controller是这样的(在@Validated注解的参数后,紧接着加上BindingResult):

SpringBoot使用Validation校验参数_第8张图片

再次使用postman测试,当校验不通过时显示如下:

SpringBoot使用Validation校验参数_第9张图片

postman中返回了数据,说明虽然参数错误,但是不影响程序的执行。

程序在控制台输出了如下信息:

SpringBoot使用Validation校验参数_第10张图片

可见,后台已经获悉了错误,至于怎么处理,这就看伟大的程序员们了。

情况二(推荐):通过AOP来处理异常(即:全局异常处理)

描述:当我们将@Validated注解放在参数模型前时,会校验该参数模型内的被标注了的字段。当校验不
           通过时会抛出MethodArgumentNotValidException异常;当我们将@Validated注解放在类上时,
           会校验该类中的所有接口中的直接被约束的参数,当校验不通过时会抛出
           ConstraintViolationException异常。

处理前:

示例一:Controller是这样的:

SpringBoot使用Validation校验参数_第11张图片

使用postman测试,当校验不通过时显示如下:

SpringBoot使用Validation校验参数_第12张图片

 

示例二:Controller是这样的:

SpringBoot使用Validation校验参数_第13张图片

注:此处的User模型与情况一里给出的模型是一样的,这里就不再给出了。

使用postman测试,当校验不通过时显示如下:

SpringBoot使用Validation校验参数_第14张图片

进行处理:加入AOP全局异常处理器:

import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;

/**
 * SpringMVC统一异常处理
 * 注:@ControllerAdvice为Controller层增强器,其只能处理Controller层抛出的异常;
 * 由于代码间的层级调用机制  、异常的处理机制等,所以这里处理Controller层的异常,就相当于
 * 处理了全局异常
 * 

* 注: @RestControllerAdvice等同于 @ResponseBody 加上 @ControllerAdvice * * @author JustryDeng */ @RestControllerAdvice public class GlobalExceptionHandler { /** * 具体的处理异常的逻辑 * 注:@ExceptionHandler的value属性指定要处理哪些异常; * * @param ex * 捕获到的异常 * @return 返回给前端的data */ @ExceptionHandler(value = {Exception.class}) public Map globalExceptionHandleMethod(Exception ex) { Map resultMap = new HashMap<>(4); if (ex instanceof ConstraintViolationException) { ConstraintViolationException cvExceptionex = (ConstraintViolationException) ex; resultMap.put("msg", "@Validated约束在类上,直接校验接口的参数时异常 -> " + cvExceptionex.getMessage()); resultMap.put("code", "1"); } else if (ex instanceof MethodArgumentNotValidException) { MethodArgumentNotValidException manvExceptionex = (MethodArgumentNotValidException) ex; resultMap.put("msg", "@Validated约束在参数模型前,校验该模型的字段时发生异常 -> " + manvExceptionex.getMessage()); resultMap.put("code", "2"); } else { resultMap.put("msg", "系统异常"); resultMap.put("code", "3"); } return resultMap; } }

处理后,使用postman再次进行上述两个请求:

SpringBoot使用Validation校验参数_第15张图片

SpringBoot使用Validation校验参数_第16张图片

可见,异常处理成功!

 

笔者寄语:

  1. 本文只是对@Validated注解的简单探索,校验性注解用法较灵活,笔者后面有时间会进一步补充。
  2. 技术学习只是理论上的,一些细节、一些坑还需要在实战中发现总结。

 

^_^ 如有不当之处,欢迎指正

^_^ 测试项目代码托管链接:
               
https://github.com/JustryDeng/CommonRepository

^_^ 本文已经被收录进《程序员成长笔记(四)》,笔者JustryDeng

你可能感兴趣的:(Java知识大杂烩)