【Java EE 學習 76 下】【數據採集系統第八天】【經過AOP實現日誌管理】【日誌管理功能分析和初步實現】

1、日誌管理相關分析

  1.日誌管理是一種典型的系統級別的應用,很是適合使用spring AOP實現。java

  2.使用日誌管理的目的:對系統修改的動做進行記錄,好比對權限、角色、用戶的寫操做、修改操做、刪除操做等spring

  3.肯定使用的通知方式:使用環繞通知。複習一下環繞通知,所謂環繞通知實際上就是AOP代理對接口中聲明方法的執行進行攔截,在執行方法以前或者以後進行一些操做,在日誌管理功能模塊中,咱們對Service接口中聲明的方法進行攔截,若是是對系統進行的修改操做的方法,則將方法執行以後就須要將相關信息保存下來方便之後查看,好比是誰登錄的系統進行的修改(最重要),執行的是什麼方法,方法的參數是什麼,執行成功額仍是失敗了,方法的返回值是什麼,執行方法的時間是什麼等等。express

  4.日誌管理功能在系統中的體現:單擊導航菜單中的"日誌管理"超連接,查看全部的系統的變動歷史記錄。apache

2、日誌實體和相關類的書寫

  1.根據一種的分析,獲得瞭如下的日誌實體

1 public class Log {
2     private String logId;                    //日誌消息標識ID
3     private String operator="";                //操做人
4     private Date operatorDate=new Date();    //操做日期
5     private String operatorName;            //操做的名稱(方法名)
6     private String operateParams;            //操做參數
7     private String operateResult="";            //操做結果(success|failure)
8     private String resultMessage="";            //結果消息
9 }

  2.DAO類的書寫和Service的書寫略。

  3.建立日誌切面

  日誌切面提供了保存保存日誌的詳細方法(通知),該方法將會攔截目標方法的執行而且記錄該方法執行過程當中的詳細信息。session

 1 package com.kdyzm.aspect;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpSession;
 5 
 6 import org.apache.struts2.ServletActionContext;
 7 import org.aspectj.lang.ProceedingJoinPoint;
 8 
 9 import com.kdyzm.domain.Log;
10 import com.kdyzm.domain.User;
11 import com.kdyzm.service.LogService;
12 import com.kdyzm.utils.StringUtils;
13 
14 public class Logger {
15     private LogService logService;
16     public LogService getLogService() {
17         return logService;
18     }
19     public void setLogService(LogService logService) {
20         this.logService = logService;
21     }
22     //通知方法
23     public Object record(ProceedingJoinPoint joinPoint) throws Throwable{
24         Log log=new Log();
25         try{
26             //獲取操做人
27             HttpServletRequest request=ServletActionContext.getRequest();
28             if(request!=null){
29                 HttpSession session=request.getSession();
30                 User user=(User) session.getAttribute("user");
31                 if(user!=null){
32                     log.setOperator(user.getUserId()+"-"+user.getEmail());//設置操做人
33                 }
34             }
35             
36             //設置方法名
37             String methodName=joinPoint.getSignature().getName();
38             log.setOperatorName(methodName);
39             
40             //獲取參數列表
41             Object[] params=joinPoint.getArgs();
42             log.setOperateParams(StringUtils.arr2String(params));
43             
44             //操做結果和結果消息的獲取
45             Object obj=joinPoint.proceed();
46             log.setOperateResult("SUCCESS");
47             
48             if(obj!=null){
49                 log.setResultMessage(obj.toString());
50             }
51             return obj;            //返回執行結果
52         }catch(Exception e){
53             log.setOperateResult("FAILURE");
54             log.setResultMessage(e.getMessage());
55         }finally{
56             logService.saveLog(log);
57         }
58         return null;
59     }
60 }

  4.配置spring配置文件applicationConext.xml

    (1)首先將切面注入到spring容器

