小强哥博客

小强哥,小强哥博客,技术大咖

pacaya项目之Hibernate Validate使用

我来接着记录我目前正在开发的pacaya项目~

目前的项目采用的是前后端分离开发模式,前端使用vue开发,后端使用springboot开发,前后端分离,这也是业界共同认可的开发方式。

这种开发方式下就需后端提供http接口供前端获得、提交数据,在这个过程中就需要后端将接口做的够严谨、粒度够细、安全性够高。

这里涉及到的一个问题就是后端需要对发送过来的数据进行合法性校验。

什么是‘合法性校验’,我举个例子,好比我们需要保存用户姓名以及用户年龄,用户名字是字符串,用户年龄是数字,如果前端按照我们的要求来提交数据那是没有问题的,比如前端提交‘张三,18’这中数据,但是如果前端不按照我们的要求提交数据,比前端提交‘张三,18x’,这种数据后端肯定是保存不进去的,这类数据我们称为非法数据。

可能有人会想到可以在前端来通过js来校验,这一点不错,js是可以来校验出来,并且很强大、效果也好,但是对于懂技术的人来说他是可以绕过你的js的,直接向你的后端接口发起请求提交,这时候js校验就不起作用了,所有,我们还是得需要在后端再次做一次校验,最好是前端做后端也做。

如何在后端来实现校验,可以通过自己编写校验代码来实现,也可以通过现有的框架来实。

我这里重点推荐使用hibernate validate框架来实现校验,如下http://xiaoqiangge.com/aritcle/1541060785534.html。 这篇文章整理了hibernate validate的常用注解 ,可以看看,不多说。

现在我们开发项目都是使用springboot来进行开发,那么如何在springboot中使用hibernate validate?也很简单,直接百度了,这很多很多,我就不写了。

我这里重点说下我在使用hibernate validate中遇到的几个问题。

第一个问题,在springboot(SpringMVC)中如何正确的使用hibernate validate?

如果你通过在百度搜过‘springboot validate’你将会看到一堆博客介绍使用类似如下这种配置的方式(关于springboot的基础知识可以自行百度),

public class ValidBean {
    @NotNull(message = "名字不能为空")
    private String name;
 
    @Min(value = 18, message = "年龄必须大于18")
    private int age;
 
    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;
    }
}
@RequestMapping("bean")
    @ResponseBody
    public String say(@Valid ValidBean bean, BindingResult bindingResult){        
        return bindingResult.hasErrors() ? 
		bindingResult.getFieldError().getDefaultMessage() : "incorrect";
    }

以上代码转载 https://blog.csdn.net/adsadadaddadasda/article/details/80831832 。

几乎好多文章都是类似上面的这种配置,首先配置一个bean,然后在bean上加上相应的validate注解,然后在配置controller中的方法中配置一个@valid和一个BindingResult,这是一种解决方案,但是不是最好的解决方案,因为你需要在每个controller中的方法中都得加上一个BindingResult,这显得太多余了。

那么有没有更好的方式能让我不加BindingResult嘛?答案是有的,非常简单,只需要将上面的代码改成如下,bean中的内容不做修改,

@RequestMapping("bean")
    @ResponseBody
    public String say(@Validate ValidBean bean){        
        省略。。。
    }

只是将@Valid换成了@Validate,并且去掉了BindingResult代码顿时感觉舒服了许多,并且当检测到非法数据的时候,会触发异常MethodArgumentNotValidException,可以通过使用spring全局异常(springboot全局异常可以百度,网上很多)解决方案来捕获该异常然后返回给客户端。

第二个问题,如何校验对象中的子对象?

所谓的子对象就是对象嵌套如下,

public class Apple {
    @NotBlank(message = "apple name required")
    String name;
    Fruid fruid;
}
public class Fruid {
    @NotBlank(message = "fruid name required")
    String name;
}

上面代码的意思是apple.name不能为空并且fruid.name也不能为空。

@RequestMapping("bean")
    @ResponseBody
    public String say(@Validate Apple apple){        
        省略。。。
    }

如果使用下面代码来进行校验是不能校验到fruid.name的,那么有无解决方法?答案是有的,只需要将上面的对象嵌套做略微调整如下,

public class Apple {
    @NotBlank(message = "apple name required")
    String name;
    @Valid
    Fruid fruid;
}
public class Fruid {
    @NotBlank(message = "fruid name required")
    String name;
}

在fruid对象上增加@Valid注解,这样就完美解决。同样的,他校验出错误以后也是通过在全局异常中捕获valid抛出的异常处理,然后告诉前端。

完。