SpringBoot基于注解切面监听事件

创建监听器三步骤:

1、事件(event)可以封装和传递监听器中要处理的参数,如对象或字符串,并作为监听器中监听的目标。

2、监听器(listener)具体根据事件发生的业务处理模块,这里可以接收处理事件中封装的对象或字符串。

3、事件发布者(publisher)事件发生的触发者。

代码展示:

pom.xml

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.8</version>
        </dependency>

第一步:

定义一个事件,需要继承spring的ApplicationEvent
package top.xzhand.event;

import org.springframework.context.ApplicationEvent;

/**
 * 定义一个事件,需要继承spring的ApplicationEvent
 */
public class LogEvent extends ApplicationEvent {

    public LogEvent(Object source) {
        super(source);
    }
}

第二步:

定义切面,发布事件

@Component@Aspect  这两个注解必须添加
package top.xzhand.event.aspect;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import top.xzhand.event.LogEvent;
import top.xzhand.po.RequestLog;
import org.aspectj.lang.JoinPoint;
import top.xzhand.util.LogUtil;
import java.util.Date;

/**
 * 切面发布
 */

@Component
@Aspect
public class LogAspect {
    public static final ThreadLocal<RequestLog> THREAD_LOCAL = new ThreadLocal<>();

    @Autowired
    private ApplicationContext applicationContext;

    @Pointcut("@annotation(top.xzhand.event.common.Log)")
    public void logAspect() {

    }

    @Before(value = "logAspect()")
    public void before(JoinPoint point) throws Throwable {
        RequestLog requestLog = new RequestLog();
        requestLog.setCreateAt(new Date());//开始时间
        Environment environment = applicationContext.getEnvironment();
        String appName = environment.getProperty("spring.application.name");
//		sysLog.setCreateName(createName);
        THREAD_LOCAL.set(LogUtil.getSysLog(point,requestLog));
        System.out.println("进入切面:"+JSON.toJSONString(requestLog));
    }

    @AfterReturning(returning = "rvt", pointcut = "logAspect()")
    public void afterReturning(JoinPoint point, Object rvt) throws Throwable {
        RequestLog sysLog = get();
        if (rvt != null) {
            sysLog.setResponseResult(LogUtil.getText(JSON.toJSONString(rvt)));
        } else {
            sysLog.setResponseResult(null);
        }
        publishEvent(sysLog);
        System.out.println("切面监听事件发布成功:"+JSON.toJSONString(sysLog));
    }

    private void publishEvent(RequestLog sysLog) {
        applicationContext.publishEvent(new LogEvent(sysLog));
        THREAD_LOCAL.remove();
    }

    @AfterThrowing(pointcut = "logAspect()", throwing = "e")
    public void afterThrowing(Throwable e) {
        RequestLog sysLog = get();
        publishEvent(sysLog);
    }

    private RequestLog get() {
        RequestLog sysLog = THREAD_LOCAL.get();
        if (sysLog == null) {
            return new RequestLog();
        }
        return sysLog;
    }

}

 定义切入点注解

package top.xzhand.event.common;

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;

