1.日誌管理是一種典型的系統級別的應用,很是適合使用spring AOP實現。java
2.使用日誌管理的目的:對系統修改的動做進行記錄,好比對權限、角色、用戶的寫操做、修改操做、刪除操做等spring
3.肯定使用的通知方式:使用環繞通知。複習一下環繞通知,所謂環繞通知實際上就是AOP代理對接口中聲明方法的執行進行攔截,在執行方法以前或者以後進行一些操做,在日誌管理功能模塊中,咱們對Service接口中聲明的方法進行攔截,若是是對系統進行的修改操做的方法,則將方法執行以後就須要將相關信息保存下來方便之後查看,好比是誰登錄的系統進行的修改(最重要),執行的是什麼方法,方法的參數是什麼,執行成功額仍是失敗了,方法的返回值是什麼,執行方法的時間是什麼等等。express
4.日誌管理功能在系統中的體現:單擊導航菜單中的"日誌管理"超連接,查看全部的系統的變動歷史記錄。apache
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 }
日誌切面提供了保存保存日誌的詳細方法(通知),該方法將會攔截目標方法的執行而且記錄該方法執行過程當中的詳細信息。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 }
<bean id="logger" class="com.kdyzm.aspect.Logger"> <property name="logService" ref="logService"></property> </bean>
注意這些方法都在事務通知上有定義,可是不能直接使用事務通知中的聲明,由於還有不一樣之處:必須刨除掉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" />
<aop:aspect id="loggerAspect" ref="logger" order="1"> <aop:around method="record" pointcut-ref="loggerPointcut" /> </aop:aspect>
這裏的意思是使用logger切面,使用切面中的record方法以環繞通知的方式在loggerPointcut指定的切入點上織入到目標對象(Service對象)。jsp
基本顯示是沒有什麼問題的,可是這裏使用了靜態調用的方法,能夠直接在jsp頁面調用某個類的靜態方法,這裏因爲可能會出現參數名稱過長的問題,必須在在這裏對顯示的長度進行限制。測試
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 }
<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>
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