统一处理validate
的校验
在开发业务系统的过程中都会设计到一些接口请求参数的校验,之前都是单个接口进行处理,现在介绍一种方法统一处理这个校验。
1、实现
通过继承ResponseEntityExceptionHandler
这个类并实现handleMethodArgumentNotValid
这个方法,就可以统一处理所以经过Valid
注解过的接口,方法中的实现根据业务来,此处我写了一个统一返回类ResponeVo
,主要用这个类和前端进行REST FULL
交互,只要出现校验命中的就会来进入此方法执行,并且携带具体的错误信息;如下的处理逻辑是:返回和前端约定的固定code
,msg
字段用于返回校验时填入的信息,data
中返回请求的值。
package com.demo.validatecommondemo.controller;
import com.alibaba.fastjson.JSON;
import com.demo.validatecommondemo.vo.ResponeVo;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
@RestController
public class ValidateCommonHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status,
WebRequest request) {
ResponeVo vo = new ResponeVo();
vo.setCode("400");
for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
String defaultMessage = fieldError.getDefaultMessage();
vo.setMsg(defaultMessage);
Object value = fieldError.getRejectedValue();
String data = "请求参数值为:"+JSON.toJSONString(value);
vo.setData(data);
break;
}
return new ResponseEntity(vo, HttpStatus.OK);
}
}
2、Controller类书写
如下的接口中addStudent
添加了Valid
注解。
package com.demo.validatecommondemo.controller;
import com.alibaba.fastjson.JSON;
import com.demo.validatecommondemo.entity.Girlfriend;
import com.demo.validatecommondemo.entity.Student;
import com.demo.validatecommondemo.vo.ResponeVo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@RestController
public class DemoController {
@PostMapping(path = "/student")
public ResponeVo<Boolean> addStudent(@RequestBody @Valid Student student){
studentsMap.put(student.getName(),student);
return ResponeVo.create(true);
}
}
解释如下的几个东西,这个类没有写get
和set
方法,因为使用了@Data
注解,更多功能请参考 官网,其他的呢就都是正常的注解,其中idCard
和phone
因为没有官方的注解,所以通过正则表达式来进行匹配,这种方法也是支持的。然后就是backCard
银行卡校验有点问题,感觉规则和中国的不太一样,所以最好是自己用正则去校验。
package com.demo.validatecommondemo.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.hibernate.validator.constraints.CreditCardNumber;
import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.Future;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.util.Date;
import java.util.List;
@Data
public class Student {
@Length(min = 1,message = "姓名不能为空")
@NotNull(message = "姓名不能为空")
private String name;
@NotNull(message = "年龄不能为空")
@Min(value = 18,message = "年龄不能小于18岁")
@Max(value = 56,message = "年龄不能大于56岁")
private Integer age;
@NotNull(message = "邮箱不能为空")
@Email(message = "邮箱地址无效")
private String email;
@NotEmpty(message = "身份证号不能为空")
@Pattern(regexp = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$",message = "请输入正确的身份证号")
private String idCard;
@NotEmpty(message = "手机号码不能为空")
@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "请输入正确的手机号码")
private String phone;
@NotNull(message = "请输入合法的时间")
@Future(message = "请输入合法的时间")
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date inSchoolDate;
@NotNull(message = "请输入正确的银行卡号")
@CreditCardNumber(message = "请输入正确的银行卡号")
private String backCard;
//嵌套校验
@NotEmpty(message = "请填写女朋友信息")
private List<@Valid Girlfriend> girlfriends;
}
package com.demo.validatecommondemo.entity;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Data
public class Girlfriend {
@NotEmpty(message = "请输入姓名")
private String name;
@NotNull(message = "请输入年龄")
@Range(min = 18,max = 24,message = "对不起,年龄不在合适的范围内")
private Integer age;
@NotNull(message = "请输入性别")
@Digits(integer = 1,fraction = 0,message = "只接受女性为女朋友")
private Integer gender;
}
3、请求
请求参数:
{
"name":"l",
"age":18,
"email":"1@qq.com",
"phone":"77777777777",
"idCard":"44444444444444444",
"backCard":"44444",
"inSchoolDate":"2019-10-10 10:10:10",
"girlfriends":[
{}
]
}
响应参数:
{
"code": "400",
"msg": "请输入性别",
"data": "请求参数值为:null"
}
如下说明校验生效了。
支持的校验标签
1、javax.validation 包下
meta-data | comment |
---|---|
AssertFalse | 布尔,为False |
AssertTrue | 布尔,为True |
DecimalMax | 数字,最大为value |
DecimalMin | 数字,最小为value |
Digits | 数字,是否等于某个值 |
邮箱 | |
Future | 是否是未来时间 |
FutureOrPresent | 时间是否是将来或者现在 |
Max | 数字,最大为value |
Min | 数字,最小为value |
Negative | 数字,是否是负数 |
NegativeOrZero | 数字,负数或0 |
NotBlank | 字符串,不为空字符串 |
NotEmpty | 集合,不为空,对于List类型或者是数组类型 |
NotNull | 对象,不为空 |
Null | 对象,为空 |
Past | 日期,过去的日期 |
PastOrPresent | 过去或者现在 |
Pattern | 字符串,正则校验 |
Positive | 数字,正数 |
PositiveOrZero | 数字,正数或0 |
Size | min<=value<=max |
源码
Github
:https://github.com/lengrongfu/validate-common-demo