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

2019 精帖
0 88

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";
    }
}

 

留言(0)
加载更多
猜你喜欢
  • blog springboot在eclipse中使devtools实现热部署

    如果你的eclipse安装了springboot插件可以通过下面方式1.选择springboot项目右击选择spring->add devtools2.点击pom文件中会出现一个依赖 <dependency> <groupI
  • blog avl树的插入和删除

    package avlTree;import java.util.LinkedList;/** * avl树(平衡二叉树) * @author Administrator * */public class AvlTree { privat
  • blog 链式栈的出栈入栈c++描述

    链式栈的出栈入栈c++描述基于双向链表//节点class node{public : int data; node * next; node * prev;};//双向链表#include"node.h"class s
  • blog linux户管理指令笔

    linux户管理指令笔useradd 户名:添加户useradd -d 目户名:添加户,并指定目useradd -g 户组 户名:添加户,并指定户组passwd 户名:为某户设置密码,只有root户有权限u
  • blog linux bg / fg命令的使

    &:这个在一个命令的最,可以把这个命令放到执行。ctrl+z:可以将一个正在前执行的命令放到,并且暂停执行。jobs:查看当前有多少在运行的命令。fg:将中的命令调至前继续运行。如果中有多个命令,可以 fg j
  • blog springboot打包分离资源文件时遇到的问题

    多么痛的领悟~分离资源打包运行项目,启动失败数据源初始化失败~检查问题,这种情况下没有打印错误,首先配置一下,将错误报告在控制中打印出来。resources文件夹下 创建一个 log4j.properties 文件log4j.r
  • blog http get和post请求

    1.区别(1)post更安全(不会为url的一部分,不会被缓存、保存在服务器、以及浏览器浏览中) (2)post发送的数据更大(get有url长度限制) (3)post能发送更多的数据类型(get只能发送ASCII字符) (4)p
  • blog 链式队列的基本 c++

    链式队列的基本 c++class node{public : int data; node * next; node * prev;};#include "node.h"class queue{private :
  • blog 二叉树基本 c++

    二叉树基本 c++class node{public : int data; node * left; node * right; node(); node(int data); node(int data,node * left,no
  • blog 微信登获取openid和户信息(端java)

    完整测试代码下载地址:http://www.jiajiajia.club/file/info/5SQzy7/120  首先配置微信公众平测试账号 位置:微信公众号->开发->开发者工具->微信公众平测试账