亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

Spring AOP + 注解實現統一注解功能

2024-07-14 08:40:44
字體:
來源:轉載
供稿:網友

1. 概述

在一般系統中,當我們做了一些重要的操作時,如登陸系統,添加用戶,刪除用戶等操作時,我們需要將這些行為持久化。本文我們通過Spring AOP和Java的自定義注解來實現日志的插入。此方案對原有業務入侵較低,實現較靈活

2. 日志的相關類定義

我們將日志抽象為以下兩個類:功能模塊和操作類型

使用枚舉類定義功能模塊類型ModuleType,如學生、用戶模塊

public enum ModuleType {  DEFAULT("1"), // 默認值  STUDENT("2"),// 學生模塊  TEACHER("3"); // 用戶模塊  private ModuleType(String index){    this.module = index;  }  private String module;  public String getModule(){    return this.module;  }}

使用枚舉類定義操作的類型:EventType。如登陸、添加、刪除、更新、刪除等

public enum EventType {  DEFAULT("1", "default"), ADD("2", "add"), UPDATE("3", "update"), DELETE_SINGLE("4", "delete-single"),  LOGIN("10","login"),LOGIN_OUT("11","login_out");  private EventType(String index, String name){    this.name = name;    this.event = index;  }  private String event;  private String name;  public String getEvent(){    return this.event;  }  public String getName() {    return name;  }}

3. 定義日志相關的注解

3.1. @LogEnable

這里我們定義日志的開關量,類上只有這個值為true,這個類中日志功能才開啟

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE})public @interface LogEnable {  /**   * 如果為true,則類下面的LogEvent啟作用,否則忽略   * @return   */  boolean logEnable() default true;}

3.2. @LogEvent

