使用Hibernate JSP 303 整合到SSM项目
小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
之前临时踩坑遇到注解校验的问题,为了避免长篇大论,这里挑了核心的部分介绍如何快速的集成注解校验。
需求:
- 在项目中加入注解校验
- 可以控制错误的操作
- 对于参数错误进行全局日志记录,方便后续查看
ValidataUtils
此工具类配置可以大大减少配置
@Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
下面是具体的工具类,当然不一定需要使用ApplicationContextAware进行校验替换,也可以直接作为一个validater的工具使用,但是建议使用bean的形式而不是使用静态方法。
@Component
public class ValidatorUtils implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ValidatorUtils.validator = (Validator) applicationContext.getBean("validator");
}
private static Validator validator;
public static Optional<String> validateResultProcess(Object obj) {
Set<ConstraintViolation<Object>> results = validator.validate(obj);
if (CollectionUtils.isEmpty(results)) {
return Optional.empty();
}
StringBuilder sb = new StringBuilder();
for (Iterator<ConstraintViolation<Object>> iterator = results.iterator(); iterator.hasNext(); ) {
sb.append(iterator.next().getMessage());
if (iterator.hasNext()) {
sb.append(" ,");
}
}
return Optional.of(sb.toString());
}
}
解决思路:
第一种:使用@Valid 加上 BindResult
注意事项:@valid 加入的DTO后面必须跟上 BindResult,@valid 加入的DTO后面必须跟上 BindResult,重要的事情说3遍,并且@valid 加入的DTO对象后面必须跟上 BindResult,如果不按此规则,将会由Spring的 bindException 直接抛出异常
第二种:使用切面的方式统一处理异常
@Aspect
@Component
public class ControllerValidatorInterceptor {
/**
* 设置 around 环绕通知切面
*/
@Around("execution(* com.aerexu.web.*.*(..)) && args(..,bindingResult)")
public Object doAround(ProceedingJoinPoint pjp, BindingResult bindingResult) throws Throwable {
Object retVal;
if (bindingResult.hasErrors()) {
retVal = doErrorHandle();
} else {
retVal = pjp.proceed();
}
return retVal;
}
}
第三种:使用validateUtil进行完全的手动校验
下面是对于工具类进行改动之后的代码:
public class ValidatorUtil {
/**
* 注意使用了快速失败的机制
*/
private static Validator validator =
Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(false)
.buildValidatorFactory()
.getValidator();
public static Validator getValidator() {
return validator;
}
/**
* 校验对象
*
* @param object
* @param groups
* @param <T>
*/
public static <T> void validate(T object, Class<?>... groups) {
Set<ConstraintViolation<T>> constraintViolationSet = validator.validate(object, groups);
if (!constraintViolationSet.isEmpty()) {
throw new ConstraintViolationException(constraintViolationSet);
}
}
// /**
// * 校验集合bean内容是否符合校验规则
// *
// * @param apiObj 接口传输对象
// * @return
// */
// public static ZmtResult validListBean(List<Object> apiObj) {
// if (CollectionUtils.isEmpty(apiObj)) {
// return ZmtResult.build(401, "请求参数为空");
// }
// StringBuilder builder = new StringBuilder();
// for (int i = 0; i < apiObj.size(); i++) {
// Object apiPaymentMsgDto = apiObj.get(i);
// if (null == apiPaymentMsgDto) {
// return ZmtResult.build(400, "第 %s 条信息请求参数为空", i);
// }
// Validator validator = ValidatorUtil.getValidator();
// Set<ConstraintViolation<Object>> validate = validator.validate(apiPaymentMsgDto);
// // 如果不存在校验异常,则返回空信息
// if (org.apache.commons.collections.CollectionUtils.isEmpty(validate)) {
// continue;
// }
// builder.append(String.format("第 %s 条信息:", i + 1));
// for (ConstraintViolation<Object> apiPaymentMsgDtoConstraintViolation : validate) {
// builder.append(apiPaymentMsgDtoConstraintViolation.getMessage());
// builder.append(",");
// }
// builder.deleteCharAt(builder.length() - 1);
// builder.append("|");
// }
// // 如果存在错误信息,返回错误提示,否则返回空对象证明没有异常
// if (builder.length() > 0) {
// builder.deleteCharAt(builder.length() - 1);
// return ZmtResult.build(401, builder.toString());
// } else {
// return null;
// }
//
// }
// /**
// * 处理validate异常信息
// *
// * @param bindResult 错误绑定对象
// * @return
// */
// public static ZmtResult dealWithError(BindingResult bindResult) {
// if (bindResult.hasErrors()) {
// List<FieldError> fieldErrors = bindResult.getFieldErrors();
// for (FieldError allError : fieldErrors) {
// String defaultMessage = allError.getDefaultMessage();
// return ZmtResult.build(400, defaultMessage);
// }
// }
// return null;
// }
}
实用bindResult 到最佳实践
真的写的十分好,这里分享出来
常用注解
下面列举的都是常用的注解,但是并不是最常用的
- @Null 被注释的元素必须为null
- @NotNull 被注释的元素不能为null
- @AssertTrue 被注释的元素必须为true
- @AssertFalse 被注释的元素必须为false
- @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
- @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
- @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
- @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
- @Size(max,min) 被注释的元素的大小必须在指定的范围内。
- @Digits(integer,fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
- @Past 被注释的元素必须是一个过去的日期
- @Future 被注释的元素必须是一个将来的日期
- @Pattern(value) 被注释的元素必须符合指定的正则表达式。
- @Email 被注释的元素必须是电子邮件地址
- @Length 被注释的字符串的大小必须在指定的范围内
- @NotEmpty 被注释的字符串必须非空
- @Range 被注释的元素必须在合适的范围内
参考资料
使用Hibernate JSP 303 整合到项目
juejin.im/post/5d3fbe… - 这么写参数校验(validator)就不会被劝退了~