使用AOP进行数据校验

Spring Validation 实战

利用 AOP 实现数据校验(不用处理异常)

当访问接口时,切面会先判断是否存在校验错误项

  • 若存在错误项则返回错误
  • 若不存在错误项则正常访问接口

环境搭建

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

</dependencies>

实体类

@Data
public class User {
    @NotBlank(message = "用户名不能为空")
    @Length(max = 10, message = "用户名最大长度为10")
    private String userName;
    @Phone(message = "手机号不合法")
    private String phoneNumber;
}

接口

@RestController
public class UserController {
    @PostMapping("/user")
    public String save(@Validated User user, BindingResult result) {
        return "数据校验成功";
    }
}

AOP

@Aspect
@Component
public class BindingResultAspect {
    /**
     * 只切入controller中有两个个参数,且第二个参数为BindingResult类型的方法
     * 此处根据项目特点选择切入点
     */
    @Pointcut("execution(public * com.mystudy.springvalidation.controller..*.*(*,org.springframework.validation.BindingResult))")
    public void controllerBindingResult() {
    }

    @Around("controllerBindingResult() ")
    public Object BindingResult(ProceedingJoinPoint joinPoint) throws Throwable {
        // 参数值
        Object[] args = joinPoint.getArgs();
        //取第二个参数即 BindingResult
        BindingResult bindingResult = (BindingResult) args[1];
        //如果存在校验失败错误
        if (bindingResult.hasErrors()) {
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            List<String> list = new ArrayList<>();
            fieldErrors.forEach(x -> list.add(x.getDefaultMessage()));
            return list.toString();
        }
        return joinPoint.proceed();
    }
}

测试

校验失败

校验通过

项目代码

/**
 * @description: 切入使用BindingResult的接口
 *
 * @author weijb
 * @since 2020.12.04 15:21
 */
@Aspect
@Component
public class BindingResultAspect {
    private final Logger logger = LoggerFactory.getLogger(BindingResultAspect.class);

    //只切入controller中有三个参数,且第二个参数为BindingResult类型的方法
    @Pointcut("execution(public * com.haier.tms.*.controller..*.*(*,org.springframework.validation.BindingResult,*))")
    public void controllerBindingResult() {
    }

    @Around("controllerBindingResult() ")
    public Object BindingResult(ProceedingJoinPoint joinPoint) throws Throwable {
        // 参数值
        Object[] args = joinPoint.getArgs();

        BindingResult bindingResult = (BindingResult) args[1];
        if (bindingResult.hasErrors()) {
            return jsr303RestFul(bindingResult, joinPoint);
        }
        return joinPoint.proceed();
    }


    private Result jsr303RestFul(BindingResult bindingResult, ProceedingJoinPoint joinPoint) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //日志处理Util
        StringBuilder sb = CommonLogInfoUtil.commonLog(joinPoint, requestAttributes);
        
        //打印错误字段
        sb.append("{[FIELD_ERROR: ");
        sb.append(bindingResult.getFieldError().getField());
        sb.append("=");
        //打印错误字段的值
        String value;
        if (bindingResult.getFieldError().getRejectedValue() == null){
            value = "null";
        }else {
            value = bindingResult.getFieldError().getRejectedValue().toString();
        }
        sb.append(value);

        //打印自定义错误信息
        sb.append(" ------>校验错误: ");
        sb.append(bindingResult.getFieldError().getDefaultMessage());
        
        RestFulStatus status;
        switch (bindingResult.getFieldError().getCode()) {
            case "NotNull":
            case "NotBlank":
                status = RestFulStatus.JSR303_IS_NULL;
                break;
            case "Length":
                status = RestFulStatus.JSR303_TOO_LONG;
                break;
            case "Digits":
                status = RestFulStatus.JSR303_DIGITS;
                break;
            case "DecimalMin":
            case "DecimalMax":
                status = RestFulStatus.JSR303_TOO_BIG;
                break;
            case "typeMismatch":
                status = RestFulStatus.JSR303_TYPE_MISMATCH;
                break;
            default:
                status = RestFulStatus.API_PARAM;
        }
        //打印国际化信息
        sb.append("]; [FIELD_ERROR_RESTFUL: ");
        sb.append(status.getKey());
        sb.append("]}");
        //打印错误注解
        sb.append(" ---").append(bindingResult.getFieldError().getCode()).append("---");
        logger.error(sb.toString());
        //返回国际化信息
        return Result.error(status);
        //测试阶段返回日志信息,方便前端同事对接
        //return Result.error(sb.toString());
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值