自学内容网 自学内容网

Spring数据校验

JSR 303 校验注解 @Valid

JSR 303 是 Java 为 Bean 数据合法性校验 提供的标准框架,它已经包含在 JavaEE 6.0 标准中。JSR 303 通过在 Bean 属性上 标注 类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。
数据校验使用流程
1、引入校验依赖:spring-boot-starter-validation
2、定义封装数据的Bean
3、给Bean的字段标注校验注解,并指定校验错误消息提示
4、使用@Valid、@Validated开启校验
5、使用 BindingResult 封装校验结果
6、使用自定义校验注解 + 校验器(implements ConstraintValidator) 完成gender字段自定义校验规则
7、结合校验注解 message属性 与 i18n 文件,实现错误消息国际化
8、结合全局异常处理,统一处理数据校验错误
在这里插入图片描述

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

@Data
public class EmployeeAddVo {

    @NotBlank(message = "姓名不能为空")
    private String name;


    @NotNull(message = "年龄不能为空")
    @Max(value = 150, message = "年龄不能超过150岁")
    @Min(value = 0, message = "年龄不能小于0岁")
    private Integer age;


    @Email(message = "邮箱格式不正确")
    private String email;


    @Gender(message = "{gender.message}") //message = "{}" 占位符
    private String gender;

    private String address;

    private BigDecimal salary;


    //只要是日期:标注统一注解:@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    //默认的日期格式: 2024-09-05T08:47:58.000+00:00
    //反序列化:前端提交日期字符串 ===> 日期对象
    //序列化:  日期对象 ===> 日期字符串
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date birth;
}

但是只标注还不能起作用,在接口接收参数的时候还要加上@Valid 注解

/**
     * 设计模式:单一职责;
     * JavaBean也要分层,各种xxO:
     * Pojo:普通java类
     * Dao:Database Access Object : 专门用来访问数据库的对象
     * DTO:Data Transfer Object: 专门用来传输数据的对象;
     * TO:transfer Object: 专门用来传输数据的对象;
     * BO:Business Object: 业务对象(Service),专门用来封装业务逻辑的对象;
     * VO:View/Value Object: 值对象,视图对象(专门用来封装前端数据的对象)
     *
     *
     * 新增员工;
     * 要求:前端发送请求把员工的json放在请求体中
     * 要求:如果校验出错,返回给前端。
     *   {
     *       "code": 500,
     *       "msg": "校验失败",
     *       "data": {
     *           "name": "姓名不能为空",  //这些就是为了让前端知道是哪些输入框错了,怎么错误,给用户要显示提示。
     *           "age": "年龄不能超过150"
     *       }
     *   }
     * @param vo
     * @return
     */
    @Operation(summary="新增员工")
    @PostMapping("/employee")
    // public R add(@RequestBody @Valid EmployeeAddVo vo, BindingResult result){
    public R add(@RequestBody @Valid EmployeeAddVo vo){
        //把vo转为do;
        Employee employee = new Employee();
        //属性对拷
        BeanUtils.copyProperties(vo,employee);
        employeeService.saveEmp(employee);
        return R.ok();
//        if (!result.hasErrors()) {  //校验通过
//
//        }
//        // 说明校验错误; 拿到所有属性错误的信息
//        Map<String, String> errorsMap = new HashMap<>();
//        for (FieldError fieldError : result.getFieldErrors()) {
//            //1、获取到属性名
//            String field = fieldError.getField();
//            //2、获取到错误信息
//            String message = fieldError.getDefaultMessage();
//            errorsMap.put(field, message);
//        }
//        return R.error(500, "校验失败", errorsMap);

    }

BindingResult result的方式太麻烦了,一但出错,我们还把错误交给全局异常处理器处理。


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        //1、result 中封装了所有错误信息
        BindingResult result = ex.getBindingResult();

        List<FieldError> errors = result.getFieldErrors();// 所有的属性错误
        Map<String, String> map = new HashMap<>();
        for (FieldError error : errors) {
            String field = error.getField();  // 错误字段
            String message = error.getDefaultMessage();   // 错误的默认消息
            map.put(field, message);
        }
        return R.error(500, "参数错误", map);
    }

数据校验:

  • 1、导入校验包
  • 2、JavaBean 编写校验注解
  • 3、使用 @Valid 告诉 SpringMVC 进行校验
  • 效果1: 如果校验不通过,目标方法不执行
  • 4【以后不用】、在 @Valid 参数后面,紧跟一个 BindingResult 参数,封装校验结果
  • 效果2: 全局异常处理机制
  • 5【推荐】:编写一个全局异常处理器,处理 MethodArgumentNotValidException(校验出错的异常),统一返回校验失败的提示消息
  • 6:自定义校验 = 自定义校验注解 + 自定义校验器

自定义校验器

// 校验注解 绑定 校验器
@Documented
@Constraint(validatedBy = {GenderValidator.class})  //校验器去真正完成校验功能。
@Target({ FIELD })
@Retention(RUNTIME)
public @interface Gender {

    String message() default "{jakarta.validation.constraints.NotNull.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };

}

我们上面的Vo中就用了@Gender的自定义校验,
而我们只是标注了一个校验注解,真正的校验还是得交给校验器进行校验。
@Constraint(validatedBy = {GenderValidator.class}) 就是指定我们的校验器
在写一个校验器实现ConstraintValidator接口

public class GenderValidator implements ConstraintValidator<Gender, String> {
    /**
     *
     * @param value 前端提交来的准备让我们进行校验的属性值
     * @param context 校验上下文
     * @return
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {

        return "男".equals(value) || "女".equals(value);
    }
}

错误消息提示

在这里插入图片描述
以前我们直接指定错误的提示,但如果现在的业务场景有变化,要求中文网站返回汉字,英文网站返回英文,怎么实现呢?
所以,我们推荐使用占位符

 @Gender(message = "{gender.message}") //message = "{}" 占位符
    private String gender;

至于gender.message是啥,我们进行配置,
在resource下创建messages.properties
里面写:

gender.message=性别只能为:,jakarta.validation.constraints.Email.message=邮箱错误~~~~

那英文怎么办,copymessages.properties这个文件,并且重命名为:messages_语言_国家区域代码.properties
在这里插入图片描述
一复制idea会自动Bundle在一起
在各自的语言中写各自的提示词

gender.message=Gender must be one of: Male, Female

浏览器修改语言环境,把英语移到顶部,就可以发起英语请求
在这里插入图片描述
请求头中会自己带上语言的
在这里插入图片描述
要是出现陌生国家怎么办,走默认。

但其实是鸡肋,根本不用,国际化不仅仅是修改个语言。想走向其他国家一定是做多个网站。


原文地址:https://blog.csdn.net/shall_zhao/article/details/142549450

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!