springboot 数据验证( JSR-303 & 自定义验证器 )

在日常工作中,往往需要验证参数的合法性,因此,springMVC提供了验证参数的机制,一方面,他可以支持JSR-303注解验证;另一方面,因为业务的复杂性,需要自定义验证规则,本篇来探讨相关问题。立志工具人。一起干饭!


本章主要内容

  • JSR-303 验证

  • SpringMVC参数验证机制


1.JSR-303验证

JSR 303: Bean Validation官方文档

JSR-303验证主要是通过注解的方式进行的。

  • 引入相关依赖
        
            org.springframework.boot
            spring-boot-starter-validation
        
  • 给参数对象添加校验注解
@Data
public class User {
    
    private Integer id;
    @NotBlank(message = "用户名不能为空")
    private String username;
    @Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$", message = "密码必须为8~16个字母和数字组合")
    private String password;
    @Email
    private String email;
    private Integer gender;

}
  • Controller 中需要校验的参数Bean前添加 @Valid 开启校验功能
@RestController
@RequestMapping("/user")
public class UserController {

    @PostMapping("")
    public Result save (@Valid User user , BindingResult bindingResult)  {
        if (bindingResult.hasErrors()) {
            Map map = new HashMap<>();
            bindingResult.getFieldErrors().forEach( (item) -> {
                String message = item.getDefaultMessage();
                String field = item.getField();
                map.put( field , message );
            } );
            return Result.build( 400 , "非法参数 !" , map);
        }
        return Result.ok();
    }

}

  • 规范内嵌的约束注解
规范内嵌的约束注解
  • 规范内嵌的约束注解
Constraint 详细信息
@Email 被注释的元素必须是电子邮箱地址
@Length 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range 被注释的元素必须在合适的范围内

2.SpringMVC参数验证机制

  • SpringMVC中 的Validator (验证器)
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.validation;

public interface Validator {
    boolean supports(Class var1);

    void validate(Object var1, Errors var2);
}

spring定义验证器接口,它定义了两个方法,其中supports方法参数为需要验证的POJO类型,如果该方法返回true,则Spring会使用当前验证其的validation方法去验证POJO,而validation方法包含需要的target对象和错误对象errors,其中target是参数绑定后的POJO,这样便可以通过这个参数对象进行业务逻辑的自定义验证。如果发现错误,则可以保存到errors对象中,然后返回给控制器。

  • 自定义用户验证器
package com.dylan.mall.validation;

import com.dylan.mall.component.Student;
import com.dylan.mall.component.User;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

/**
 * @author Administrator
 */
public class UserValidator implements Validator {
    //验证器只支持User

    @Override
    public boolean supports(Class clazz) {
        return clazz.equals(User.class);
    }

    /**
     * 逻辑验证
     */
    @Override
    public void validate(Object target, Errors errors) {
        if (target == null) {
            errors.rejectValue("", null, "用户不能为空");
            return;
        }
        //强制转换
        User user = (User) target;
        //用户名非空串
        if (StringUtils.isEmpty(user.getUserName())) {
            //增加错误,可以进入控制器方法
            errors.rejectValue("userName", null, "用户名不能为空");
        }
    }
}

有了验证器,需要spring对象自动启动它。在springMVC中提供了一个注解@InitBinder,他的作用是在执行控制器方法前,处理器会先执行标@InitBinder标注的方法。这时将WebDataBinder对象作为参数传递到方法中,通过这层关系得到WebDataBinder对象,这个对象有一个setValidator方法,它可以绑定自定义验证器,这样就可以在获取参数之后,通过自定义的验证器去验证参数。

package com.dylan.mall.controller;

import com.dylan.mall.component.User;
import com.dylan.mall.validation.UserValidator;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Administrator
 */
@Controller
@RequestMapping("/user")
public class UserController {
    /**
     * 调用控制器前先执行这个方法
     */
    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        //绑定验证器
        webDataBinder.setValidator(new UserValidator());
        //定义日期参数格式,参数不在需注解@DateTimeFormat,boolean参数表示是否允许为空
        webDataBinder.registerCustomEditor(Date.class,
                new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false)
        );
    }

    @GetMapping("/validator")
    @ResponseBody
    public Map validator(@Valid User user, Errors errors,Date date) {
        Map map = new HashMap<>();
        map.put("user", user);
        map.put("date", date);
        if (errors.hasErrors()) {
            List oes= errors.getAllErrors();
            for (ObjectError oe : oes) {
                if (oe instanceof FieldError) {
                    FieldError fe = (FieldError) oe;
                    map.put(fe.getField(), fe.getDefaultMessage());
                } else {
                    map.put(oe.getObjectName(), oe.getDefaultMessage());
                }
            }
        }
        return map;
    }

}

user类

package com.dylan.mall.component;

import lombok.Data;

/**
 * @author Administrator
 */
@Data
public class User {
    private String userName;
    private Integer age;
}

输出结果:

自定义校验结果

通过这样的自定义,在使用注解@Valid标注User参数后,SpringMVC就会去遍历对应的验证器,当遍历到UserValidator时,会去执行它的supports方法。因为该方法返回true,所以SpringMVC会用这个验证器去验证User类的数据。


不要以为每天把功能完成了就行了,这种思想是要不得的,互勉~!

若文章对您有用,请点赞支持哦。

你可能感兴趣的:(springboot 数据验证( JSR-303 & 自定义验证器 ))