美文网首页Java
Spring切面编程(AOP)-拦截API请求打印日志

Spring切面编程(AOP)-拦截API请求打印日志

作者: AC编程 | 来源:发表于2022-03-16 09:54 被阅读0次

    一、实体类

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ApiModel(value = "api请求日志记录")
    public class LogApi {
    
        @ApiModelProperty(value = "线程ID")
        private String threadId;
    
        @ApiModelProperty(value = "线程名称")
        private String threadName;
    
        @ApiModelProperty(value = "ip")
        private String ip;
    
        @ApiModelProperty(value = "url")
        private String url;
    
        @ApiModelProperty(value = "http方法 GET POST PUT DELETE PATCH")
        private String httpMethod;
    
        @ApiModelProperty(value = "类方法")
        private String classMethod;
    
        @ApiModelProperty(value = "请求参数")
        private Object requestParams;
    
        @ApiModelProperty(value = "返回参数")
        private Object result;
    
        @ApiModelProperty(value = "接口耗时")
        private Long timeCost;
    
        @ApiModelProperty(value = "是否为移动平台")
        private boolean mobile;
    
        @ApiModelProperty(value = "浏览器类型")
        private String browser;
    
        @ApiModelProperty(value = "平台类型")
        private String platform;
    
        @ApiModelProperty(value = "系统类型")
        private String os;
    
        @ApiModelProperty(value = "引擎类型")
        private String engine;
    
        @ApiModelProperty(value = "浏览器版本")
        private String version;
    
        @ApiModelProperty(value = "引擎版本")
        private String engineVersion;
    }
    

    二、AOP拦截

    @Aspect
    @Component
    @Slf4j
    public class AOPLogApi {
    
        private static final String UNKNOWN = "unknown";
    
        /**
         * 日志切入点 - 正常执行<br>
         * 表达式1:拦截所有controller
         * 表达式2:排除拦截ApiLogController中的方法
         */
        @Pointcut(
            "execution(public * com.alanchen.*.controller.*Controller.*(..))" +
            "&& !execution(public * com.alanchen.*.controller.ApiLogController.*(..))" +
            "&& !execution(public * com.alanchen.*.controller.SensitiveWordController.selectList(..))" +
            "&& !execution(public * com.alanchen.*.controller.SensitiveWordController.test(..))"
        )
        public void logPointCut() {
    
        }
    
        /**
         * 日志切入点 - 异常
         */
        @Pointcut(
                "execution(public * com.alanchen.*.controller.*Controller.*(..))"
        )
        public void logExceptionPointCut() {
    
        }
    
        /**
         * 正常执行
         * @param point 切入点
         * @throws Throwable 异常信息
         */
        @Around("logPointCut()")
        public Object logAround(ProceedingJoinPoint point) throws Throwable {
            Object result = point.proceed();
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
    
                // 打印请求相关参数
                long startTime = System.currentTimeMillis();
                String ua = request.getHeader("User-Agent");
                UserAgent userAgent = UserAgentUtil.parse(ua);
                ApiLogVO logApi = new ApiLogVO();
                //线程ID
                logApi.setThreadId(Long.toString(Thread.currentThread().getId()));
                //线程名
                logApi.setThreadName(Thread.currentThread().getName());
                //IP
                logApi.setIp(getIp(request));
                //访问URI
                logApi.setUrl(request.getRequestURL().toString());
                //http方法
                logApi.setHttpMethod(request.getMethod());
                //类方法
                logApi.setClassMethod(point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName());
                //请求参数
                logApi.setRequestParams(getNameAndValue(point));
                //返回参数
               // logApi.setResult(JSONUtil.toJsonStr(result));
                //接口耗时
                logApi.setTimeCost(System.currentTimeMillis() - startTime);
                //是否为移动平台
                logApi.setMobile(userAgent.isMobile());
                //浏览器类型
                logApi.setBrowser(userAgent.getBrowser().getName());
                //平台类型
                logApi.setPlatform(userAgent.getPlatform().getName());
                //系统类型
                logApi.setOs(userAgent.getOs().getName());
                //引擎类型
                logApi.setEngine(userAgent.getEngine().getName());
                //浏览器版本
                logApi.setVersion(userAgent.getVersion());
                //引擎版本
                logApi.setEngineVersion(userAgent.getEngineVersion());
                //操作时间
                logApi.setCreateTime(LocalDateTime.now());
                log.info("API请求信息: {}", JSONUtil.toJsonStr(logApi));
            }
    
            return result;
        }
    
        /**
         * 异常
         * @param point 切入点
         * @param e     异常
         */
        @AfterThrowing(pointcut = "logExceptionPointCut()", throwing = "e")
        public void logExceptionAround(JoinPoint point, Throwable e) {
            e.printStackTrace();
        }
    
        /**
         * 获取ip
         * @param request
         * @return
         */
        private String getIp(HttpServletRequest request) {
            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.getRemoteAddr();
            }
            String comma = ",";
            String localhost = "127.0.0.1";
            if (ip.contains(comma)) {
                ip = ip.split(",")[0];
            }
            if (localhost.equals(ip)) {
                // 获取本机真正的ip地址
                try {
                    ip = InetAddress.getLocalHost().getHostAddress();
                } catch (UnknownHostException e) {
                    log.error(e.getMessage(), e);
                }
            }
            return ip;
        }
    
        /**
         *  获取方法参数名和参数值
         * @param joinPoint
         * @return
         */
        private Map<String, Object> getNameAndValue(ProceedingJoinPoint joinPoint) {
    
            final Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            final String[] names = methodSignature.getParameterNames();
            final Object[] args = joinPoint.getArgs();
    
            if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) {
                return Collections.emptyMap();
            }
            if (names.length != args.length) {
                log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName());
                return Collections.emptyMap();
            }
            Map<String, Object> map = Maps.newHashMap();
            for (int i = 0; i < names.length; i++) {
                map.put(names[i], args[i]);
            }
            return map;
        }
    }
    

    相关文章

      网友评论

        本文标题:Spring切面编程(AOP)-拦截API请求打印日志

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