参数校验工具之Validator自定义校验

编程

validator百度博客一大堆,本文是摘取的部分内容结合在项目中使用的经验.

一.导入maven依赖

    <dependency> 

<groupId>javax.validation</groupId>

<artifactId>validation-api</artifactId>

<version>1.1.0.Final</version>

</dependency>

<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate-validator</artifactId>

<version>5.2.0.Final</version>

</dependency>

二.给需要校验的pojo加上注解

@Data

public class InformationBasicInfoAO {

/**

* 主键id

*/

private Long id;

/**

* 文章标题

*/

@NotBlank(message = "文章标题不能为空")

private String title;

/**

* 发布日期

*/

@NotNull(message = "发布时间不能为空")

private Date releaseDate;

/**

* 文章来源

*/

@NotBlank(message = "文章来源不能为空")

private String source;

message的内容是返回给前端的提醒信息,可以不填

三.校验

1.通用的校验工具

@Slf4j

public class ValidatorUtil {

//也可以使用spring注入的方式

private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

/**

* 使用指定分组

*

* @param object 被校验的bean

* @param groups 分组

* @return

*/

public static <T> Map<String, StringBuilder> validate(T object, Class<?>... groups) {

Map<String, StringBuilder> errorMap = new HashMap<>(16);

if (groups == null) {

groups = new Class[]{Default.class};

}

Set<ConstraintViolation<T>> set = validator.validate(object, groups);

if (CollectionUtils.isEmpty(set)) {

return null;

}

String property;

for (ConstraintViolation<T> c : set) {

// 这里循环获取错误信息,可以自定义格式

property = c.getPropertyPath().toString();

if (errorMap.get(property) != null) {

errorMap.get(property).append(",").append(c.getMessage());

} else {

StringBuilder sb = new StringBuilder();

sb.append(c.getMessage());

errorMap.put(property, sb);

}

}

return errorMap;

}

}

2.使用工具校验

这种方式直接抛去异常,全局异常处理

        Map<String, StringBuilder> errorMap = ValidatorUtil.validate(object);

if (!CollectionUtils.isEmpty(errorMap)) {

log.info("------参数校验失败:{}", errorMap);

throw new ApplicationException(new ExceptionContext("参数校验失败"), "000005", errorMap.toString());

}

也可以在controller中返回.

      Map<String, StringBuilder> errorMap = ValidatorUtils.validate(accountAO);

if (!CollectionUtils.isEmpty(errorMap)) {

simpleData.setData(errorMap);

result.setContent(simpleData);

return result;

}

也可以在controller的形参上使用注解@Valid,这种方式不需要util类,可以直接使用,直接抛出异常,需要加配置项,具体可以百度,个人不喜欢这种方式,不够灵活.

    @PostMapping(value = "/order")

public PojoResult<String> purchase(@RequestBody @Valid OrderAO orderAO,

HttpServletRequest request) throws IOException, ServletException {

PojoResult<String> pojoResult = new PojoResult<>();

}

三.自定义注解校验

框架自带的注解只能解决一些常规的校验,一些复杂逻辑的校验,可以使用自定义校验器,这是本人很喜欢的功能,重复的复杂的校验逻辑可以使用注解很优雅的代替,让代码的耦合性降低,也更简洁.
自定义校验的基本思路是--自定义注解+自定义校验器

自定义注解

//这里可以加上原生的注解,直接使用非空等功能

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})

@Retention(RetentionPolicy.RUNTIME)

//这里需要引入校验器

@Constraint(validatedBy = CheckTagsValidator.class)

@Documented

public @interface CheckTags {

String message() default "";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

}

自定义校验器

 //接口的两个泛型,分别是自定义注解和注解校验的参数类型

public class CheckTagsValidator implements ConstraintValidator<CheckTags, List<String>> {

@Override

public void initialize(CheckTags constraintAnnotation) {

}

//方法体内可以写自己需要校验的逻辑,返回值为false则校验不通过

@Override

public boolean isValid(List<String> value, ConstraintValidatorContext context) {

boolean isValid = false;

//限定最多3个tag,最少可以0个,tag不超过4个汉字

if (CollectionUtils.isEmpty(value)) {

return true;

}

String filter = value.stream().filter(tag -> tag.length() > 4).findAny().orElse(null);

if (StringUtils.isBlank(filter) && value.size() < 4) {

isValid = true;

}

if (!isValid) {

context.disableDefaultConstraintViolation();

context.buildConstraintViolationWithTemplate("标签输入错误").addConstraintViolation();

}

return isValid;

}

}

结合ValidatorUtil使用

四.Controller中校验参数

Validator本身是支持用@Valid注解自动校验的,也可可以配置校验返回策略,如下

@Configuration

public class ValidatorConfiguration {

@Bean

public Validator validator(){

ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )

.configure()

.addProperty( "hibernate.validator.fail_fast", "true" )

.buildValidatorFactory();

Validator validator = validatorFactory.getValidator();

return validator;

}

}

个人并不推荐这种方式,参数不对时会直接抛出异常,然后@ControllerAdvice全局异常处理,返回结果
有两个弊端,一是try/catch相对而言性能较低,二是返回异常结果不够清晰;
推荐使用ValidatorUtil结合AOP,直接返回结果,代码如下

@Slf4j

@Aspect

@Component

public class ValidatorAspect {

private static final String METHOD_POST = "POST";

@Around("execution(* com.test.government.affair.controller..*(..))")

public Object handlerControllerMethod(ProceedingJoinPoint point) throws Throwable {

long s = System.currentTimeMillis();

// 从获取RequestAttributes中获取HttpServletRequest的信息

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

HttpServletRequest request = (HttpServletRequest) requestAttributes

.resolveReference(RequestAttributes.REFERENCE_REQUEST);

BucSSOUser user = SimpleUserUtil.getBucSSOUser(request);

Object[] args = point.getArgs();

//校验post请求参数

log.info("Controller: 请求 URI( {} )| user( {} )| args:( {} )| ", request.getRequestURI(), user.getEmpId(), args);

if (METHOD_POST.equals(request.getMethod())) {

for (int i = 0; i < args.length; i++) {

Object arg = args[i];

Map<String, StringBuilder> errorMap = ValidatorUtil.validate(arg);

if (!CollectionUtils.isEmpty(errorMap)) {

log.info("参数校验失败 errorMap:{}", errorMap);

return ServiceResult.error("000005", errorMap.toString());

}

}

}

Object proceed = point.proceed();

log.info("Controller: 响应 result:( {} )| 请求耗时:( {} )", proceed, System.currentTimeMillis() - s);

return proceed;

}

}

统一参数校验,同时打印log

作者:从入门到脱发
链接:https://www.jianshu.com/p/b3876bf9396c
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

以上是 参数校验工具之Validator自定义校验 的全部内容, 来源链接: utcz.com/z/511968.html

回到顶部