数据校验不建议放在 Controller 层或是 Service 层中做,而是建议放在 POJO 中,可以利用 Java Bean Validation 标准提供的一系列注解去做,配合 @Valid` 和
@Validation` 使用。
业务相关的数据校验也应该交给 Bean Validation,可以通过自定义注解的方式来实现,将业务校验逻辑与业务处理逻辑分离,并防止各层重复校验、或者分别校验一部分的情况出现。
/**
* 表示一个用户的信息是无冲突的
*
* “无冲突”是指该用户的敏感信息与其他用户不重合,譬如将一个注册用户的邮箱,修改成与另外一个已存在的注册用户一致的值,这便是冲突
**/
@Documented
@Retention(RUNTIME)
@Target({FIELD, METHOD, PARAMETER, TYPE})
@Constraint(validatedBy = AccountValidation.NotConflictAccountValidator.class)
public @interface NotConflictAccount {
String message() default "用户名称、邮箱、手机号码与现存用户产生重复";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
pubcli class NotConflictAccountValidator implements
ConstraintValidator<NotConflictAccount, String> {
@Override
public void initialize(NotConflictAccount constraintAnnotation) {
}
@Override
public boolean isValid(Account c,
ConstraintValidatorContext constraintValidatorContext) {
Collection<Account> collection =
repository.findByUsernameOrEmailOrTelephone(
c.getUsername(), c.getEmail(), c.getTelephone());
// 将用户名、邮件、电话改成与现有完全不重复的,或者只与自己重复的,就不算冲突
return collection.isEmpty() || (collection.size() == 1 && collection.iterator().next().getId().equals(c.getId()));
}
}
建议将不带业务含义的格式校验注解放到 Bean 的类定义里面(类的成员变量上),把带业务逻辑的校验放到类定义的外面(像是 @NotConflictAccount Account account
)。防止业务校验的执行频率过高,影响性能。