前言
数据校验是用来判断输入的数据是否满足规定的要求的。
前端可用JS来校验,如用户名唯一性,生日格式,邮箱格式校验等。
前端做了数据校验,后端也做数据校验的原因是防止有人绕过前端界面,直接向后端发起请求,导致数据库内写入了脏数据。
常用注解
JSR提供的校验注解: @Null 被注释的元素必须为 null @NotNull 被注释的元素必须不为 null @AssertTrue 被注释的元素必须为 true @AssertFalse 被注释的元素必须为 false @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 @Size(max=, min=) 被注释的元素的大小必须在指定的范围内 @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内 @Past 被注释的元素必须是一个过去的日期 @Future 被注释的元素必须是一个将来的日期 @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式 Hibernate Validator提供的校验注解: @NotBlank(message =) 验证字符串非null,且长度必须大于0 @Email 被注释的元素必须是电子邮箱地址 @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内 @NotEmpty 被注释的字符串的必须非空 @Range(min=,max=,message=) 被注释的元素必须在合适的范围内
讯享网
实战
1、添加校验注解
在属性上添加校验注解,用于校验输入的属性是否符合校验规则。
还可以在校验注解上自定义校验失败后显示的信息。如@Null(message = “新增时不能指定id”),当校验失败后,错误信息展示为message中内容。
讯享网/ * 品牌 * * @author xiao-wang * @email * @date 2022-03-09 10:19:41 */ @Data @TableName("pms_brand") public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L; / * 品牌id */ @TableId @Null(message = "新增时不能指定id") private Long brandId; / * 品牌名 */ @NotBlank(message = "品牌名不能为空") private String name; / * 品牌logo地址 */ @NotBlank @URL(message = "url地址必须是一个有效的地址") private String logo; / * 介绍 */ private String descript; / * 显示状态[0-不显示;1-显示] */ // @TableLogic(value = "1",delval = "0") @NotNull(message = "显示状态不能为空") private Integer showStatus; / * 检索首字母 */ @NotBlank @Pattern(regexp = "^[a-zA-Z]$",groups = {
message = "首字母必须为a-z或者A-Z中的一个字母") private String firstLetter; / * 排序 */ @NotNull private Integer sort; }
2、在controller层添加@valid注解
只添加校验注解,校验是不会生效的。在controller层的某个方法上添加了@valid注解,校验才会生效。
@RestController @RequestMapping("product/brand") public class BrandController {
@Autowired private BrandService brandService; @RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand){
brandService.save(brand); return R.ok(); } }
用postman测试,校验完成,出现提示信息。
讯享网{
"timestamp": "2022-03-31 02:15:05", "status": 400, "error": "Bad Request", "errors": [ {
"codes": [ "NotBlank.brandEntity.name", "NotBlank.name", "NotBlank.java.lang.String", "NotBlank" ], "arguments": [ {
"codes": [ "brandEntity.name", "name" ], "arguments": null, "defaultMessage": "name", "code": "name" } ], "defaultMessage": "品牌名不能为空", "objectName": "brandEntity", "field": "name", "rejectedValue": "", "bindingFailure": false, "code": "NotBlank" } ], "message": "Validation failed for object='brandEntity'. Error count: 6", "path": "/product/brand/save" }
但是返回的格式不是自己需要的。
要求返回的格式:
{
"msg": "提交数据不合法", "code": 400, "data": {
"校验失败属性名": "错误提示信息", } }
3、统一异常处理
为了规范异常返回的格式,返回一个R类型,R类型的格式为上述要求返回的格式
避免代码的冗余,新建一个类用来统一异常处理。
讯享网@Slf4j @RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller") public class GulimallExceptionController {
@ExceptionHandler(value = MethodArgumentNotValidException.class) //表示能捕获的异常类型为MethodArgumentNotValidException public R methodArgumentValidException(MethodArgumentNotValidException e){
log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass()); BindingResult bindingResult = e.getBindingResult(); //e.getBindingResult()表示校验结果 Map<String,String> errorsMap = new HashMap<>(); bindingResult.getFieldErrors().forEach((item)->{
//遍历校验结果中的错误信息 String field = item.getField(); //错误信息中的报错的属性名 String message = item.getDefaultMessage(); //报错的错误提示 errorsMap.put(field,message); }); return R.error(400,"提交数据不合法").put("data",errorsMap); } }
分组校验
有的属性在新增的时候必须为空,但是修改的时候必须不为空
所以,需要对属性进行分组校验。
1、创建好分组接口,并在实体类的属性上加上groups=哪个分组
@Data @TableName("pms_brand") public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L; / * 品牌id */ @TableId @Null(message = "新增时不能指定id",groups = {
AddGroup.class}) @NotNull(message = "修改时必须指定id",groups = {
UpdateGroup.class}) private Long brandId; / * 品牌名 */ @NotBlank(message = "品牌名不能为空",groups = {
AddGroup.class}) private String name; / * 品牌logo地址 */ @NotBlank(groups = {
AddGroup.class}) @URL(message = "url地址必须是一个有效的地址",groups = {
AddGroup.class,UpdateGroup.class}) private String logo; / * 介绍 */ private String descript; / * 显示状态[0-不显示;1-显示] */ // @TableLogic(value = "1",delval = "0") @NotNull(groups = {
AddGroup.class},message = "显示状态不能为空") @ListValues(values = {
0,1},groups = {
AddGroup.class}) private Integer showStatus; / * 检索首字母 */ @NotBlank(groups = {
AddGroup.class}) @Pattern(regexp = "^[a-zA-Z]$",groups = {
AddGroup.class, UpdateGroup.class},message = "首字母必须为a-z或者A-Z中的一个字母") private String firstLetter; / * 排序 */ @NotNull(groups = {
AddGroup.class}) private Integer sort; }
2、controller层需要将@valid注解换成@Validated注解
由上可知,只添加注解是不会生效的,需要在controller层的方法内添加@Valid注解,但是@Valid注解没有分组功能,因此,换成@Validated注解,指定生效的是哪个分组。
讯享网@RestController @RequestMapping("product/brand") public class BrandController {
@Autowired private BrandService brandService; @RequestMapping("/save") public R save(@Validated(value = {
AddGroup.class}) @RequestBody BrandEntity brand){
brandService.save(brand); return R.ok(); } }
自定义校验
1、自定义校验注解
自己添加一个注解,规定该属性值只能填入规定的0和1,否则会报错

@Constraint(validatedBy = {
ListvaluesConstraintValidator.class}) //指定该注解由ListvaluesConstraintValidator.class来校验 @Target({
ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface ListValues {
String message() default "{com.atguigu.common.valid.ListValues.message}"; //在resources中新建ValidationMessages.properties(必须为此名字),就可指定该注解的默认报错信息 //在ValidationMessages.properties中填写,com.atguigu.common.valid.ListValues.message = 请输入指定的值, //当报错时,默认报错信息为“请输入指定值” Class<?>[] groups() default {
}; Class<? extends Payload>[] payload() default {
}; int[] values() default {
}; }
2、编写校验类
校验类实现真正的校验功能,initialize表示初始化功能,isValid判断是否校验成功。
讯享网public class ListvaluesConstraintValidator implements ConstraintValidator<ListValues,Integer> {
HashSet<Integer> set = new HashSet<Integer>(); public void initialize(ListValues constraintAnnotation) {
for (int value : constraintAnnotation.values()) {
set.add(value); } } public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(integer); } }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/34358.html