リスナーを作成する3つのステップ:
1. イベントは、オブジェクトや文字列など、リスナーで処理されるパラメーターをカプセル化して渡すことができ、リスナーのターゲットとして機能します。
2.リスナー(リスナー)は、特にイベントが発生するビジネス処理モジュールに基づいており、処理イベントにカプセル化されたオブジェクトまたは文字列を受け取ることができます。
3.イベント発行元(発行元)イベントのトリガー。
コード表示:
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を継承する必要があるイベントを定義する
パッケージtop.xzhand.event; import org.springframework.context.ApplicationEvent; / ** * SpringのApplicationEventを継承する必要があるイベントを定義 * / public class LogEvent extends ApplicationEvent { public LogEvent(Object source){ super(source); } }
2番目のステップ:
アスペクトを定義してイベントを公開する
@Component
@Aspect
これら2つのアノテーションを追加する必要があります
パッケージ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; インポートtop.xzhand.util.LogUtil; import java.util.Date; / ** *切り取り面 * / @Component @Aspect public class LogAspect { public static final ThreadLocal <RequestLog> THREAD_LOCAL = new ThreadLocal <>(); @Autowired プライベートApplicationContext applicationContext; @Pointcut( "@ annotation(top.xzhand.event.common.Log)") public void logAspect(){ } @Before(value = "logAspect()") public void before(JoinPoint point)throws Throwable { RequestLog requestLog =新しい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。 } 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(); } sysLogを返します。 } }
エントリポイントアノテーションを定義する
パッケージ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 ""; }
関連するエンティティクラス、マッパー、サービスなどは無視され、自分で生成できます。
パッケージtop.xzhand.po; import java.util.Date; public class RequestLog { private Integer id; プライベート文字列requestUrl; プライベート文字列requestArgs; プライベート文字列ipUrl; プライベート文字列メッセージ。 プライベート文字列responseResult; プライベート日付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(){ 戻りメッセージ。 } 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; } }
パッケージtop.xzhand.util; cn.hutool.core.util.StrUtilをインポートします。 cn.hutool.core.util.URLUtilをインポートします。 lombok.experimental.UtilityClassをインポートします。 import org.aspectj.lang.JoinPoint; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; インポート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 //メソッド变量静的态话、类最終私有构造器 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()); 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(); } 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(); //接続を取得しますPointパラメーター Object [] args = point.getArgs(); //接続ポイントの名前に従って指定されたクラスを取得します Class targetClass = Class.forName(targetName); String description = "" ; //クラスのメソッドを取得 Method []メソッド= targetClass.getMethods(); throwable StringWriter sw = new StringWriter(); for(メソッドmethod:methods){ if(method.getName()。equals(methodName)){ Class [] clazzs = method.getParameterTypes(); if(clazzs.length == args.length){ description = method.getAnnotation(Log.class).value(); ブレーク; } } } 説明を返します。 } catch(例外e){ return ""; } } / ** *获取堆栈信息 * * @param throwable * @return * / public String getStackTrace(Throwable throwable ){ try(PrintWriter pw = new PrintWriter(sw)){ throwable.printStackTrace(pw); getText(sw.toString());を返します。 } } }
パッケージ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)); } }
3番目のステップ:
ビジネスを処理するカスタムリスナー
パッケージ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を実装する必要があります。 *同時に、ジェネリックパラメーターは、監視するイベントのクラス名を追加する必要があります。 *書き換えられたメソッド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); } }
検証テスト:
パッケージ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; インポートtop.xzhand.event.EventPublister; インポートtop.xzhand.event.common.Log; import top.xzhand.po.RequestLog; インポートtop.xzhand.util.LogUtil; import javax.servlet.http.HttpServletRequest; import java.util.Date; / ** * * / @Controller public class TestEventListenerController { @Autowired private EventPublister Publisher; / ** *非注解形式监挺事件 * @paramリクエスト * @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( "切面注解监挺"); } }
ログが正常に記録されました