/**
 * 方法级别 日志
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Log {

    String value() default "";
}

 相关实体类,mapper,service等忽略,可自己生成!

package top.xzhand.po;

import java.util.Date;

public class RequestLog {
    private Integer id;

    private String requestUrl;

    private String requestArgs;

    private String ipUrl;

    private String message;

    private String responseResult;

    private Date createAt;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRequestUrl() {
        return requestUrl;
    }

    public void setRequestUrl(String requestUrl) {
        this.requestUrl = requestUrl == null ? null : requestUrl.trim();
    }

    public String getRequestArgs() {
        return requestArgs;
    }

    public void setRequestArgs(String requestArgs) {
        this.requestArgs = requestArgs == null ? null : requestArgs.trim();
    }

    public String getIpUrl() {
        return ipUrl;
    }

    public void setIpUrl(String ipUrl) {
        this.ipUrl = ipUrl == null ? null : ipUrl.trim();
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message == null ? null : message.trim();
    }

    public String getResponseResult() {
        return responseResult;
    }

    public void setResponseResult(String responseResult) {
        this.responseResult = responseResult == null ? null : responseResult.trim();
    }

    public Date getCreateAt() {
        return createAt;
    }

    public void setCreateAt(Date createAt) {
        this.createAt = createAt;
    }
}

  

package top.xzhand.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import lombok.experimental.UtilityClass;
import org.aspectj.lang.JoinPoint;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import top.xzhand.event.common.Log;
import top.xzhand.po.RequestLog;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Date;

@UtilityClass // 方法变量 静态话,类final 私有构造器
public class LogUtil {

	public RequestLog getSysLog(JoinPoint point, RequestLog sysLog) {

		HttpServletRequest request = getRequest();
		sysLog.setIpUrl(getIP(request));
		sysLog.setRequestUrl(URLUtil.getPath(request.getRequestURI()));
		sysLog.setRequestArgs(request.getQueryString());
		sysLog.setCreateAt(new Date());

		return sysLog;
	}

	private HttpServletRequest getRequest() {
		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
	}
	private final String UNKNOWN = "unknown";

	public String getIP(HttpServletRequest request) {
		String ip = request.getHeader("X-Requested-For");
		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Forwarded-For");
		}
		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return StrUtil.isBlank(ip) ? null : ip.split(",")[0];
	}
	public String getText(String val) {
		return StrUtil.sub(val, 0, 65535);
	}

	/***
	 * 获取操作信息
	 *
	 * @param point
	 * @return
	 */
	public String getControllerMethodDescription(JoinPoint point) {
		try {
			// 获取连接点目标类名
			String targetName = point.getTarget().getClass().getName();
			// 获取连接点签名的方法名
			String methodName = point.getSignature().getName();
			// 获取连接点参数
			Object[] args = point.getArgs();
			// 根据连接点类的名字获取指定类
			Class targetClass = Class.forName(targetName);
			// 获取类里面的方法
			Method[] methods = targetClass.getMethods();
			String description = "";
			for (Method method : methods) {
				if (method.getName().equals(methodName)) {
					Class[] clazzs = method.getParameterTypes();
					if (clazzs.length == args.length) {
						description = method.getAnnotation(Log.class).value();
						break;
					}
				}
			}
			return description;
		} catch (Exception e) {
			return "";
		}
	}

	/**
	 * 获取堆栈信息
	 *
	 * @param throwable
	 * @return
	 */
	public  String getStackTrace(Throwable throwable) {
		StringWriter sw = new StringWriter();
		try (PrintWriter pw = new PrintWriter(sw)) {
			throwable.printStackTrace(pw);
			return getText(sw.toString());
		}
	}
}

 

package top.xzhand.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import top.xzhand.po.RequestLog;

/**
 * 事件发布
 *
 */
@Component
public class EventPublister {
    @Autowired
    private ApplicationContext applicationContext;

    // 事件发布方法
    public void pushListener(RequestLog requsetLog) {
        applicationContext.publishEvent(new LogEvent(requsetLog));
    }

}

  

第三步:

 自定义监听器处理业务

package top.xzhand.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import top.xzhand.po.RequestLog;
import top.xzhand.service.RequestLogService;

/**
 * 自己定义的监听器需要实现ApplicationListener,
 * 同时泛型参数要加上自己要监听的事件Class名,
 * 在重写的方法onApplicationEvent中,添加自己的业务处理
 */
@Component
public class LogListerner  implements ApplicationListener<LogEvent> {
    @Autowired
    private RequestLogService requestLogService;
    @Override
    public void onApplicationEvent(LogEvent logEvent) {
        RequestLog requestLog=(RequestLog) logEvent.getSource();
        requestLogService.insertSelective(requestLog);

    }
}

 验证测试:

package top.xzhand.controller;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import top.xzhand.event.EventPublister;
import top.xzhand.event.common.Log;
import top.xzhand.po.RequestLog;
import top.xzhand.util.LogUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 *
 */
@Controller
public class TestEventListenerController {
    @Autowired
    private EventPublister publisher;

