自定义注解进行参数校验
经常用到在javax.validation包下的参数校验方式, 例如一些@Length,@NotNull,@NotBlank, 等等, 有次业务中频繁的需要校验字符串拼接格式问题; 突发奇想写一个参数校验的注解,为自己做下记录
- 首先需要自定义注解, 类似于这样:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Constraint(validatedBy = ProductIdStrValidated.class)
public @interface ProductIdStrRule {
String message() default "商品编号拼接格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@ducumened: 为这个注解类做解释说明;
@retention: 表示这个注解作用的生命周期, 常用参数就是RetentionPolicy.RUNTIME, 即运行时
@target: 作用范围, 可定义多个, 因为楼主只是做单个参数校验, 所以ElementType.FIELD, 但是作用在更大的范围, 例如, method, class, PACKAGE
@Constraint: 重要注解, 处理类,类似于处理器, 参数可在此类校验, 并且该类被spring所管理, 可注入其他的service, mapper等, 作用于其他操作
- 参数校验类
public class ProductIdStrValidated implements ConstraintValidator<ProductIdStrRule,String> {
private String message;
@Override
public void initialize(ProductIdStrRule constraintAnnotation) {
this.message = constraintAnnotation.message();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
System.out.println(value);
if (StringUtil.isBlank(value)){
return true;
}
if (value.lastIndexOf(",")+1 == value.length() || value.indexOf(",") == 0){
return false;
}
String[] split = value.split(",");
boolean flag = true;
for (String s : split) {
if (!isNumeric(s)){
flag = false;
}
}
return flag;
}
}
此类实现ConstraintValidator泛型参数两个; 前者为自定义注解, 后者为参数类型
initialize为初始化构造方法
isValid为校验方法, 实际操作的方法
- 为参数接受实体加上注解 @Validated, 表示加入参数校验
public Result getPage(@Validated Req Req){}
楼主的定义的简单校验, 逗号拼接的字符串, 判断拆分后都为数字类型, 否则返回false, 就会抛出异常信息
商品编号拼接格式不正确
错误传参 异常信息如此
{
"timestamp": 1590390392334,
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"ProductIdStrRule.stockAdjustReq.productId",
"ProductIdStrRule.productId",
"ProductIdStrRule.java.lang.String",
"ProductIdStrRule"
],
"arguments": [
{
"codes": [
"stockAdjustReq.productId",
"productId"
],
"arguments": null,
"defaultMessage": "productId",
"code": "productId"
}
],
"defaultMessage": "商品编号拼接格式不正确",
"objectName": "stockAdjustReq",
"field": "productId",
"rejectedValue": "21,aa",
"bindingFailure": false,
"code": "ProductIdStrRule"
}
],
"message": "Validation failed for object='stockAdjustReq'. Error count: 1",
"path": "/stockData/getPage"
}
此时已经参数校验已生效但是错误信息过于复杂, 可定义异常拦截器格式化错误信息
- 此处使用springBoot的@RestControllerAdvice + @ExceptionHandler方式, 如下
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
private static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 方法参数校验
*/
@ExceptionHandler(BindException.class)
public Result bindException(BindException e) {
log.error(e.getMessage(), e);
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(","));
return Result.buildFail(message);
}
}
最后错误信息如下
{
"code": -1,
"msg": "商品编号拼接格式不正确",
"model": null
}
到此完成自定义注解参数校验;