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

硅谷探秘者 1090 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";
    }
}

 

猜你喜欢
框架 2979 springaop实现此次的目的是实现对controller中的方法执行情况进行的有方法执行时间,人,请求的路径,方法的入参,模块,功能等。并实现利注解的方式实现对被
数据库 486 MariaDB/MySQL中,主要有5种文件:1.错误(errorlog):mysql服务的启停时正确和错误的信息,还启动、停止、运行过程中的错误信息。2.查询(generallog):
数据库 549 开启和设置二进制切换二进制相关参数二进制恢复数据库上一篇文章介绍了普通查询和慢查询等参考:mysql分析,本篇主要介绍二进制。一、什么是二进制  二进制主要
框架 534 }/pattern/layoutencoderpattern${PATTERN}/patterncharsetUTF-8/charset/encoder/appender!--下面配置一些第三方包的过滤级别,
git 381 码;完成编辑,我们gitadd将工区文件添加到暂存区;然gitcommit提交文件到我们自己的分支。命令:gitcheckoutfiles或者gitcheckout.:把文件从暂存区域复
java项目 968 springboot+mybatis配置多数据源并利aop实现自动切换(demo)
spring/springmvc 803 "spring在ioc容器中获取aop的受理对象",这句话是什么意思呢?有时候我们会在spring项目中对一下类进行代理,比如我们会spring的aop和自定义注解对一些接口访问添加,再比如对
分布式项目管理工具 828 git&github学习使
归档
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 2021年04月  4 2021年05月  4 2021年06月  1 2021年07月  7 2021年08月  2 2021年09月  8 2021年10月  9 2021年11月  16 2021年12月  14 2022年01月  7 2022年05月  1 2022年08月  3 2022年09月  2 2022年10月  2
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议 keepalived minio mysql ensp 网络基础 xxl-job
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。