前言
大多数项目中都需要后台对传过来的对象进行校验,比如手机号的位数,特殊字段不能为空等等。之前我们可能都是使用if…else…,今天我们了解一下validated
正文
单个对象
想要使用validated需要引入Jar包,有两个方式,选择一种即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.5.Final</version>
</dependency>
对于单个对象我们可以直接使用注解,在方法中使用案例:
/**
* 修改方法
* @param students 学生类(需要校验的对象)
* @param result 检验返回的结果信息
* @return
*/
@PutMapping()
public String updateStudent(@RequestBody @Validated Student students, BindingResult result){
/**
* 查看校验结果,统计保存信息
*/
Set<String> errors = new HashSet<>();
// 如果 BindingResult 的 hasErrors 方法返回true,则表示有错误信息
if (result.hasErrors()) {
List<ObjectError> allErrors = result.getAllErrors();
// 遍历错误信息,返回给前端
for (ObjectError error : allErrors) {
errors.add(error.getDefaultMessage());
}
}
if(errors.size() == 0){
try {
studentService.updateByPrimaryKeySelective(students);
return "更新成功";
} catch (Exception e) {
e.printStackTrace();
return "更新失败";
}
}else {
return errors.toString();
}
}
实体中写上校验规则,基本的校验规则都有,大家可以自行Google一下,这里就不介绍了
@NotEmpty(message = "ID不能为空")
private Integer id;
@Size(min = 5,max = 10,message = "名称需要在5到10个字符之间")
private String name;
然后通过postman验证数据,可以跑出来我们想要的结果:
一组对象
我直接在接收参数把Student装到了List中,结果发现没有校验直接过了,看来这个方式不对。
public String updateStudent(@RequestBody @Validated List<Student> students, BindingResult result)
然后Google了一下,有文章说在Controller添加@Validated,在方法上添加@Valid,然后我运行发现报错,但是报错的内容里有我想要的信息,我就想到定义一个全局抛错类,抓住javax.validation.ConstraintViolationException 错误,把错误解析,拿出想要的信息,结果发现这个报错抓不住,这个方式也没走通。
@Validated
@CrossOrigin
@RestController
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
/**
* 修改方法
* @param students 学生类(需要校验的对象)
* @param result 检验返回的结果信息
* @return
*/
@PutMapping()
public String updateStudent(@RequestBody @Valid List<Student> students, BindingResult result){
/**
* 查看校验结果,统计保存信息
*/
Set<String> errors = new HashSet<>();
// 如果 BindingResult 的 hasErrors 方法返回true,则表示有错误信息
if (result.hasErrors()) {
List<ObjectError> allErrors = result.getAllErrors();
// 遍历错误信息,返回给前端
for (ObjectError error : allErrors) {
errors.add(error.getDefaultMessage());
}
}
if(errors.size() == 0){
try {
studentService.updateByPrimaryKeySelective(students.get(0));
return "更新成功";
} catch (Exception e) {
e.printStackTrace();
return "更新失败";
}
}else {
return errors.toString();
}
}
}
再一次进行Google,查看了一下@Validated和@Valid的区别,发现@Validated用在方法入参上无法单独提供嵌套验证功能,但是单个对象是可以的,那我可以把List继承一下,写成一个对象。然后再调用的时候,还是和单个对象一样。这次得到了想要的结果,由于报错信息可能重复的太多,所以用Set接收的错误信息。
public class ValidList<E> implements List<E> {
@Valid
private List<E> list = new LinkedList<>();
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(E e) {
return list.add(e);
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
@Override
public void clear() {
list.clear();
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public E set(int index, E element) {
return list.set(index, element);
}
@Override
public void add(int index, E element) {
list.add(index, element);
}
@Override
public E remove(int index) {
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
return list.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
return list.listIterator(index);
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
public List<E> getList() {
return list;
}
public void setList(List<E> list) {
this.list = list;
}
}
@CrossOrigin
@RestController
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
/**
* 修改方法
* @param students 学生类(需要校验的对象)
* @param result 检验返回的结果信息
* @return
*/
@PutMapping()
public String updateStudent(@RequestBody @Validated ValidList<Student> students, BindingResult result){
/**
* 查看校验结果,统计保存信息
*/
Set<String> errors = new HashSet<>();
// 如果 BindingResult 的 hasErrors 方法返回true,则表示有错误信息
if (result.hasErrors()) {
List<ObjectError> allErrors = result.getAllErrors();
// 遍历错误信息,返回给前端
for (ObjectError error : allErrors) {
errors.add(error.getDefaultMessage());
}
}
if(errors.size() == 0){
try {
studentService.updateByPrimaryKeySelective(students.get(0));
return "更新成功";
} catch (Exception e) {
e.printStackTrace();
return "更新失败";
}
}else {
return errors.toString();
}
}
}
结束
感觉写代码就是一步一步的尝试,错了就换一种是方式。
抓住自己有兴趣的东西,由浅入深,循序渐进地学。