spring aop 配置(controller层 配置包名)

今天在 PLAY项目里面, 要配置一个aop,拦截controller的所有请求,把入参都记录下来。

步骤1:引入aop的依赖:

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

步骤2:添加aop配置的类:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import first.zxz.tools.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import simple.proj.zxz.play.pojo.entity.LogEntity;
import simple.proj.zxz.play.pojo.vo.FieldVO;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Date;

/**
 * 控制器层的aop
 *
 * @author zhangxz
 * 2019/11/6
 */


@Aspect
@Component
@Slf4j
public class ControllerAop {

    //get方法类型
    private static final String METHOD_TYPE_GET = "GET";

    //controller层的aop配置

    //配置注解
    //@Pointcut(value = "@annotation(org.springframework.web.bind.annotation.GetMapping)")

    //配置指定包下的类,不包含子包
    //@Pointcut("execution(* simple.proj.zxz.play.controller.acg.*.*(..))")

    //配置指定包下的类,包含所有子包的类
    @Pointcut("execution(* simple.proj.zxz.play.controller..*.*(..))")
    public void controllerAspect() {
    }


    /**
     * 切面方法,在方法执行期间,记录方法的入参,返回结果,执行时长等信息
     *
     * @param joinPoint 切面数据
     * @return java.lang.Object
     * @author Zxz
     * @date 2019/11/7 11:46
     **/
    @Around(value = "controllerAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

        long startTime = System.currentTimeMillis();

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        LogEntity logEntity = new LogEntity();

        logEntity.setCreateTime(new FieldVO<>(new Date()));
        logEntity.setReqData(getReqDataStr(joinPoint));
        logEntity.setRemoteIp(getIp(request));

        logEntity.setReqApi(request.getRequestURL().toString());
        logEntity.setReqType(request.getMethod());

        logEntity.setReqMethod(joinPoint.getSignature().toShortString());

        try {
            Object proceed = joinPoint.proceed();

            long endTime = System.currentTimeMillis();
            logEntity.setMethodHandleMilliseconds(endTime - startTime);

            if (!isIdempotentMethod(request.getMethod())) {
                logEntity.setResult(proceed.toString());
            }

            log.info("controller request data: " + JSON.toJSONString(logEntity, true));

            return proceed;
        } catch (Throwable throwable) {

            long endTime = System.currentTimeMillis();
            logEntity.setMethodHandleMilliseconds(endTime - startTime);

            logEntity.setErrorMsg(throwable.getMessage());
            log.info("controller request data: " + JSON.toJSONString(logEntity, true));

            throw throwable;
        }


    }

    /**
     * 判断方法类型是否为幂等性的方法
     * 只有类型为GET的方法,才是幂等性的。
     *
     * @param methodType 方法类型
     * @return boolean
     * @author Zxz
     * @date 2019/11/7 11:43
     **/
    private boolean isIdempotentMethod(String methodType) {
        if (StringUtil.isEmptyAndBlank(methodType)) {
            return false;
        }
        return methodType.trim().toUpperCase().equals(METHOD_TYPE_GET);
    }

    /**
     * 获取请求的ip地址
     *
     * @param request 请求
     * @return java.lang.String
     * @author Zxz
     * @date 2019/11/7 11:39
     **/
    private static String getIp(HttpServletRequest request) {
        if (request == null)
            return null;
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                log.error(e.getLocalizedMessage(), e);
            }
        }
        return ip;
    }

    /**
     * 获取请求参数,构造成字符串
     *
     * @param joinPoint 数据
     * @return java.lang.String
     * @author Zxz
     * @date 2019/11/6 17:37
     **/
    private String getReqDataStr(JoinPoint joinPoint) {
        StringBuilder result = new StringBuilder();
        if (joinPoint.getArgs() == null || joinPoint.getArgs().length <= 0) {
            return result.toString();
        }
        for (Object arg : joinPoint.getArgs()) {
            if (isInputString(arg)) {
                String jsonString = JSON.toJSONString(arg,
//                        SerializerFeature.NotWriteDefaultValue,
                        SerializerFeature.DisableCircularReferenceDetect,
                        SerializerFeature.WriteClassName);
                result.append(jsonString).append(",");
            }
        }

        //去除最后一个逗号
        if (result.length() > 0) {
            result.deleteCharAt(result.length() - 1);
        }
        return result.toString();
    }

    /**
     * 判断对象是否是用户输入的数据
     *
     * @param arg 对象
     * @return boolean
     * @author Zxz
     * @date 2019/11/6 17:40
     **/
    private boolean isInputString(Object arg) {
        return !(arg instanceof HttpServletRequest)
                && !(arg instanceof HttpServletResponse)
                && !(containsMultipartFile(arg));
    }

    /**
     * 判断是否包含MultipartFile类型数据
     *
     * @param object 数据
     * @return boolean
     * @author Zxz
     * @date 2019/11/6 17:37
     **/
    private boolean containsMultipartFile(Object object) {
        if (object instanceof MultipartFile) {
            return true;
        }
        if (object instanceof Collection) {
            Collection list = (Collection) object;
            for (Object o : list) {
                if (o instanceof MultipartFile) {
                    return true;
                }
            }
        }
        return false;
    }

}

以上两步完成之后,项目运行过程中,每次有请求到达Controller层的接口时,都会去记录该请求的具体情况:客户端ip,请求数据,请求类型,请求方法名,请求执行总时间,请求返回结果,错误信息等。

原文地址:https://www.cnblogs.com/zhangxuezhi/p/11812020.html