【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验

文章目录

  • JSR303数据校验
    • 引入依赖和简介
    • 配置验证规则
    • 开启验证
    • BindResult
    • 校验的统一异常处理
    • JSR303分组校验
    • 自定义校验注解


JSR303数据校验

引入依赖和简介

引入依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-validationartifactId>
dependency>

里面依赖了hibernate-validator 在非空处理方式上提供了@NotNull,@NotBlank和@NotEmpty

1 @NotNull

注解元素禁止为null,能够接收任何类型

2 @NotEmpty

该注解修饰的字段不能为null或""

支持以下几种类型:

  • 字符序列(字符序列长度的计算)

  • 集合长度的计算

  • map长度的计算

  • 数组长度的计算

3 @NotBlank

该注解不能为null,并且至少包含一个非空格字符。接收字符序列。

配置验证规则

/**
 * 品牌
 * @author WSKH
 * @email [email protected]
 * @date 2022-01-03 18:28:04
 */
@Data
@ToString
@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(message = "品牌logo地址不能为空")
//	@URL(message = "品牌logo地址必须是合法的URL")
	private String logo;
	/**
	 * 介绍
	 */
	@NotEmpty(message = "描述信息不能为空")
	private String descript;
	/**
	 * 显示状态[0-不显示;1-显示]
	 */
	@NotNull(message = "显示状态不能为null")
	private Integer showStatus;
	/**
	 * 检索首字母
	 */
	@Pattern(regexp = "[a-zA-Z]",message = "检索首字母必须是a-z或A-Z")
	@NotEmpty(message = "检索首字母不能为空")
	private String firstLetter;
	/**
	 * 排序
	 */
	@NotNull(message = "排序信息不能为null")
	private Integer sort;

}

开启验证

在需要验证的controller参数前加上注解,即可开启验证

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第1张图片

用postMan进行测试

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第2张图片

测试结果如下:

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第3张图片

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第4张图片

BindResult

给校验的Bean后,紧跟一个BindResult,就可以获取到校验的结果。拿到校验的结果,就可以自定义的封装。

    @RequestMapping("/save")    
    public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
        if( result.hasErrors()){
            Map<String,String> map=new HashMap<>();
            // 1.获取错误的校验结果
            result.getFieldErrors().forEach((item)->{
                // 2.获取发生错误时的message
                String message = item.getDefaultMessage();
                // 3.获取发生错误的属性名
                String field = item.getField();
                map.put(field,message);
            });
            return R.error(400,"提交的数据不合法").put("data",map);
        }else {
            // 如果校验通过 就进行保存操作
            brandService.save(brand);
            return R.ok();
        }
    }

再用PostMan进行测试看看

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第5张图片

比刚刚整齐好看多了!

校验的统一异常处理

可以使用SpringMvc所提供的@ControllerAdvice,通过“basePackages”能够说明处理哪些路径下的异常。

0 将原来controller上的BindResult去掉

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第6张图片

1 抽取一个异常处理类

// 开启日志功能
@Slf4j
// 使用SpringMvc所提供的@ControllerAdvice,通过“basePackages”能够说明处理哪些路径下的异常。
@RestControllerAdvice(basePackages = "com.wskh.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
    @ExceptionHandler(value = Exception.class) // 也可以返回ModelAndView
    public R handleValidException(MethodArgumentNotValidException exception){

        Map<String,String> map=new HashMap<>();
        // 获取数据校验的错误结果
        BindingResult bindingResult = exception.getBindingResult();
        bindingResult.getFieldErrors().forEach(fieldError -> {
            String message = fieldError.getDefaultMessage();
            String field = fieldError.getField();
            map.put(field,message);
        });

        log.error("数据校验出现问题{},异常类型{}",exception.getMessage(),exception.getClass());

        return R.error(400,"数据校验出现问题").put("data",map);
    }

}

2 默认异常处理

    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        log.error("未知异常{},异常类型{}",throwable.getMessage(),throwable.getClass());
        return R.error(400,"数据校验出现问题");
    }

3 错误状态码和错误信息规范化声明

/***
 * 错误码和错误信息定义类
 * 1. 错误码定义规则为5为数字
 * 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
 * 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
 * 错误码列表:
 *  10: 通用
 *      001:参数格式校验
 *  11: 商品
 *  12: 订单
 *  13: 购物车
 *  14: 物流
 */
