[踩坑]在项目中引入validator导致aop切面异常问题

590 阅读1分钟

如题,在引入validator后,当我传入一个空值时,

    /**
     * 角色名称
     */
    @NotBlank(message = "角色名称不能为空!")
    private String roleName;

系统抛出了如下下异常

com.alibaba.fastjson.JSONException: write javaBean error, fastjson version 1.2.83, class org.springframework.web.bind.MethodArgumentNotValidException, fieldName : 0, write javaBean error, fastjson version 1.2.83, class org.springframework.validation.BeanPropertyBindingResult, fieldName : bindingResult, write javaBean error, fastjson version 1.2.83, class org.springframework.beans.GenericTypeAwarePropertyDescriptor, fieldName : 0

可以看到是fastjson解析java对象时出现了问题,于是推断出问题可能在为了方便调试写的一个记录接口入参的切面中

Aspect
@Component
@Order(1)
@Slf4j
public class AspectConfig {
​
    @Pointcut("execution(* com.z.controller..*.*(..))")
    private void webLog(){
    }
    @Before(value="webLog()")
    public void before(JoinPoint joinPoint){
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        log.info("请求日志的打印");
        log.info("请求地址:{}", Optional.ofNullable(request.getRequestURI().toString()).orElse(null));
        log.info("请求方式:{}",request.getMethod());
        log.info("请求类方法:{}",joinPoint.getSignature());
        log.info("请求类方法参数:{}", JSONObject.toJSONString(JSONObject.toJSONString(filterArgs(joinPoint.getArgs()))));
    }
    private List<Object> filterArgs(Object[] objects) {
        return Arrays.stream(objects).filter(obj -> !(obj instanceof MultipartFile)
                && !(obj instanceof HttpServletResponse)
                && !(obj instanceof HttpServletRequest)
                ).collect(Collectors.toList());
    }
}

经过debug,当这个切面切到的时候joinPoint.getArgs()的值已经是这样了

org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.z.bean.base.Response com.z.controller.RoleController.edit(com.z.bean.admin.req.role.RoleEditReq): [Field error in object 'roleEditReq' on field 'roleName': rejected value []; codes [NotBlank.roleEditReq.roleName,NotBlank.roleName,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [roleEditReq.roleName,roleName]; arguments []; default message [roleName]]; default message [角色名称不能为空!]] 

validator抛出的异常,被封装成了接口参数传到了切面,所以fastjson序列化不了。

不难得知,validator验证顺序应该是在自定义切面之前的,想到使用Orderd指定优先级,但是都没有效果。

解决:序列化时过滤掉异常类型,由系统中的ExceptionHandler去捕获异常。

private List<Object> filterArgs(Object[] objects) {
        return Arrays.stream(objects).filter(obj -> !(obj instanceof MultipartFile)
                && !(obj instanceof HttpServletResponse)
                && !(obj instanceof HttpServletRequest)
                && !(obj instanceof Exception)).collect(Collectors.toList());}

validator验证在参数解析时执行,而AOP的执行时机却是,在调用方法时才会执行。因此validator验证始终会比AOP先执行。