一、参数校验

          常见的用于校验的注解有

@NotNull      用于校验数字类型         javax.validation.constraints.NotNull;

@Max           用于校验数字最大值      javax.validation.constraints.Max;

@Min            用于校验数字最小值      javax.validation.constraints.Min;

@NotEmpty  用于校验集合长度         javax.validation.constraints.NotEmpty

@NotBlank   用于校验字符串非空      javax.validation.constraints.NotBlank

@Length       用于校验字符串长度     org.hibernate.validator.constraints.Length

          编写一个电话Phone实体,使用上述的注解。

package com.zhoutianyu.learnspringboot.valid;

import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.*;

@Data
public class Phone {

@NotNull(message = "电话号码不能为空")
private Long number;


@Max(value = 5000, message = "预算价格不能超过{value}元")
@Min(value = 1000, message = "预算价格不能低于{value}元")
private double price;

@NotBlank(message = "品牌不能为空")
@Length(max = 5, message = "品牌长度不能超过{max}")
private String brand;
}

        再编写一个PhoneController,使用上面的这个电话实体。

        只要在实体前面加上@Valid注解,并且在后面使用一个叫做BindingResult的实体来保存错误信息,就能实现过滤效果。

        下面的实现中,把错误的数据保存在了一个Map集合中。实际中会把map中的错误信息再传给前端小姐姐。

package com.zhoutianyu.learnspringboot.valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class PhoneController {
private static final Logger LOGGER = LoggerFactory.getLogger(PhoneController.class);

@GetMapping(value = "/phone/test")
public Phone buyPhone(@Valid Phone phone, BindingResult result) {
List<FieldError> fieldErrors = result.getFieldErrors();
Map<String, Object> errorMap = new HashMap<>(10);
fieldErrors.forEach(error -> {
LOGGER.error("字段:{}校验失败, Message:{} \n", error.getField(), error.getDefaultMessage());
errorMap.put(error.getField(), error.getDefaultMessage());
}
);
return phone;
}
}

二、测试

        启动项目,在浏览器上访问​​http://localhost:8081/study/springboot/phone/test​​。

        控制台输出:

       

第三节  SpringBoot参数校验_spring

       加上一些参数看看。

       在浏览器上访问​​http://localhost:8081/study/springboot/phone/test?brand=HUAWEI&price=20000&number=110120119​​。

       添加了三个参数。品牌为HUAWEI,但是超过了最大5个字的限制,价格传了2万,超过了预算。下图符合预期。

      

第三节  SpringBoot参数校验_错误信息_02

三、补充

       其实上述的第二个参数BindingResult可以忽略,那么错误信息将会以异常的形式抛出来。所以一般公司里的项目会使用一个全局异常拦截器来拦截此请求。

       下面是我的测试用例。

        有一个查询实体DictionQuery,它专门用于接收前端传过来的参数,dicTypeId不能为空。

public class DictionQuery ...

@NotNull(message = "dicTypeId不能为空")
private Long dicTypeId;
}

GET请求方法,它没有使用BindingResult参数来接收校验结果。如果参数里面的dicTypeId为null,那么就会抛出异常BindingException。

@GetMapping("/dic/list")
public MultiResponse<DicInfoVO> getDicList(@Valid DicListQry dicListQry) {
return null;
}

Post请求,dicTypeId的值还是传null。那么抛出的异常不一样,抛出 MethodArgumentNotValidException。

@PostMapping("/dic/list")
public MultiResponse<DicInfoVO> getDicListPost(@RequestBody @Valid DicListQry dicList) {
return null;
}

把接收的List做成一个类的成员变量,然后在List上添加@Valid注解。 请求的时候,需要配合使用@Validated注解。参考:Java 对list对象进行属性校验

@PostMapping("/dic/list")
public MultiResponse<DicInfoVO>
getDicListPost(@RequestBody @Validated DicList dicList) {
return dictionaryService.getDicList(null);
}


@Data
private static class DicList {

@Valid
private List<DicListQry> dicListQry;
}

       一般用于处理全局响应的代码:

@ExceptionHandler({MethodArgumentNotValidException.class, 
BindException.class, ConstraintViolationException.class})
public Response handlerViolationException(Exception exception) ...
String errMsg = "服务器内部错误";
if (exception instanceof MethodArgumentNotValidException) {
errMsg = handlerBindingResult(((MethodArgumentNotValidException) exception).getBindingResult());
} else if (exception instanceof BindException) {
errMsg = handlerBindingResult(((BindException) exception).getBindingResult());
} else if (exception instanceof ConstraintViolationException) {
errMsg = handlerConstraintViolationException((ConstraintViolationException) exception);
}

// return 默认错误实体...
}


private String handlerBindingResult(BindingResult bindingResult) {
return bindingResult.getFieldErrors()
.stream().map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining(", "));
}

private String handlerConstraintViolationException(ConstraintViolationException exception) {
// 使用Set去除集合中重复的错误信息
Set<String> errMessages = exception.getConstraintViolations()
.stream().map(ConstraintViolation::getMessage).collect(Collectors.toSet());
return String.join(", ", errMessages);
}

 

四、源码下载

        本章节项目源码:​​点我下载源代码​

        ​