美文网首页
Aop中接收处理@Valid校验结果

Aop中接收处理@Valid校验结果

作者: 轻轻敲醒沉睡的心灵 | 来源:发表于2020-12-08 15:48 被阅读0次

在SpringBoot中,请求参数使用了@Valid注解,同时使用Aop记录了日志,但是当发生@Valid的异常时,在Aop的切点中记录不到,虽然全局异常捕获到了@Valid异常,但在aop中无法处理异常。为了在Aop中记录请求参数和参数校验结果,需要将@Valid的BindingResult带入到aop中。

1. 注意点

    1. 方法的参数中若有@Valid注解,要绑定上BindingResult bindingResult
      BindingResult
      -- 若不添加BindingResult ,当在参数实体中校验出错误时,就会直接抛出异常,程序走不到这里,也就不会走aop;
      -- 添加BindingResult后,校验出错误时,会记录到result中,不抛出异常,程序走到这里时进aop,在aop中处理BindingResult结果
    1. @Around注解上 要加上 && args(.., bindingResult) 用来接收参数
      image.png

2. Aop中处理@Valid校验结果

Aop示例中有接收swagger注解的处理

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.test.dao.LogDao;
import com.test.entity.Log;
import com.test.exception.MyArgumentException;

import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

@Aspect
@Component
@Slf4j
public class LogPrintAspect {
    
    @Resource
    private LogDao logDao;
    

    @Pointcut("within(com.test..*) && @within(org.springframework.web.bind.annotation.RestController)")
    public void getParams() {
        
    }
    
    @Pointcut("within(com.test..*) && @within(org.springframework.web.bind.annotation.RestController)")
    public void printLog() {
        
    }
    
    @Pointcut("within(com.test..*) && @within(org.springframework.web.bind.annotation.RestController) && !args(..,org.springframework.validation.BindingResult)")
    public void printLogNoBindingResult() {
        
    }
    
    @Before(value = "getParams()")
    public void beforeFunction(JoinPoint joinPoint) {
        
    }
    
    @AfterReturning(value = "printLog()", returning = "ret")
    public void afterReturningFunction(Object ret) {

    }
    
