Spring boot 使用 AOP 验证请求参数

VO 声明验证

在 VO 中使用 javax.validation.constraints 包提供的验证注解:

	@Data
	public class AnchorRecordVO {
	    @NotNull(message = "基站编号不能为空")
	    private Long num;
	
	    @NotNull(message = "天线编号不能为空")
	    private Integer antId;
	
	    private String site;
	
		...
	}

Controller 中使用 @Validated

在请求参数前使用 @Valid 注解就可以完成验证,验证结果将存放到 BindingResult 中。

	@RequestMapping(value = "/anchors", method = RequestMethod.POST)
    @ResponseBody
    public ResultBean addAnchor(@RequestBody @ValidatedAnchorRecordVO vo, BindingResult bindingResult) {
        return new ResultBean(anchorService.save(vo));
    }

使用 ControllerAdvice 统一处理

定义一个异常处理, 使用 @ResponseBody 注解才能返回自定义格式,否则Spring 将包装一个返回结果,并且 HTTP Status 为400

	@ControllerAdvice
	@Slf4j
	public class ControllerExceptionHandler {
	
	    /**
	     * 处理验证异常
	     *
	     * @param request
	     * @param exception
	     * @return
	     */
	    @ExceptionHandler(MethodArgumentNotValidException.class)
	    @ResponseBody
	    public ResultBean handleBindException(HttpServletRequest request, MethodArgumentNotValidException exception) {
	
	        log.error("访问" + request.getRequestURI() + "发生参数验证异常", exception);
	
	        ResultBean<?> result = new ResultBean();
	
	        String messages = exception.getBindingResult().getAllErrors()
	                .stream()
	                .map(ObjectError::getDefaultMessage)
	                .reduce((m1, m2) -> m1 + "," + m2)
	                .orElse("参数输入有误");
	
	        result.setMsg(messages);
	        result.setCode(FAIL);
	
	        return result;
	    }
	
	    /**
	     * 处理参数类型转换异常
	     *
	     * @param request
	     * @param exception
	     * @return
	     */
	    @ExceptionHandler(InvalidFormatException.class)
	    @ResponseBody
	    public ResultBean handleParseException(HttpServletRequest request, InvalidFormatException exception) {
	
	
	        String messages = String.format("字段 [%s] 的值 [%s] 不能转换成 [%s] 类型", exception.getPathReference(),
	                exception.getValue(), exception.getTargetType().getName());
	
	        log.error("访问" + request.getRequestURI() + "发生参数验证异常 : {}", messages);
	
	        ResultBean<?> result = new ResultBean();
	        result.setMsg("参数类型输入有误");
	        result.setCode(FAIL);
	
	        return result;
	    }
	}

类库说明

1. 注解说明

验证注解验证的数据类型说明
@AssertFalseBoolean,boolean验证注解的元素值是false
@AssertTrueBoolean,boolean验证注解的元素值是true
@NotNull任意类型验证注解的元素值不是null
@Null任意类型验证注解的元素值是null
@Min(value=值)BigDecimal,BigInteger, byte,short, int, long,等任何Number或CharSequence(存储的是数字)子类型验证注解的元素值大于等于@Min指定的value值
@Max(value=值)和@Min要求一样验证注解的元素值小于等于@Max指定的value值
@DecimalMin(value=值)和@Min要求一样验证注解的元素值大于等于@ DecimalMin指定的value值
@DecimalMax(value=值)和@Min要求一样验证注解的元素值小于等于@ DecimalMax指定的value值
@Digits(integer=整数位数, fraction=小数位数)和@Min要求一样验证注解的元素值的整数位数和小数位数上限
@Size(min=下限, max=上限)字符串、Collection、Map、数组等验证注解的元素值的在min和max(包含)指定区间之内,如字符长度、集合大小
@Pastjava.util.Date,java.util.Calendar;Joda Time类库的日期类型验证注解的元素值(日期类型)比当前时间早
@Future与@Past要求一样验证注解的元素值(日期类型)比当前时间晚
@NotBlankCharSequence子类型验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的首位空格
@Length(min=下限, max=上限)CharSequence子类型验证注解的元素值长度在min和max区间内
@NotEmptyCharSequence子类型、Collection、Map、数组验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@Range(min=最小值, max=最大值)BigDecimal,BigInteger,CharSequence, byte, short, int, long等原子类型和包装类型验证注解的元素值在最小值和最大值之间
@Email(regexp=正则表达式,flag=标志的模式)CharSequence子类型(如String)验证注解的元素值是Email,也可以通过regexp和flag指定自定义的email格式
@Pattern(regexp=正则表达式,flag=标志的模式)String,任何CharSequence的子类型验证注解的元素值与指定的正则表达式匹配
@Valid任何非原子类型指定递归验证关联的对象如用户对象中有个地址对象属性,如果想在验证用户对象时一起验证地址对象的话,在地址对象上加@Valid注解即可级联验证

2. 使用groups的校验

同一个对象要复用,但在不同场景下要求实效不同的校验规则, 如 ID 字段,在新增时不需要验证, 但在更新接口中要求不能为空。

2.1 先定义groups的分组接口

	import javax.validation.groups.Default;
	
	public interface Create extends Default {
	}
	
	import javax.validation.groups.Default;
	
	public interface Update extends Default{
	}

2.2 在验证类校验注解中使用

   @NotNull(message = "id不能为空", groups = Update.class)
   private Long userId;

2.3 Controller 中设置 Groups

    public ResultBean update(@RequestBody @Validated(Update.class) UserVo userVo){
    }

3. 在Controller接口中直接使用

3.1 接口方法中使用验证注解

    public ResultBean getUser(@RequestParam("userId") @NotNull(message = "用户id不能为空") Long userId) {

3.2 Controller 中开启验证

	@RestController
	@RequestMapping("user/")
	@Validated
	public class UserController{ ... }

版权声明:本文为weixin_39340061原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。