JSR303数字校验

1.基本校验实现
  • spirngboot2.3.0以上需要导入依赖
    <!--        数据校验依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.6.7</version>
        </dependency>
  • 给bean加校验注解,并定义自己的message信息提示
package com.gek.gulimall.product.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.hibernate.validator.constraints.URL;

import javax.validation.constraints.*;

/**
 * 品牌
 * 
 * @author gek
 * @email gek@gmail.com
 * @date 2022-04-21 15:17:16
 */
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 品牌id
	 */
	@TableId
	private Long brandId;
	/**
	 * 品牌名
	 */
	@NotBlank(message = "品牌名必须提交")
	private String name;
	/**
	 * 品牌logo地址
	 */
	@NotEmpty
	@URL(message = "logo必须是一个合法的url地址")
	private String logo;
	/**
	 * 介绍
	 */
	private String descript;
	/**
	 * 显示状态[0-不显示;1-显示]
	 */
	private Integer showStatus;
	/**
	 * 检索首字母
	 */
	@NotEmpty
	@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母")
	private String firstLetter;
	/**
	 * 排序
	 */
	@NotNull
	@Min(value = 0,message = "排序必须大于等于0")
	private Integer sort;

}

  • 在需要校验的方法上添加@Valid注解,并返回提示信息
  • 给校验的bean后紧跟一个BindingResult,就可以获取到校验结果
  @RequestMapping("/save")
  //  @RequiresPermissions("product:brand:save")
    public R save(@Valid  @RequestBody BrandEntity brand, BindingResult result){
        if(result.hasErrors()){
            HashMap<String, String> map = new HashMap<>();
//            获取所有的错误信息
            List<FieldError> errors = result.getFieldErrors();
            for (FieldError error : errors) {
//                获取到错误提示
                String message=error.getDefaultMessage();
//                获取到错误提示的属性名
                String fieldName=error.getField();
                map.put(fieldName,message);
            }
            return  R.error().put("data",map);
        }else{
            brandService.save(brand);
        }

        return R.ok();
    }
2. 统一异常处理
  • 针对于错误状态码。是我们进行随意定义的,然而在正规的开发中,有有着严格的定义规则

在这里插入图片描述

  • 为了定义这些错误的状态码,我们可以单独定义一个常量类,用来存储这些错误状态码
  • 在common中新建BizCodeEnume用来存储状态码
package com.gek.common.exception;

public enum BizCodeEnum {
    UNKNOWN_EXCEPTION(10000,"系统未知异常"),

    VALID_EXCEPTION(10001,"参数格式校验失败");
    private int code;
    private String message;
    BizCodeEnum(int code,String message){
        this.code=code;
        this.message=message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

  • 在product里面新建类GulimallExceptionControllerAdvice,用来集中处理所有异常
package com.gek.gulimall.product.exception;

import com.gek.common.exception.BizCodeEnum;
import com.gek.common.utils.R;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.List;

@RestControllerAdvice(basePackages = "com.gek.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
//    处理数据校验异常
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException e){
        BindingResult result = e.getBindingResult();
        HashMap<String, String> map = new HashMap<>();
        List<FieldError> fieldErrors = result.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            String message = fieldError.getDefaultMessage();
            String field = fieldError.getField();
            map.put(field,message);
        }
        return  R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMessage()).put("data",map);
    }
//    处理全局的异常
    @ExceptionHandler(value = Throwable.class)
    public  R handleException(){
        return  R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(), BizCodeEnum.UNKNOWN_EXCEPTION.getMessage());
    }

}

3.分组校验
  • 在common中新建valid包,里面新建两个空接口AddGroup,UpdateGroup用来分组
  • 给校验注解,标注上groups,指定什么情况下才需要进行校验
  • 如:指定在更新和添加的时候,都需要进行校验
package com.gek.gulimall.product.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;

import com.gek.common.exception.AddGroup;
import com.gek.common.exception.UpdateGroup;
import lombok.Data;
import org.hibernate.validator.constraints.URL;

import javax.validation.constraints.*;

/**
 * 品牌
 * 
 * @author gek
 * @email gek@gmail.com
 * @date 2022-04-21 15:17:16
 */
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 品牌id
	 */
	@TableId
	@NotNull(message = "id必须要传",groups = {UpdateGroup.class})
	@Null(message = "id必须不传",groups = {AddGroup.class})
	private Long brandId;
	/**
	 * 品牌名
	 */
	@NotNull
	@NotBlank(message = "品牌名必须提交",groups = {UpdateGroup.class, AddGroup.class})
	private String name;
	/**
	 * 品牌logo地址
	 */
	@NotBlank(groups = {AddGroup.class})
	@URL(message = "logo必须是一个合法的url地址",groups = {UpdateGroup.class,AddGroup.class})
	private String logo;
	/**
	 * 介绍
	 */
	private String descript;
	/**
	 * 显示状态[0-不显示;1-显示]
	 */
	private Integer showStatus;
	/**
	 * 检索首字母
	 */
	@NotEmpty(groups = {AddGroup.class})
	@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母",groups = {UpdateGroup.class,AddGroup.class})
	private String firstLetter;
	/**
	 * 排序
	 */
	@NotNull(groups = {AddGroup.class})
	@Min(value = 0,message = "排序必须大于等于0",groups = {UpdateGroup.class,AddGroup.class})
	private Integer sort;

}

  • 业务方法参数上使用@Validated注解,并在value中给出group接口,标记当前校验是哪个组
    @RequestMapping("/save")
  //  @RequiresPermissions("product:brand:save")
    public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand, BindingResult result){
        if(result.hasErrors()){
            HashMap<String, String> map = new HashMap<>();
//            获取所有的错误信息
            List<FieldError> errors = result.getFieldErrors();
            for (FieldError error : errors) {
//                获取到错误提示
                String message=error.getDefaultMessage();
//                获取到错误提示的属性名
                String fieldName=error.getField();
                map.put(fieldName,message);
            }
            return  R.error().put("data",map);
        }else{
            brandService.save(brand);
        }

        return R.ok();
    }
  • 默认情况下,在分组校验情况下,没有指定指定分组的校验注解,将不会生效,它只会在不分组的情况下生效
4. 自定义校验
  • 编写一个自定义校验注解ListValue
  • 新建配置文件ValidationMessages.properties保存注解信息
  • 编写一个自定义校验气ListValueConstraintValidator
  • 关联自定义校验器和自定义校验注解(可以指定多个不同的校验器,适配不同类型的校验)

注解校验

package com.gek.common.valid;

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.*;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{com.gek.common.valid.ListValue.message}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };
    int[] vals() default { };
}

配置文件:

com.gek.common.valid.ListValue.message=必须提交指定的值

校验器:

package com.gek.common.valid;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;

public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    private Set<Integer> set=new HashSet<>();
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return set.contains(value);
    }
}

关联校验器和校验注解:在校验注解的@Constraint注解上关联校验器

@Constraint(validatedBy = {ListValueConstraintValidator.class})

校验注解添加到showStatus上,进行测试

@ListValue(vals = {0, 1},groups = {AddGroup.class, UpdateGroup.class})
	private Integer showStatus;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值