public enum BizCodeEnum {

    UNKNOW_EXEPTION(10000,"系统未知异常"),

    VALID_EXCEPTION( 10001,"参数格式校验失败");

    private int code;
    private String msg;

    BizCodeEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

4 使用错误状态码和状态信息

// 开启日志功能
@Slf4j
// 使用SpringMvc所提供的@ControllerAdvice,通过“basePackages”能够说明处理哪些路径下的异常。
@RestControllerAdvice(basePackages = "com.wskh.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
    @ExceptionHandler(value = Exception.class) // 也可以返回ModelAndView
    public R handleValidException(MethodArgumentNotValidException exception){

        Map<String,String> map=new HashMap<>();
        // 获取数据校验的错误结果
        BindingResult bindingResult = exception.getBindingResult();
        bindingResult.getFieldErrors().forEach(fieldError -> {
            String message = fieldError.getDefaultMessage();
            String field = fieldError.getField();
            map.put(field,message);
        });

        log.error("数据校验出现问题{},异常类型{}",exception.getMessage(),exception.getClass());

        return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(),BizCodeEnum.VALID_EXCEPTION.getMsg()).put("data",map);
    }

    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        log.error("未知异常{},异常类型{}",throwable.getMessage(),throwable.getClass());
        return R.error(BizCodeEnum.UNKNOW_EXEPTION.getCode(),BizCodeEnum.UNKNOW_EXEPTION.getMsg());
    }

}

5 测试下看看

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第7张图片

错误状态码和错误信息都已经按照我们自定义的输出了

JSR303分组校验

分组校验常常用于完成多场景的复杂校验

如:指定在更新和添加的时候,都需要进行校验。新增时不需要带id,修改时必须带id

1 在common模块下创建一个文件夹vaild,里面创建两个空的接口AddGroup和UpdateGroup

image-20220127151633431

2 在请求传入参数对象中的校验注解中指定其生效的groups

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第8张图片

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第9张图片

3 在controller中加入@Validated注解,并指定其对应的分组

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第10张图片

4 测试下看看

指定id,测试新增产品

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第11张图片

不指定id,测试修改产品

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第12张图片

自定义校验注解

场景:要校验showStatus的01状态,可以用正则,但我们可以利用其他方式解决

1 添加依赖

<dependency>
    <groupId>javax.validationgroupId>
    <artifactId>validation-apiartifactId>
    <version>2.0.1.Finalversion>
dependency>

2 common模块中新建空接口UpdateStatusGroup,代表只校验showStatus的分组

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第13张图片

3 编写自定义的校验器

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

    }
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        // 如果所传参数在指定的set集合中,才允许校验通过
        return  set.contains(value);
    }
}

4 编写自定义的校验注解

@Documented
// 关联校验器和校验注解(一个校验注解可以匹配多个校验器)
@Constraint(validatedBy = { ListValueConstraintValidator.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    // 使用该属性去Validation.properties中取
    String message() default "{com.wskh.common.valid.ListValue.message}";

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

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

    int[] value() default {};
}

5 在common模块的resources文件夹下,创建Validation.properties文件,在里面定义校验失败要返回的msg

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第14张图片

6 将注解应用在实例对象的显示状态属性上,并设置分组

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第15张图片

7 新增一个只用来修改显示状态的controller方法,分组设置为UpdateStatusGroup.class

    /**
     * 修改显示状态
     */
    @RequestMapping("/update/status")
    // @RequiresPermissions("product:brand:update")
    public R updateStatus(@Validated(UpdateStatusGroup.class) @RequestBody BrandEntity brand){
        brandService.updateById(brand);

        return R.ok();
    }

8 测试一下看看

先试一下不输入显示状态

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第16张图片

再试一下输入显示状态为3,会不会成功报错

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第17张图片

这里可以看到已经报错了,而且是按照配置文件中的msg来报的,只不过由于项目的编码格式问题,导致出现了乱码

解决方案:在idea设置中,将项目编码格式全部设置为UTF-8

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第18张图片

如果改了之后还是这样。那就用英文吧…

image-20220127181709444

【系统开发】尚硅谷 - 谷粒商城项目笔记(四):JSR303数据校验_第19张图片

你可能感兴趣的:(系统开发,笔记,java,谷粒商城,数据校验,尚硅谷,JSR303)