简介:

  数据验证是作为一个企业级项目架构上设计的最基础的模块,前辈们曾说过:界面上传递到后台的数据没有百分之百值得相信的!为什么这么说呢?往往我们在编写程序的时候都会感觉后台的验证无关紧要,这样就会给别人空子钻。我可以模拟前台发送的请求到后台地址,那么我如果发送一些涉及系统安全的代码到后台,后果一发不可收拾。接下来我们就来讲解下SpringBoot项目内如何对参数进行校验!

本章目标

在SpringBoot项目内完成参数后台数据校验。

SpringBoot的Web组件内部集成了hibernate-validator,所以我们这里并不需要额外的为验证再导入其他的包,接下来我们先来看看SpringBoot为我们提供了哪些验证。

一、项目构建

  使用IntelliJ IDEA工具来构建一个SpringBoot项目,预先导入Web依赖

 

二、使用验证,书写实体类

  我们接下来创建一个实体叫做DemoEntity,实体内添加几个测试字段并对每个字段都做出验证处理

复制代码
public class DemoEntity implements Serializable
{
    @NotBlank
    @Length(min = 2,max = 10)
    private String name;

    @Min(value = 1)
    private int age;

    @NotBlank
    @Email
    private String mail;
    
    //自定义验证,值为1或2或3,其他均不可通过验证
    @FlagValidator(values = "1,2,3")
    private String flag;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getMail() {
        return mail;
    }

    public void setMail(String mail) {
        this.mail = mail;
    }

    public String getFlag() {
        return flag;
    }

    public void setFlag(String flag) {
        this.flag = flag;
    }
}
复制代码

 

三、创建一个名叫IndexController的控制器并通过页面传递参数的形式来校验数据

  我在控制器中注入了一个MessageSource的接口对象,这个对象是用于格式化错误消息的。根据传入的错误字段对象(FieldError)结合hibernate-validator验证的内置错误消息文件进行输出错误消息,hibernate-validator的错误消息支持国际化,所以我们获取错误消息的时候需要传入Locale对象获取本地的国际化类型。hibernate-validator错误消息文件在对应源码包内可以找到
复制代码
@RestController
public class IndexController
{

    @Autowired
    private MessageSource messageSource;

    @RequestMapping(value = "/validator",method = RequestMethod.GET)
    public String validator(@Valid DemoEntity entity, BindingResult result) {
        if(result.hasErrors()) {
            StringBuffer msg = new StringBuffer();
            //获取错误字段集合
            List<FieldError> fieldErrors = result.getFieldErrors();
            //获取本地locale,zh_CN
            Locale currentLocale = LocaleContextHolder.getLocale();
            //遍历错误字段获取错误消息
            for (FieldError fieldError :
                    fieldErrors) {
                //获取错误信息
                String errorMessage = messageSource.getMessage(fieldError,currentLocale);
                //添加到错误消息集合内
                msg.append(fieldError.getField()+":"+errorMessage+" , ");
            }
            return msg.toString();
        }
        return "验证通过," + "\t名称:" + entity.getName()+ "\t年龄:" + entity.getAge() + "\t邮箱地址:"+entity.getMail();
    }
}
复制代码

四、运行测试

 

五、自定义验证

1、自定义验证注解

我们先来创建一个注解,注解内部需要对应验证注解的验证实现类

复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Constraint(validatedBy = FlagValidatorClass.class)
public @interface FlagValidator
{
    //flag的有效值多个使用','隔开
    String values();
    //提示内容
    String message() default "flag不存在";

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

    Class<? extends Payload>[] payload() default {};
}
复制代码

 2、@Constraint注解,里面传入了一个validatedBy的字段,这个就是我们自定义注解的实现类的类型,实现类代码

  自定义验证实现类里面有两个方法,分别是初始化验证消息、执行验证。

  初始化验证消息方法内你可以得到配置的注解内容,而验证方法则是你的验证业务逻辑。

复制代码
public class FlagValidatorClass implements ConstraintValidator<FlagValidator, Object> {

    //临时变量保存flag值列表
    private String values;

    //初始化values的值
    @Override
    public void initialize(FlagValidator flagValidator) {
        //将注解内配置的值赋值给临时变量
        this.values = flagValidator.values();
    }

    //实现验证
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext)
    {
        //分割定义的有效值
        String[] value_array = values.split(",");
        boolean isFlag = false;
        //遍历比对有效值
        for (int i =0;i<value_array.length;i++)
        {
            //存在一致跳出循环,赋值isFlag=true
            if(value_array[i].equals(value))
            {
                isFlag = true;
                break;
            }
        }
        //返回是否存在boolean
        return isFlag;
    }
}
复制代码

测试: