springboot使用aop记录后台操作日志

硅谷探秘者 455 0 0

1.Log注解

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

//该注解可以放在controller类上,但是只有 modular 参数有效;
//该注解也可以放在controller类的方法上,如果只有方法上有Log注解,那么只会解析该注解上的信息,
//如果类和方法上都有Log注解,且方法上的 modular参数 不是默认值,那么以方法上的 modular 参数为准,否则以类上的 modular 参数为准;

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /** 方法模块 */
    String modular() default "";
    /** 功能描述 */
    String describe() default "";
}

2.日志信息封装DTO

import lombok.Data;
import lombok.ToString;
import java.time.LocalDateTime;
/**
 * @ClassName LogMessage
 * @Description: 日志数据封装
 * @Author Jiajiajia
 * @Version V1.0
 **/
@Data
@ToString
public class LogMessage {
    //操作人id
    private Long operationUserId;
    //操作人
    private String operationUser;
    //操作模块
    private String modular;
    //具体方法描述
    private String describe;
    //来源计算机ip地址
    private String ip;
    //操作状态
    private byte state;
    //请求类型
    private String type;
    //执行时间
    private LocalDateTime createTime=LocalDateTime.now();
    //其他信息
    private String message;

    public void setState(State state){
        this.state=state.getState();
    }
    /**
     *  操作状态的枚举类
     */
    public enum State{
        SUCCESS((byte)0),ERROR((byte)1);
        private byte state;
        State(byte state){
            this.state=state;
        }
        public byte getState(){
            return state;
        }
    }
}

3.注解解析

利用反射技术,获取注解所在类的类信息,方法信息,和注解信息


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
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.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @ClassName AopTest
 * @Author Jiajiajia
 * @Version V1.0
 **/
@Aspect
@Component
public class LogAopAdapter {
    /**
     *  如果同步操作那就在这里注入dao层,在doAfter或throwing方法中将message对象插入数据库;
     *  如果异步操作,那就在doAfter或throwing方法中将message对象放入阻塞队列异步执行,或者使用mq,
     *  或者使用springboot的异步事件等;
     */
//    @Resource
//    private LogAopDao logAopDao;

    @Pointcut("@annotation(com.test.Log)")
    public void log(){}

    /**
     *  前置通知
     * @param joinPoint
     * @throws Throwable
     */
    @Before("log()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
    }

    /**
     *  后置通知
     * @param joinPoint
     * @throws Throwable
     */
    @After("log()&&@annotation(logMessage)")
    public void doAfter(JoinPoint joinPoint,Log logMessage)throws Throwable{
        LogMessage message = getMessage(joinPoint,logMessage);
        message.setState(LogMessage.State.SUCCESS);
        System.out.println(message);
    }

    /**
     *  异常通知
     * @param joinPoint
     * @param ex
     * @throws Exception
     */
    @AfterThrowing(value="log()&&@annotation(logMessage)", throwing="ex")
    public void throwing(JoinPoint joinPoint,Log logMessage,Exception ex) throws Exception{
        LogMessage message = getMessage(joinPoint,logMessage);
        message.setMessage(ex.getMessage());
        message.setState(LogMessage.State.ERROR);
        System.out.println(message);
    }

    private LogMessage getMessage(JoinPoint joinPoint,Log mlog)throws Exception{
        LogMessage message=new LogMessage();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        message.setType(request.getMethod());
        message.setIp(getUserRealIp(request));
        Signature signature = joinPoint.getSignature();
        Class c=signature.getDeclaringType();
        if(!"".equals(mlog.describe())){
            message.setDescribe(mlog.describe());
        }
        if(!"".equals(mlog.modular())){
            message.setModular(mlog.modular());
        }else{
            Log clog=(Log)c.getAnnotation(Log.class);
            if(clog!=null){
                if(!"".equals(clog.modular())){
                    message.setModular(clog.modular());
                }
            }
        }
        return message;
    }

    /**
     * 获取源主机ip地址
     * @param request
     * @return
     * @throws UnknownHostException
     */
    public static String getUserRealIp(HttpServletRequest request) throws UnknownHostException {
        String ip;
        if  (request.getHeader("x-forwarded-for") == null)  {
            ip = request.getRemoteAddr();
        }  else  {
            ip = request.getHeader("x-forwarded-for");
        }
        if  ("127.0.0.1".equals(ip))  {
            ip = InetAddress.getLocalHost().getHostAddress();
        }
        return ip;
    }
}

4.测试代码

测试代码
@Log(modular = "测试模块")
@RestController
public class TestController {
    @GetMapping("test")
    @Log(describe = "测试描述")
    public String test(){
        if(true){
	//手动抛异常
            throw new Exception("异常");
        }
        return "test";
    }
}

 

猜你喜欢
框架 2431 springaop实现此次的目的是实现对controller中的方法执行情况进行的有方法执行时间,人,请求的路径,方法的入参,模块,功能等。并实现利注解的方式实现对被
spring/springmvc 244 "spring在ioc容器中获取aop的受理对象",这句话是什么意思呢?有时候我们会在spring项目中对一下类进行代理,比如我们会spring的aop和自定义注解对一些接口访问添加,再比如对
java项目 475 springboot+mybatis配置多数据源并利aop实现自动切换(demo)
框架 1593 log4j.properties配置1.完整示例:##屏蔽com.mchange.v2包下面的debug,info,warn信息##log4j.logger.xxx=error意为屏蔽xxx包下
分布式项目管理工具 355 git&github学习使
框架 487 springboot+mybatis配置多数据源并利aop实现自动切换1.项目大致结构2.pom依赖dependencygroupIdorg.springframework.boot
计算机网络基础 1631 1.区别(1)post更安全(不会为url的一部分,不会被缓存、保存在服务器、以及浏览器浏览中)(2)post发送的数据更大(get有url长度限制)(3)post能发送更多的数据类型
linux系统 3234 linux文件目类指令笔pwd:查看当前工mkdira:创建目a,mkdir-pa/b:创建多级目/a/brmdir:删除空目rm-rf:删除目touch文件名:创建空文件cp:拷
归档
2018年11月  12 2018年12月  33 2019年01月  28 2019年02月  28 2019年03月  32 2019年04月  27 2019年05月  33 2019年06月  6 2019年07月  12 2019年08月  12 2019年09月  21 2019年10月  8 2019年11月  15 2019年12月  25 2020年01月  9 2020年02月  5 2020年03月  16 2020年04月  4 2020年06月  1 2020年07月  7 2020年08月  13 2020年09月  9 2020年10月  5 2020年12月  3 2021年01月  1 2021年02月  5 2021年03月  7
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo
目录