    /**
     * 此方法用来拦截不含BindingResult参数校验结果的方法
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("printLogNoBindingResult()")
    public Object aroundFunction(ProceedingJoinPoint joinPoint) throws Throwable {
        Long startTime = System.currentTimeMillis();
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        Log l = new Log();
        l.setAccessTime(new Date(startTime));
        l.setAccessMethod(joinPoint.getSignature().getName());
        log.info("\r\n请求地址:" + request.getRequestURL().toString());
        l.setRequestUri(request.getRequestURL().toString());
        // 获取header
        Map<String, String> headerMap = ServletUtil.getHeaderMap(request);
        if (!headerMap.isEmpty()) {
            log.info("\r\n请求头header:{}", headerMap);
        }
        // 获取表单请求参数
        Map<String, String> m = ServletUtil.getParamMap(request);
        if (m.isEmpty()) { // 无表单参数,获取其他参数
            Object[] args = joinPoint.getArgs();
            ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            String[] parameterNames = pnd.getParameterNames(method);
            for (int i = 0; i < parameterNames.length; i++) {
                if (!"bindingResult".equals(parameterNames[i])) {
                    m.put(parameterNames[i], args[i].toString());
                }
            }
        }
        log.info(m.isEmpty()?"\r\n请求参数为空":"\r\n请求参数:{}", JSONUtil.parseObj(m).toJSONString(1));
        l.setRequestParams(JSONUtil.parseObj(m).toJSONString(0));
        l.setUserid(request.getHeader("CurrentUser"));
        l.setRemoteIpAddress(request.getRemoteAddr());
        
        // 获取@Api注解信息
        Class<?> targetClass = joinPoint.getTarget().getClass();
        if (targetClass.isAnnotationPresent(Api.class)) {
            Api swaggerApi = (Api) targetClass.getDeclaredAnnotation(Api.class);
//          log.info("模块名称-->>  {}", swaggerApi.tags()[0]);
            l.setAccessModule(swaggerApi.tags()[0]);
        }
        // 获取@ApiOperation注解信息
        Signature sig = joinPoint.getSignature();
        MethodSignature msig = (MethodSignature)sig;
        Method md = targetClass.getMethod(msig.getName(), msig.getParameterTypes());
        if (md.isAnnotationPresent(ApiOperation.class)) {
            ApiOperation swaggerApiOperation = (ApiOperation) md.getDeclaredAnnotation(ApiOperation.class);
//          log.info("功能名称-->>  {}", swaggerApiOperation.value());
            l.setAccessFunction(swaggerApiOperation.value());
        }
        
        // 执行proceed(),只能执行一次
        Object result = joinPoint.proceed();
        l.setResponseData(JSONUtil.parseObj(result).toJSONString(0));
        log.info("\r\n返回结果: " + JSONUtil.parseObj(result));
        Long endTime = System.currentTimeMillis();
        l.setTimeConsuming((int)(endTime - startTime));
        logDao.insert(l);
        return result;
    }
    
    /**
     * 此方法用来拦截含有BindingResult参数校验结果的方法
     * @param joinPoint
     * @param bindingResult
     * @return
     * @throws Throwable
     */
    @Around("printLog() && args(.., bindingResult)")
    public Object aroundFunctionWithBindingResult(ProceedingJoinPoint joinPoint, BindingResult bindingResult) throws Throwable {
        Long startTime = System.currentTimeMillis();
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        Log l = new Log();
        l.setAccessTime(new Date(startTime));
        l.setAccessMethod(joinPoint.getSignature().getName());
        log.info("\r\n请求地址:" + request.getRequestURL().toString());
        l.setRequestUri(request.getRequestURL().toString());
        // 获取header
        Map<String, String> headerMap = ServletUtil.getHeaderMap(request);
        if (!headerMap.isEmpty()) {
            log.info("\r\n请求头header:{}", headerMap);
        }
        // 获取表单请求参数
        Map<String, String> m = ServletUtil.getParamMap(request);
        if (m.isEmpty()) { // 无表单参数,获取其他参数
            Object[] args = joinPoint.getArgs();
            ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            String[] parameterNames = pnd.getParameterNames(method);
            for (int i = 0; i < parameterNames.length; i++) {
                if (!"bindingResult".equals(parameterNames[i])) {
                    m.put(parameterNames[i], args[i].toString());
                }
            }
        }
        log.info(m.isEmpty()?"\r\n请求参数为空":"\r\n请求参数:{}", JSONUtil.parseObj(m).toJSONString(1));
        l.setRequestParams(JSONUtil.parseObj(m).toJSONString(0));
        l.setUserid(request.getHeader("CurrentUser"));
        l.setRemoteIpAddress(request.getRemoteAddr());
        
        // 参数校验有错误返回
        if (bindingResult.hasErrors()) {
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            List<String> lists = new ArrayList<String>();
            for (FieldError error : fieldErrors) {
                lists.add(error.getDefaultMessage());
            }
            l.setResponseData(lists.toString());
            throw new MyArgumentException(lists.toString(), JSONUtil.parseObj(m));
        }
        
        // 获取@Api注解信息
        Class<?> targetClass = joinPoint.getTarget().getClass();
        if (targetClass.isAnnotationPresent(Api.class)) {
            Api swaggerApi = (Api) targetClass.getDeclaredAnnotation(Api.class);
//          log.info("模块名称-->>  {}", swaggerApi.tags()[0]);
            l.setAccessModule(swaggerApi.tags()[0]);
        }
        // 获取@ApiOperation注解信息
        Signature sig = joinPoint.getSignature();
        MethodSignature msig = (MethodSignature)sig;
        Method md = targetClass.getMethod(msig.getName(), msig.getParameterTypes());
        if (md.isAnnotationPresent(ApiOperation.class)) {
            ApiOperation swaggerApiOperation = (ApiOperation) md.getDeclaredAnnotation(ApiOperation.class);
//          log.info("功能名称-->>  {}", swaggerApiOperation.value());
            l.setAccessFunction(swaggerApiOperation.value());
        }
        
        // 执行proceed(),只能执行一次
        Object result = joinPoint.proceed();
        l.setResponseData(JSONUtil.parseObj(result).toJSONString(0));
        log.info("\r\n返回结果: " + JSONUtil.parseObj(result));
        Long endTime = System.currentTimeMillis();
        l.setTimeConsuming((int)(endTime - startTime));
        logDao.insert(l);
        return result;
    }
}

在Aop中处理校验结果,拿到自定义的message,抛出异常,由全局统一异常处理。


Springboot添加AOP参考:Springboot添加AOP打印请求参数 - 简书 (jianshu.com)
SpringBoot添加全局统一异常参考:SpringBoot添加全局统一异常处理 - 简书 (jianshu.com)

相关文章

网友评论

      本文标题:Aop中接收处理@Valid校验结果

      本文链接:https://www.haomeiwen.com/subject/lpdtgktx.html