java实现AOP记录日志操作

通过AOP切面实现自定义注解,完成添加日志记录的操作

1.首先定义公共接口,接口中的方法根据自己的需求自己添加和定义

import javax.validation.constraints.NotNull;
import java.lang.annotation.*;


//Target注解type可以放在类上,method可以放在方法上
@Target({ElementType.TYPE, ElementType.METHOD})
//Retention注解括号中的"RetentionPolicy.RUNTIME"意思是让 MyLog 这个注解的生命周期一直程序运行时都存在
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
    /**
     * 方法名
     * @return
     */
    @NotNull
    String method() default "";

    /**
     * 操作
     * @return
     */
    @NotNull
    String operate() default "";
}
  1. 创建一个实体类用来封装并存储具体的数据
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Log {
    /**
     * 唯一id
     */
    private Integer id;

    /**
     * 操作人员
     */
    private Long UserId;
    /**
     * 模块操作
     */
    private String operate;
    /**
     * 日志内容
     */
    private String content;
    /**
     * 方法名称
     */
    private String methodName;
    /**
     * ip地址
     */
    private String ip;
    /**
     * 操作状态(0正常 1删除)
     */
    private String status;
    /**
     * 操作时间
     */
    private Date operateTime;
    /**
     * 执行时间
     */
    private long executeTime;
}
  1. 再定义一个切面类
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.shade.org.apache.commons.lang3.ArrayUtils;
import com.dlbcloud.cjd.common.annotation.LogAnnotation;
import com.dlbcloud.cjd.common.utils.HttpContextUtils;
import com.dlbcloud.cjd.common.utils.IPUtils;
import com.dlbcloud.cjd.common.utils.StringUtils;
import com.dlbcloud.cjd.domain.log.domain.OperLog;
import com.dlbcloud.cjd.server.base.enums.BizConstants;
import lombok.extern.slf4j.Slf4j;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Optional;

/**
 * 日志切面
 */
@Component
@Aspect//定义了切面和切点的关系
@Slf4j
public class LogAspect {

    @Resource
    UserSercice userService;

    @Pointcut("@annotation(放入第一项公共接口的项目全路径)")
    public void logPointCut() {
    }

    /**
     * 环绕通知
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //执行方法(可以获取到方法执行完毕后返回的参数)
        Object result = point.proceed();
        //执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        //保存日志
        dispose(point, time,result);
        return result;
    }

    /**
     * 处理过程
     */
    private void dispose(ProceedingJoinPoint point, long time,Object result) {
        try{
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            //获取注解位置请求的参数(logAnnotation可以获取到注解方法的参数)
            LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
            log.info("方法名:{}", logAnnotation.method());
            log.info("方法描述:{}", logAnnotation.operate());

            int type = logAnnotation.type();
            //请求的参数
            Object[] args = point.getArgs();
            String className = point.getTarget().getClass().getName();
            String methodName = signature.getName();
            log.info("方法名:{}", className + "." + methodName + "()");
            //获取request
            HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
            //解析参数,获取请求参数里面具体的值(需要看args数组里面具体的参数args[?])
           String arg = JSONObject.toJSONString(args[0]);
           JSONObject jsonObject = JSONObject.parseObject(arg);
           //同样方法解析返回的参数
			//String re = JSONObject.toJSONString(result);
	        //JSONObject reObj = JSONObject.parseObject(re);
	       //JSONObject data = (JSONObject) reObj.get("data");

           //实例化对象
           Log  log = new Log();
           String UserId= jsonObject.getString("UserId");
           log .setUserId(UserId);
           //调自己的接口,保存数据
           log.setOperate(logAnnotation.operate());
           log.setContent(className + "." + methodName + "()");
           log.setMethodName(logAnnotation.operate() + jsonString);
           log.setIp(IPUtils.getIpAddr(request));
           log.setStatus("0");
           log.setOperateTime(new Timestamp(System.currentTimeMillis()));
           log.setExecuteTime(time);
           userService.save(operLog);
    }

}
  1. 获取Ip的工具包
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;

@Slf4j
public class IPUtils {
    /**
     * 获取IP地址
     * <p>
     * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
     * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = null, unknown = "unknown", seperator = ",";
        int maxLength = 15;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
            log.error("IpUtils ERROR ", e);
        }

        // 使用代理,则获取第一个IP地址
        if (StringUtils.isEmpty(ip) && ip.length() > maxLength) {
            int idx = ip.indexOf(seperator);
            if (idx > 0) {
                ip = ip.substring(0, idx);
            }
        }
        return ip;
    }
}
  1. 获取request的包
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class HttpContextUtils {
    public static HttpServletRequest getHttpServletRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }

    public static HttpServletResponse getHttpServletResponse() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    }

    public static HttpSession getHttpSession() {
        return getHttpServletRequest().getSession();
    }

    public static String getDomain() {
        HttpServletRequest request = getHttpServletRequest();
        StringBuffer url = request.getRequestURL();
        String domain = url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
        return domain;
    }

    public static String getOrigin() {
        HttpServletRequest request = getHttpServletRequest();
        return request.getHeader("Origin");
    }

    public static String getIp() {
        HttpServletRequest request = getHttpServletRequest();
        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();
        }
        return ip;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP是一个强大的框架,可以帮助我们实现各种切面,其包括日志记录。下面是实现日志记录的步骤: 1. 添加Spring AOP依赖 在Maven或Gradle添加Spring AOP依赖。 2. 创建日志切面 创建一个用于记录日志的切面。这个切面可以拦截所有需要记录日志的方法。在这个切面,我们需要使用@Aspect注解来声明这是一个切面,并使用@Pointcut注解来定义哪些方法需要被拦截。 ```java @Aspect @Component public class LoggingAspect { @Pointcut("execution(* com.example.demo.service.*.*(..))") public void serviceMethods() {} @Around("serviceMethods()") public Object logServiceMethods(ProceedingJoinPoint joinPoint) throws Throwable { // 获取方法名,参数列表等信息 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); // 记录日志 System.out.println("Method " + methodName + " is called with args " + Arrays.toString(args)); // 执行方法 Object result = joinPoint.proceed(); // 记录返回值 System.out.println("Method " + methodName + " returns " + result); return result; } } ``` 在上面的代码,我们使用了@Around注解来定义一个环绕通知,它会在拦截的方法执行前后执行。在方法执行前,我们记录了该方法的名称和参数列表,然后在方法执行后记录了该方法的返回值。 3. 配置AOP 在Spring的配置文件配置AOP。首先,我们需要启用AOP: ```xml <aop:aspectj-autoproxy/> ``` 然后,我们需要将创建的日志切面添加到AOP: ```xml <bean id="loggingAspect" class="com.example.demo.aspect.LoggingAspect"/> <aop:config> <aop:aspect ref="loggingAspect"> <aop:pointcut id="serviceMethods" expression="execution(* com.example.demo.service.*.*(..))"/> <aop:around method="logServiceMethods" pointcut-ref="serviceMethods"/> </aop:aspect> </aop:config> ``` 在上面的代码,我们将创建的日志切面声明为一个bean,并将其添加到AOP。我们还定义了一个切入点,并将其与日志切面的方法进行关联。 4. 测试 现在,我们可以测试我们的日志记录功能了。在我们的业务逻辑,所有匹配切入点的方法都会被拦截,并记录它们的输入和输出。我们可以在控制台看到这些日志信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值