<bean id="logger" class="com.kdyzm.aspect.Logger">
        <property name="logService" ref="logService"></property>
    </bean>  

    (2)在aop配置中聲明切入點表達式,表示對那些方法進行日誌記錄

      注意這些方法都在事務通知上有定義,可是不能直接使用事務通知中的聲明,由於還有不一樣之處:必須刨除掉logService中的全部方法,不然最後確定會拋出堆棧溢出的異常。app

      分析緣由:logService中的記錄方法自己也是寫操做(默認加上了事務),若是是寫操做按照規則是須要寫入日誌表的,可是寫入的時候又被AOP日誌代理攔截,每次想寫的時候都被日誌AOP代理攔截,最終這種無限遞歸方式就會致使堆棧溢出,注意如下的切入點表達式的寫法已經將logService刨除掉了。dom

1 <aop:pointcut
2             expression="(execution(* *..*Service.save*(..))
3                                     or execution(* *..*Service.update*(..))
4                                     or execution(* *..*Service.delete*(..))
5                                     or execution(* *..*Service.batch*(..))
6                                     or execution(* *..*Service.create*(..))
7                                     or execution(* *..*Service.new*(..))) and !bean(logService)"
8             id="loggerPointcut" />

    (3)切面配置,聲明使用哪一個切面中的哪些方法使用何種通知方式在指定的切入點上織入到目標對象

<aop:aspect id="loggerAspect" ref="logger" order="1">
  <aop:around method="record" pointcut-ref="loggerPointcut" />
</aop:aspect>

      這裏的意思是使用logger切面,使用切面中的record方法以環繞通知的方式在loggerPointcut指定的切入點上織入到目標對象(Service對象)。jsp

  5.顯示全部日誌列表

    基本顯示是沒有什麼問題的,可是這裏使用了靜態調用的方法,能夠直接在jsp頁面調用某個類的靜態方法,這裏因爲可能會出現參數名稱過長的問題,必須在在這裏對顯示的長度進行限制。測試

    (1)com.kdyzm.utils.StringUtils類中定義靜態方法setTagContentLimitLength,默認長度爲15,也就是說最多隻是顯示15個字符。

 1 //經過jsp頁面的靜態調用能夠直接調用某個類的某個方法
 2     public static String setTagContentLimitLength(String string){
 3         int length=15;
 4         System.out.println("訪問了setTagContentLimitLength方法!"+string);
 5         if(string !=null){
 6             if(string.length()>length){
 7                 return string.substring(0,length)+"......";
 8             }else{
 9                 return string;
10             }
11         }
12         return "";
13     }

    (2)在jsp頁面中調用,調用新式:<s:property value="@類的全名@方法名(參數列表)"/>

<s:iterator value="%{#logList}" status="st">
  <tr>
    <td><s:property value="operator" /></td>
    <td><s:property value="operatorName" /></td>
    <td><s:property value="@com.kdyzm.utils.StringUtils@setTagContentLimitLength(operateParams)" /></td>
    <td><s:property value="operateResult" /></td>
    <td><s:property value="resultMessage" /></td>
    <td><s:date name="operatorDate" format="yyyy/MM/dd HH:mm:ss" /></td>
  </tr>
</s:iterator>

    (3)若是隻是以上兩步確定還會報錯,由於strutrs2默認禁用靜態調用,須要在配置文件中開啓,這裏爲了方便起見,直接使用了struts.properties進行了配置

 1 struts.i18n.encoding=UTF-8
 2 struts.action.extension=action,,
 3 struts.serve.static.browserCache=false
 4 struts.i18n.reload=true
 5 struts.configuration.xml.reload=true
 6 struts.devMode=true
 7 struts.ui.theme=simple
 8 struts.enable.DynamicMethodInvocation=true
 9 struts.multipart.maxSize=2097152
10 struts.ognl.allowStaticMethodAccess=true

3、測試日誌

 

  1.新建調查以後查看日誌:

  2.將新建的調查刪除掉以後:

相關文章
相關標籤/搜索