【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.将新建的调查删除掉以后:

相关文章
相关标签/搜索