文章目录
1、什么是validator?
在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码有三个麻烦:
验证代码繁琐,重复劳动
方法内代码显得冗长
每次要看哪些参数验证是否完整,需要去翻阅验证逻辑代码
Hibernate Validator就用于解决这种问题,他是一种参数校验的框架, Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。
2、准备工作
(1) Springboot项目中,它被集成在web包里
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
(2) 编写校验结果存储类(存储错误信息)
import org.apache.tomcat.util.buf.StringUtils;
import java.util.HashMap;
import java.util.Map;
public class ValidationResult {
private boolean hasErrors;
private Map<String,String> errorMsgMap = new HashMap<>();
public boolean isHasErrors() {
return hasErrors;
}
public void setHasErrors(boolean hasErrors) {
this.hasErrors = hasErrors;
}
public Map<String, String> getErrorMsgMap() {
return errorMsgMap;
}
public void setErrorMsgMap(Map<String, String> errorMsgMap) {
this.errorMsgMap = errorMsgMap;
}
//通过字符串信息获取错误结果的msg方法
public String getErrMsg(){
return errorMsgMap.toString();
}
}
(3) 编写ValidatorImpl实现类,实现错误检查,并且将错误结果存储在ValidationResult
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
@Component
public class ValidatorImpl implements InitializingBean {
private Validator validator;
public ValidationResult validate(Object bean){
ValidationResult validationResult = new ValidationResult();
Set<ConstraintViolation<Object>> constraintViolationSet = validator.validate(bean);
if(constraintViolationSet.size() > 0){
//大于0说明有错误
validationResult.setHasErrors(true);
constraintViolationSet.forEach(constraintViolation->{
String errMsg = constraintViolation.getMessage();
String propertyName = constraintViolation.getPropertyPath().toString();
validationResult.getErrorMsgMap().put(propertyName,errMsg);
});
}
return validationResult;
}
@Override
public void afterPropertiesSet() throws Exception {
//将validator通过工厂的初始化方式使其实例化
this.validator = Validation.buildDefaultValidatorFactory().getValidator();
}
}
(4) 实体类,注意其中部分属性上的注解
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
/**
* dictionaryDTO
*
* @Date: 2019/8/13
* @Version: 1.0
* @Maintenance Records:
*/
public class DictionaryVO implements Serializable {
private static final long serialVersionUID = 6193674149029494679L;
/**
* 字典id
*/
@Id
@JsonSerialize(using = ToStringSerializer.class)
private Long dictionaryId;
/**
* 字典名
*/
@NotNull(message = "字典名不能为空!")
private String name;
/**
* 字典类型
*/
@NotNull(message = "字典类型不能为空!")
private String category;
/**
* 字典值
*/
@NotNull(message = "字典值不能为空!")
private String value;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 备注
*/
private String remark;
/**
* 状态
*/
@Max(1)
@Min(0)
private Integer status;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Date getUpdatedTime() {
return updatedTime;
}
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Long getDictionaryId() {
return dictionaryId;
}
public void setDictionaryId(Long dictionaryId) {
this.dictionaryId = dictionaryId;
}
@Override
public String toString() {
return "DictionaryVO{" +
"dictionaryId=" + dictionaryId +
", name='" + name + '\'' +
", category='" + category + '\'' +
", value='" + value + '\'' +
", updatedTime=" + updatedTime +
", remark='" + remark + '\'' +
", status=" + status +
'}';
}
}
(5) !在Springboot启动器上加上扫描我们validator包的注解,使其能够找到我们的validator实现类
@EnableAspectJAutoProxy
@SpringBootApplication(scanBasePackages ={"utils.validator"})
@MapperScan(basePackages ="com.bosssoft.bes.basedata.center.dao")
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
(6) Controller上的方法,其余代码就不贴出来了,看看主要方法部分
/**
* 数据字典添加
*
* @param commonRequest
* @return: protocol.CommonResponse
*/
@Override
@RequestMapping(value = "add",method = RequestMethod.POST)
public CommonResponse add(@RequestBody CommonRequest commonRequest) {
//用fastJson将前端传回来的Json转成我们要的对象,注意下面的方法是自定义的工具,读者可以自行百度方法
DictionaryVO dictionaryVO = (DictionaryVO) Converter.getObjectFromJson(JSON.toJSONString(commonRequest.getBody()),DictionaryVO.class);
//采用validator验证
ValidationResult result = validator.validate(dictionaryVO);
if(result.isHasErrors()){
//这里面存的就是错误信息,本来应该抛异常,这里直接返回给前端信息
result.getErrMsg();
return CommonResponse.create("1","1","1",false,result.getErrMsg());
}
dictionaryService.add(dictionaryVO);
return CommonResponse.create("1","2","3",false,"添加成功!");
}
3、简单用PostMan测试下
{
"head": {
"version": "1",
"token": "1",
"businessType": "1",
"deviceId": "1",
"deviceType": "0",
"encrypt": "false"
},
"body": {
"data": {
"dictionaryId": "8",
"name": "8",
"category": "8",
"value": "8",
"remark": "8",
"status": "7",
"createdBy": "11",
"createdTime": "2019-08-15 18:21:24",
"updatedBy": "11",
"updatedTime": "2019-08-15 18:21:24",
"version": "2"
}
}
}
4、测试
可以看到,我们的控制器检验了代码并返回了我们所需要错误信息
5、小结
通过上述使用Validator进行参数校验的实例,可以看出它减少了我们平常繁琐且重复的校验过程,极大降低后端参数校验代码的冗余度~