這里定義日志的詳細內容。如果此注解注解在類上,則這個參數做為類全部方法的默認值。如果注解在方法上,則只對這個方法啟作用

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({java.lang.annotation.ElementType.METHOD, ElementType.TYPE})public @interface LogEvent {  ModuleType module() default ModuleType.DEFAULT; // 日志所屬的模塊  EventType event() default EventType.DEFAULT; // 日志事件類型  String desc() default ""; // 描述信息}

3.3. @LogKey

此注解如果注解在方法上,則整個方法的參數以json的格式保存到日志中。如果此注解同時注解在方法和類上,則方法上的注解會覆蓋類上的值。

@Target({ElementType.FIELD,ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface LogKey {   String keyName() default ""; // key的名稱   boolean isUserId() default false; // 此字段是否是本次操作的userId,這里略   boolean isLog() default true; // 是否加入到日志中}

4. 定義日志處理類

4.1. LogAdmModel

定義保存日志信息的類

public class LogAdmModel {  private Long id;  private String userId; // 操作用戶  private String userName;  private String admModel; // 模塊  private String admEvent; // 操作  private Date createDate; // 操作內容  private String admOptContent; // 操作內容  private String desc; // 備注  set/get略}

4.2. ILogManager

定義日志處理的接口類ILogManager

我們可以將日志存入數據庫,也可以將日志發送到開中間件,如果redis, mq等等。每一種日志處理類都是此接口的實現類

public interface ILogManager {  /**   * 日志處理模塊   * @param paramLogAdmBean   */  void dealLog(LogAdmModel paramLogAdmBean);}

4.3. DBLogManager

ILogManager實現類,將日志入庫。這里只模擬入庫

@Servicepublic class DBLogManager implements ILogManager {  @Override  public void dealLog(LogAdmModel paramLogAdmBean) {    System.out.println("將日志存入數據庫,日志內容如下: " + JSON.toJSONString(paramLogAdmBean));  }}

5. AOP的配置

5.1. LogAspect定義AOP類

使用@Aspect注解此類

使用@Pointcut定義要攔截的包及類方法

我們使用@Around定義方法

@Component@Aspectpublic class LogAspect {  @Autowired  private LogInfoGeneration logInfoGeneration;  @Autowired  private ILogManager logManager;  @Pointcut("execution(* com.hry.spring.mvc.aop.log.service..*.*(..))")  public void managerLogPoint() {  }  @Around("managerLogPoint()")  public Object aroundManagerLogPoint(ProceedingJoinPoint jp) throws Throwable {  ….  } }

aroundManagerLogPoint:主方法的主要業務流程

1. 檢查攔截方法的類是否被@LogEnable注解,如果是,則走日志邏輯,否則執行正常的邏輯

2. 檢查攔截方法是否被@LogEvent,如果是,則走日志邏輯,否則執行正常的邏輯

3. 根據獲取方法上獲取@LogEvent 中值,生成日志的部分參數。其中定義在類上@LogEvent 的值做為默認值

4. 調用logInfoGeneration的processingManagerLogMessage填充日志中其它的參數,做個方法我們后面再講

5. 執行正常的業務調用

6. 如果執行成功,則logManager執行日志的處理(我們這里只記錄執行成功的日志,你也可以定義記錄失敗的日志)

@Around("managerLogPoint()")    public Object aroundManagerLogPoint(ProceedingJoinPoint jp) throws Throwable {      Class target = jp.getTarget().getClass();      // 獲取LogEnable      LogEnable logEnable = (LogEnable) target.getAnnotation(LogEnable.class);      if(logEnable == null || !logEnable.logEnable()){        return jp.proceed();      }      // 獲取類上的LogEvent做為默認值      LogEvent logEventClass = (LogEvent) target.getAnnotation(LogEvent.class);      Method method = getInvokedMethod(jp);      if(method == null){        return jp.proceed();      }      // 獲取方法上的LogEvent      LogEvent logEventMethod = method.getAnnotation(LogEvent.class);      if(logEventMethod == null){        return jp.proceed();      }      String optEvent = logEventMethod.event().getEvent();      String optModel = logEventMethod.module().getModule();      String desc = logEventMethod.desc();      if(logEventClass != null){        // 如果方法上的值為默認值,則使用全局的值進行替換        optEvent = optEvent.equals(EventType.DEFAULT) ? logEventClass.event().getEvent() : optEvent;        optModel = optModel.equals(ModuleType.DEFAULT) ? logEventClass.module().getModule() : optModel;      }      LogAdmModel logBean = new LogAdmModel();      logBean.setAdmModel(optModel);      logBean.setAdmEvent(optEvent);      logBean.setDesc(desc);      logBean.setCreateDate(new Date());      logInfoGeneration.processingManagerLogMessage(jp,          logBean, method);      Object returnObj = jp.proceed();      if(optEvent.equals(EventType.LOGIN)){        //TODO 如果是登錄,還需要根據返回值進行判斷是不是成功了,如果成功了,則執行添加日志。這里判斷比較簡單        if(returnObj != null) {          this.logManager.dealLog(logBean);        }      }else {        this.logManager.dealLog(logBean);      }      return returnObj;    }    /**     * 獲取請求方法     *     * @param jp     * @return     */    public Method getInvokedMethod(JoinPoint jp) {      // 調用方法的參數      List classList = new ArrayList();      for (Object obj : jp.getArgs()) {        classList.add(obj.getClass());      }      Class[] argsCls = (Class[]) classList.toArray(new Class[0]);      // 被調用方法名稱      String methodName = jp.getSignature().getName();      Method method = null;      try {        method = jp.getTarget().getClass().getMethod(methodName, argsCls);      } catch (NoSuchMethodException e) {        e.printStackTrace();      }      return method;    }  }

6. 將以上的方案在實際中應用的方案

這里我們模擬學生操作的業務,并使用上文注解應用到上面并攔截日志

6.1. IStudentService

業務接口類,執行一般的CRUD

public interface IStudentService {  void deleteById(String id, String a);  int save(StudentModel studentModel);  void update(StudentModel studentModel);  void queryById(String id);}

6.2. StudentServiceImpl:

@LogEnable : 啟動日志攔截類上@LogEvent定義所有的模塊方法上@LogEven定義日志的其它的信息@Service@LogEnable // 啟動日志攔截@LogEvent(module = ModuleType.STUDENT)public class StudentServiceImpl implements IStudentService {  @Override  @LogEvent(event = EventType.DELETE_SINGLE, desc = "刪除記錄") // 添加日志標識  public void deleteById(@LogKey(keyName = "id") String id, String a) {    System.out.printf(this.getClass() + "deleteById id = " + id);  }  @Override  @LogEvent(event = EventType.ADD, desc = "保存記錄") // 添加日志標識  public int save(StudentModel studentModel) {    System.out.printf(this.getClass() + "save save = " + JSON.toJSONString(studentModel));    return 1;  }  @Override  @LogEvent(event = EventType.UPDATE, desc = "更新記錄") // 添加日志標識  public void update(StudentModel studentModel) {    System.out.printf(this.getClass() + "save update = " + JSON.toJSONString(studentModel));  }  // 沒有日志標識  @Override  public void queryById(String id) {    System.out.printf(this.getClass() + "queryById id = " + id);  }}

執行測試類,打印如下信息,說明我們日志注解配置啟作用了:

將日志存入數據庫,日志內容如下:

{"admEvent":"4","admModel":"1","admOptContent":"{/"id/":/"1/"}","createDate":1525779738111,"desc":"刪除記錄"}

7. 代碼

以上的詳細的代碼見下面

github代碼,請盡量使用tag v0.21,不要使用master,因為我不能保證master代碼一直不變


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品色婷婷福利天堂| 国产一区二区在线免费视频| 精品日本美女福利在线观看| 日韩欧美在线免费观看| 最新中文字幕亚洲| 日韩电影免费在线观看| 国产精品成人播放| 国产精品久久久久7777婷婷| 国产色视频一区| 久久在精品线影院精品国产| 日韩欧美在线观看视频| 色偷偷av亚洲男人的天堂| 欧美日韩国产成人在线观看| 日本高清视频精品| 精品在线小视频| 中文在线资源观看视频网站免费不卡| 清纯唯美亚洲综合| 国产成人在线一区| 久久久爽爽爽美女图片| 国内精品久久久久影院优| 538国产精品一区二区免费视频| 8090成年在线看片午夜| 668精品在线视频| 亚洲欧美视频在线| 日韩欧美在线免费观看| 日韩电影中文字幕一区| 亚洲美女视频网站| 九九精品视频在线观看| 久久精品久久久久久| 国产精品色婷婷视频| 91亚洲精品一区二区| 久久人人爽人人爽人人片亚洲| 欧美性videos高清精品| 国产精品视频内| 色妞在线综合亚洲欧美| 最近2019中文字幕大全第二页| 国产裸体写真av一区二区| 国产在线视频不卡| 国内精品久久久久久影视8| 久国内精品在线| 国产欧美日韩综合精品| 成人国产精品一区二区| 91精品视频播放| 亚洲欧洲成视频免费观看| 91精品久久久久久| 精品中文字幕视频| 欧美午夜精品久久久久久浪潮| 深夜福利国产精品| 中文字幕精品www乱入免费视频| 亚洲品质视频自拍网| 欧美激情乱人伦| 91亚洲精品一区二区| 中文字幕一区日韩电影| 欧美洲成人男女午夜视频| 亚洲影影院av| 在线观看国产成人av片| 亚洲精品国产成人| 日韩欧美福利视频| 国产亚洲精品美女| 成人有码在线视频| 第一福利永久视频精品| 欧美电影免费观看高清完整| 国产91在线播放| 欧美乱大交xxxxx| 亚洲乱码一区二区| 麻豆精品精华液| 成人av在线亚洲| 欧美老女人www| 中文字幕亚洲欧美日韩2019| 亚洲第一福利网站| 情事1991在线| 琪琪亚洲精品午夜在线| 伊人成人开心激情综合网| 精品电影在线观看| 国产精品揄拍500视频| 国产一区二区三区在线视频| 亚洲精品久久久久久久久久久久| 久久久久成人精品| 色哟哟网站入口亚洲精品| 日韩激情av在线免费观看| 国产精品一区二区av影院萌芽| 亚洲国产精品高清久久久| 国产精自产拍久久久久久蜜| www国产精品com| 欧美国产日韩一区| 日韩欧美在线第一页| 欧美在线视频网站| 国产婷婷色综合av蜜臀av| 中文日韩在线视频| 成人国产精品日本在线| 久久青草福利网站| 91免费高清视频| 亚洲欧美日韩天堂一区二区| 精品国产31久久久久久| 国产在线一区二区三区| 国内精品久久久久久影视8| 亚洲精品v欧美精品v日韩精品| 亚洲人线精品午夜| 亚洲天堂成人在线| 精品国产精品三级精品av网址| 日韩av网站电影| 久久久亚洲影院| 国产玖玖精品视频| 国产成+人+综合+亚洲欧美丁香花| 欧美一级大胆视频| 国产成人精品在线播放| 精品调教chinesegay| 91精品国产电影| 91精品久久久久久久久青青| 亚洲毛茸茸少妇高潮呻吟| 久久成人国产精品| 成人美女av在线直播| 亚洲无av在线中文字幕| 欧美精品日韩www.p站| 国产网站欧美日韩免费精品在线观看| 亚洲精品久久久久| 亚洲国产天堂久久国产91| 亚洲精品第一页| 国产精品日韩在线观看| 九九热r在线视频精品| 欧美日韩国产中文字幕| 欧美日韩福利在线观看| 91最新在线免费观看| 欧美激情视频在线| 午夜精品一区二区三区在线播放| 中日韩美女免费视频网站在线观看| 国产视频在线一区二区| 国产精品电影网| 亚洲视频在线播放| 亚洲国产另类 国产精品国产免费| 国产精品电影观看| 成人免费观看49www在线观看| 久久精品视频播放| 在线成人激情黄色| 欧美日韩中文字幕在线| 欧美精品第一页在线播放| 97免费中文视频在线观看| 91在线视频精品| 欧美激情视频在线观看| 国产在线观看91精品一区| 91久久嫩草影院一区二区| 精品视频偷偷看在线观看| 亚洲精品98久久久久久中文字幕| 在线日韩日本国产亚洲| 国产日韩在线看| 欧美性生交大片免费| 久久亚洲精品网站| 国产美女精彩久久| 亚洲精品综合精品自拍| 国产一区私人高清影院| 亚洲国产精品va在线看黑人动漫| 少妇精69xxtheporn| 国产亚洲一区精品| 在线观看亚洲视频| 国产精品1区2区在线观看| 中文字幕不卡av| 亚洲精品在线91| 黑人巨大精品欧美一区免费视频| 91国内在线视频| 久久人体大胆视频| 欧美人在线视频| 日韩资源在线观看| 亚洲国产日韩欧美在线动漫| 亚洲直播在线一区|