1. 需求/目的
- 减少代码量,提高model约束条件的可维护性
2.使用环境
- 同之前笔记,没有额外引入
3.思路
- 在model定义约束条件
- 依据约束条件进行判断
- 获取判断结果
- 处理判断结果
4.定义约束条件
注解 | 作用 |
---|---|
@Valid | 被注释的元素是一个对象,需要检查此对象的所有字段值 |
@Null | 被注释的元素必须为 null |
@NotNull | 被注释的元素必须不为 null( 任何对象的value不能为null) |
@AssertTrue | 被注释的元素必须为 true |
@AssertFalse | 被注释的元素必须为 false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 |
@Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
- Hibernate Validator 附加的 constraint
注解 | 作用 |
---|---|
被注释的元素必须是电子邮箱地址 | |
@Length(min=, max=) | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串的必须非空(可以用于集合对象的元素不为0,即集合不为空) |
@Range(min=, max=) | 被注释的元素必须在合适的范围内 |
@NotBlank | 被注释的字符串的必须非空(字符串trim()以后length要大于0) |
-
以上是一些可用的约束注解.参考:https://blog.csdn.net/danielzhou888/article/details/74740817
-
使用示例:
@Entity
@Table(name = "base_user") //基本用户表
public class BaseUser extends AbstractModel implements Serializable {
//主键
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
// @Column(name = "id", unique = true, nullable = false, length = 20)
private Integer id;
//用户名
@NotBlank(message = "用户名不能为空")
@Length(max = 16,message = "用户名长度不能超过{max}位")
@Column(name = "username", length = 64)
private String username;
//密码
@NotBlank(message = "密码不能为空")
@Column(name = "password", length = 128)
private String password;
//性别
@Column(name = "sex_id", length = 32)
private Integer sex_id;
//邮箱
@Email(message = "邮箱不符合规范")
@Column(name = "email", length = 64)
private String email;
//手机号
@Column(name = "phone", length = 32)
private String phone;
//备注
@Length(max = 500,message = "备注长度不能超过{max}位")
@Column(name = "remark", length = 512)
private String remark;
//状态
@Column(name = "status_id", length = 32)
private Integer status_id;
...略...
}
- 约束条件也可以标注在属性的get方法上,但是显然,标注在属性上更方便些
- 注解的message可不填,Hibernate有默认的提示文本
4.设计一个工具类,进行约束的判断与处理
/**
* 提供使用Hibernate注解进行model的约束,获取约束验证的返回值
* @time 2019年4月25日15:13:24
* @author author
*/
@Component
public class HibernateValidatorUtils {
private static Validator validator;
//注解PostConstruct用于在项目启动的时候执行该方法
@PostConstruct
public synchronized void init() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
public static Validator getValidator() {
return validator;
}
public static void validate(Object obj)throws MsgException {
//依据约束条件进行判断,获取判断结果
Set<ConstraintViolation<Object>> s = validator.validate(obj, new Class[0]);
//处理判断结果
if (s != null && !s.isEmpty()) {
//throw new ConstraintViolationException(s);
throw Assert.ThrowByViolationResult(s);
}
}
}
- init方法会在spring boot 启动时获取一个validator对象,用于执行约束判断
- validate方法用来接收一个model,并进行相关处理
- validation包有提供相关的ConstraintViolationException异常类,可以直接使用约束的判断结果创建一个异常,用于抛出.
- 但ConstraintViolationException异常无法方便的提供所有约束的判断信息,因此这里我进行自定义处理
/**
* 通过hibernate的model验证结果集,创建异常对象
* @param constraintViolations hibernate的model验证结果集
* @return 创建的异常
* @time 2019年4月23日11:36:51
* @author authstr
*/
public static MsgException ThrowByViolationResult(Set<? extends ConstraintViolation<?>> constraintViolations){
//记录异常信息
String message="";
//用于存储所有的错误信息
List<Map<String,String>> allError=new ArrayList<Map<String,String>>();
int index=0;
//遍历set
for(ConstraintViolation con:constraintViolations){
//将第一个验证结果作为异常的message
if(index==0){
message=con.getMessage();
}
index++;
//记录其他异常信息
Map<String,String> errInfo=new HashMap<String,String>();
errInfo.put("message",con.getMessage());
errInfo.put("value",String.valueOf(con.getInvalidValue()));
errInfo.put("propertyPath",String.valueOf(con.getPropertyPath()));
allError.add(errInfo);
}
return new MsgException(BasicException.DEFAULT_CODE,message,allError);
}
- Assert和MsgException类在之前有说明.
- Set里包含了没通过判断的相关约束信息
- 该方法进行的处理是:
将第一个没有通过判断的约束的message作为MsgException异常对象的message
每个没通过判断的约束信息转换为Map,将Map集合作为MsgException异常对象的data
5.调用约束判断
- 约束的判断放在了数据库操作的上一步,也就是AbstractDao类的sava方法和update方法
- 有时,也会有不需要进行约束判断的需求,因此对原有的方法进行了一些修改
- 这里抛出的异常最终会被AbstractController类处理
/**
* 保存一个entity
* @param entity 要保存的model
* @return 主键值
*/
@Override
public Serializable save(Object entity) {
return save(entity,true);
}
/**
* 保存一个entity
* @param entity 要保存的model
* @param isValidation 是否验证model
* @return 主键值
*/
@Override
public Serializable save(Object entity, Boolean isValidation) {
// model验证
if(isValidation){
HibernateValidatorUtils.validate(entity);
}
return this.getSession().save(entity);
}
/**
* 更新一个entity
* @param entity 要更新的model
* @time 2018年9月25日16:15:25
* @author authstr
*/
@Override
public void update(Object entity) {
update(entity,true);
}
/**
* 更新一个entity
* @param entity 要更新的model
* @param isValidation 是否验证model
* @return 主键值
*/
@Override
public void update(Object entity, Boolean isValidation) {
// model验证
if(isValidation){
HibernateValidatorUtils.validate(entity);
}
this.getSession().update(entity);
}
7.实际使用
![](https://img.haomeiwen.com/i7769347/4fdd3a0b86781af0.png)
-
在不进行任何输入的情况下,进行保存,出现错误提示
错误提示
-
请求返回数据还包含其他错误信息,前端可以根据实际情况选择将多个错误信息显示到表单上
返回值
8.创建自定义约束
- java和Hibernate提供的约束注解不一定能满足全部需要,这时可以自行创建新的约束注解
- 约束注解很方便,但是不够强大(自定义也不够方便),过于复杂的约束还需在Service层进行定义.
- 以身份证验证自定义约束注解为例:
- 第一步:创建注解类
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
@Constraint(validatedBy = IDCardValidated.class)
@Target({METHOD,FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IDCard {
String message() default "身份证号码不符合规范";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- Target,Retention,Documented都是元注解,这里不做说明,可参考:自定义注解入门
- Constraint注解用来与注解的执行类进行关联
- IDCard 注解执行类
import com.authstr.ff.utils.base.StringUtils;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@Component
public class IDCardValidated implements ConstraintValidator<IDCard,String> {
public void initialize(IDCard constraintAnnotation) { }
public boolean isValid(String s, ConstraintValidatorContext context) {
if(StringUtils.notText(s)){
return false;
}
return IDCardUtil.verify(s);
}
}
- IDCardUtil是进行身份证号码验证的一个工具类,在其他笔记有说明.
- 之后,就可以在model中进行使用.通过注解约束model作用有限,这里不做深入探究
- 参考:Hibernate validator官方文档
网友评论