创建监听器三步骤:
1、事件(event)可以封装和传递监听器中要处理的参数,如对象或字符串,并作为监听器中监听的目标。
2、监听器(listener)具体根据事件发生的业务处理模块,这里可以接收处理事件中封装的对象或字符串。
3、事件发布者(publisher)事件发生的触发者。
代码展示:
pom.xml
org.springframework
spring-aspects
cn.hutool
hutool-all
4.6.8
第一步:
定义一个事件,需要继承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 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 {
@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("切面注解监听");
}
}
日志成功记录