    /**
     * 非注解形式监听事件
     * @param request
     * @param arg
     */
    @RequestMapping(value = "/test/logEvent1" )
    public void testPublishEvent1(HttpServletRequest request,String arg ){
        RequestLog requestLog=new RequestLog();
        requestLog.setCreateAt(new Date());
        requestLog.setRequestUrl(request.getContextPath());
        requestLog.setIpUrl(LogUtil.getIP(request));
        requestLog.setRequestArgs(request.getQueryString());
        publisher.pushListener(requestLog);
        System.out.println(JSON.toJSONString(requestLog));
    }

    /**
     * 基于注解的切面事件发布监听
     * @param request
     * @param arg
     */
    @Log
    @RequestMapping(value = "/test/logEvent2" )
    public void testPublishEvent2(HttpServletRequest request,String arg ){

        System.out.println("切面注解监听");
    }

}

 日志成功记录

原文地址:https://www.cnblogs.com/notmore/p/12699683.html

时间: 2024-10-29 15:17:13

SpringBoot基于注解切面监听事件的相关文章

JAVAscript学习笔记 js句柄监听事件 第四节 (原创) 参考js使用表

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>句柄添加监听事件</title> <script type="text/javascript" src="tzy.js"></script> </head> <body>

浅谈postMessage多页面监听事件

最近做了一个Echarts和Highcharts多图多页面连动的效果,就用到postMessage 如下介绍: 最开始在最外围的页面也就是所有页面的父级页面添加postMessage监听事件以便监听下面子级页面的动态,代码: window.parent.addEventListener('message',function(e){ if(e.source != window.parent) return; var names = localStorage.getItem("toName"

ios ---键盘的监听事件

//在view将要出现的时候重载viewWillAppear方法添加通知 监听事件 keyboardWillShow:  keyboardWillHide: - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:

js html 交互监听事件学习

事件处理程序(handler): HTML事件处理程序: <input type="button" value="Click Here" onclick="showMessage();" /> <script type="text/javascript"> function showMessage() { alert('Clicked!'); } JavaScript指定事件处理程序: <inpu

Android中Button的五种监听事件

简单聊一下Android中Button的五种监听事件: 1.在布局文件中为button添加onClick属性,Activity实现其方法2.匿名内部类作为事件监听器类3.内部类作为监听器4.Activity本身作为事件监听器,实现onClickListener5.外部类作为监听器 ButtonListenerActivity.class public class ButtonListenerActivity extends AppCompatActivity implements View.On

Android——监听事件总结1

各种监听事件 1.按钮 Button(1)点击监听 btn_1.setOnClickListener(new View.OnClickListener() { (2)长按监听 btn_1.setOnLongClickListener(new View.OnLongClickListener() { 2.单选框 RadioGroup radio_gp.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { 3.复选

datePicker 及 timePicker 监听事件 获取用户选择 年月日分秒信息

public class MainActivity extends AppCompatActivity { private TimePicker timePicker; private DatePicker datePicker; private Calendar cal; private int year; private int month; private int day; private int hour; private int minute; @Override protected

Android中Preference的使用以及监听事件分析

> 在Android系统源码中,绝大多数应用程序的UI布局采用了Preference的布局结构,而不是我们平时在模拟器中构建应用程序时使用的View布局结构,例如,Setting模块中布局.当然,凡事都有例外,FMRadio应用程序中则使用了View布局结构(可能是该应用程序是marvel公司提供的,如果由google公司做,那可说不准).归根到底,Preference布局结构和View的布局结构本质上还是大同小异,Preference的优点在于布局界面的可控性和高效率以及可存储值的简洁性(每个

监听事件 实现的四种方法

1.初始化当前所需要控件,如何初始化一个控件…………private Button xxxxfindViewById---返回的是一个View的对象…………需要强转成其子类Button对象findViewById---是如何查找View的Id…………通过R中的ID2.设置Button的监听器,通过监听器实现我们点击Button需要操作的事情 方式一: 匿名内部类实现事件监听:在按钮的setOnClickListener方法中new一个OnClickListener类,并在OnClickListen