利用aop进行统一日志记录

本文介绍如何使用面向切面编程(AOP)来实现应用程序的日志记录功能,通过在关键点插入日志代码,达到日志统一管理的目的。详细步骤和代码注释帮助理解实践过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码比较简单,直接看注释吧。


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * aop系统日志注解
 *
 * @author TenSunLee
 * @date 2019/7/26
 * @version 1.0.0
 * @updateBy TenSunLee
 * @updated 2019/7/26
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SystemLogger {
    /**
     * 对调用方法的简单描述
     * @return 描述内容
     */
    String description() default "";
}

 

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;

/**
 * service日志切面类
 *
 * @author TenSunLee
 * @date 2019/7/25
 * @version 1.0.0
 * @updateBy TenSunLee
 * @updated 2019/7/29
 *
 */
@Aspect
@Component
public class SystemLogAspect {
    /**
     * 定义切入点为SystemLogger注解
     */
    @Pointcut("@annotation(com.bosssoft.hr.train.jl.boss.bes.basedat.center.aspect.annotation.SystemLogger)")
    public void logPointcut(){};

    /**
     * 日志对象
     */
    private static org.slf4j.Logger logger = LoggerFactory.getLogger("System_ControllerLogger");

    /**
     *记录controller接受请求和响应的状况
     *
     * @param pjp 切点
     */
    @Around(value = "logPointcut()", argNames = "pjp")
    public Object log(ProceedingJoinPoint pjp) throws Throwable {
        //前置日置记录
        //获取方法参数
        Object[] args = pjp.getArgs();
        StringBuilder stringBuilder = new StringBuilder();
        for(Object arg:args){
            stringBuilder.append(arg).append(":");
        }
        String params = stringBuilder.toString();
        //获取方法名
        String methodName = pjp.getTarget().getClass().getName() + "."
                + pjp.getSignature().getName() + "()";
        Method method = ((MethodSignature)pjp.getSignature()).getMethod();
        //获取注解中的description参数
        SystemLogger systemLoggerAnno = method.getAnnotation(SystemLogger.class);
        String methodDescription = "";
        if(null!= systemLoggerAnno) {
            methodDescription = systemLoggerAnno.description();
        }
        //尝试获取request对象
        HttpServletRequest request = null;
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if(null!=requestAttributes){
            request = ((ServletRequestAttributes) requestAttributes).getRequest();
        }
        //尝试获取ip及user-agent
        String ipAddr = null;
        String userAgent = null;
        if(null!=request){
             ipAddr = getIpAddress(request);
             userAgent = request.getHeader("user-agent");
        }
        //获取本次方法执行唯一标识UUID
        String uuid = UUID.randomUUID().toString();
        //拼接方法执行前日志字符串
        String beforeLogString = uuid + "\n::" + new Date() + "\n::进入方法"+methodName +
                "\n::" + methodDescription + "\n::客户端ip地址为" + ipAddr + "\n::客户端信息" +
                userAgent + "\n::参数为\n:: " + params;
        logger.info(beforeLogString);

        long start = System.currentTimeMillis();
        //执行原方法
        Object ret = pjp.proceed();
        long end = System.currentTimeMillis();
        //后置日志记录
        //拼接方法返回后日志字符串
        String afterLogString = uuid + "\n::" + new Date() + "\n::离开方法" + methodName +
                "\n::" + methodDescription + "\n::响应对象为\n:: " + ret + "\n::方法执行时间为" +
                (end-start) + "ms.";
        logger.info(afterLogString);
        return ret;
    }

    /**
     * 获取客户端IP地址
     *
     * @param request request对象
     * @return ip地址字符串
     */
    private  String getIpAddress(HttpServletRequest request) {
        String ip = null;

        //X-Forwarded-For:Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        String unknown = "unknown";
        if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP:apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP:weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP:有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP:nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到,最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值