• log4j


     Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。比如在这里定义了INFO级别,只有等于及高于这个级别的才进行处理,

       一、log4j使用步骤(重点在使用过程和初始化):
    1.将log4j.jar相关包放到jsp-examplesWEB-INFlib下;
    2.在classpath下面建立log4j.properties;
    3.完善log4j.properties内容:

     
    1. log4j.rootLogger=warn, stdout,A1   
    2.   
    3. #配置输出到控制台   
    4. log4j.appender.stdout=org.apache.log4j.ConsoleAppender   
    5. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout   
    6. log4j.appender.stdout.layout.ConversionPattern=(%F:%L) - %m%n   
    7.   
    8. log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender    
    9. log4j.appender.A1.layout=org.apache.log4j.HTMLLayout   
    10. log4j.appender.A1.File=${webappHome}/logs/${date}_log.html   
    11. log4j.appender.A1.MaxFileSize= 100KB  

       具体log4j.properties的配置方法参见http://hi.baidu.com/276668688/blog/item/e8d2fc1fdd8818c1a786698d.html

    4.初始化log4j的配置文件:有两种方法
       方法一:
        a.新建一个初始化类,一般用Servlet或过滤器Log4JInit.java

     
    1. package log4j;    
    2. import java.io.*;    
    3. import javax.servlet.*;    
    4. import javax.servlet.http.*;    
    5. import org.apache.log4j.*;   
    6.   
    7. public class Log4JInit extends HttpServlet {   
    8.    public void init() throws ServletException{   
    9.        String prefix = getServletContext().getRealPath("/");    
    10.        String test = getServletContext().getRealPath("");    
    11.        System.out.println(prefix);    
    12.        System.out.println(test);    
    13.          
    14.        System.setProperty("webappHome", test);   
    15.        String file = getServletConfig().getInitParameter("log4j-config-file");    
    16.        System.out.println(prefix+file);    
    17.        // 从Servlet参数读取log4j的配置文件    
    18.         if (file != null) {    
    19.          PropertyConfigurator.configure(prefix + file);    
    20.           
    21.        }   
    22.    }   
    23. }   

         注意:System.setProperty("webappHome", test);”这行代码要出现在“PropertyConfigurator.configure(prefix + file);”这行代码之前;因为这样才给"webappHome"设置值了,log4j.properties文件中的“log4j.appender.A1.file=${webappHome}/logs/tomcat_log_”中的“${webappHome}”这个环境变量才被赋值了,否则无法输出日志文件;

         b.配置web.xml文件

     
    1. <servlet>    
    2.    <servlet-name>log4jinit</servlet-name>    
    3.    <servlet-class>log4j.Log4JInit</servlet-class>    
    4.    <init-param>    
    5.        <param-name> log4j-config-file </param-name>    
    6.        <param-value>propertieslog4j.properties</param-value>    
    7.    </init-param>    
    8.    <load-on-startup>1</load-on-startup>    
    9. </servlet>  

         注意:上面的load-on-startup应设为1,以便在Web容器启动时即装入该Servlet。log4j.properties文件放在根的properties子目录中,也可以把它放在其它目录中。应该把.properties文件集中存放,这样方便管理。

       方法二、使用Spring已经写好的过滤器
          a.配置web.xml

     
    1. <context-param>  
    2.    <param-name>log4jConfigLocation</param-name>  
    3.    <param-value>/WEB-INF/config/log4j.properties</param-value>  
    4.  </context-param>     
    5.  <context-param>  
    6.    <param-name>log4jRefreshInterval</param-name>  
    7.    <param-value>6000</param-value>  
    8.  </context-param>  
    9.  <listener>  
    10.      <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>  
    11.  </listener>  

    5.在webapp中使用log4j
       主要建立一个属性private static Logger logger = Logger.getLogger(Log4jTest.class);

    public class Hello extends HttpServlet {
          private static Logger logger = Logger.getLogger(Hello.class);

          @Override
          protected void service(HttpServletRequest request,
          HttpServletResponse response) throws ServletException, IOException {
              System.out.println("Hello world!!");
              logger.debug("log4j加载成功!");
          }

    }

    6.在具体使用的时候如果触发了异常,就在生成以日期命名的html日志文件tomcat_log_2007-03-05.html了!
      这个日志的格式可以在log4j.properties里面配置.......

    ====================================================================================================================================================================================================
    常用log4j配置

    常用log4j配置,一般可以采用两种方式,.properties和.xml,下面举两个简单的例子:

    一、 log4j.properties

    ### 设置org.zblog域对应的级别INFO,DEBUG,WARN,ERROR和输出地A1,A2 ##
    log4j.category.org.zblog=ERROR,A1 
    log4j.category.org.zblog=INFO,A2 
    log4j.appender.A1=org.apache.log4j.ConsoleAppender 
    ### 设置输出地A1,为ConsoleAppender(控制台) ##
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout 
    ### 设置A1的输出布局格式PatterLayout,(可以灵活地指定布局模式)##
    log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n 
    ### 配置日志输出的格式##
    log4j.appender.A2=org.apache.log4j.RollingFileAppender 
    ### 设置输出地A2到文件(文件大小到达指定尺寸的时候产生一个新的文件)##
    log4j.appender.A2.File=E:/study/log4j/zhuwei.html 
    ### 文件位置##
    log4j.appender.A2.MaxFileSize=500KB 
    ### 文件大小##
    log4j.appender.A2.MaxBackupIndex=1 
    log4j.appender.A2.layout=org.apache.log4j.HTMLLayout 
    ##指定采用html方式输出

    二、 log4j.xml

    <?xml version="1.0" encoding="GB2312" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="org.zblog.all" class="org.apache.log4j.RollingFileAppender">
    <!-- 设置通道ID:org.zblog.all和输出方式:org.apache.log4j.RollingFileAppender -->
       <param name="File" value="E:/study/log4j/all.output.log" /><!-- 设置File参数:日志输出文件名 -->
       <param name="Append" value="false" /><!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->
       <param name="MaxBackupIndex" value="10" /> 
       <layout class="org.apache.log4j.PatternLayout">
           <param name="ConversionPattern" value="%p (%c:%L)- %m%n" /><!-- 设置输出文件项目和格式 -->
       </layout>
    </appender>
    <appender name="org.zblog.zcw" class="org.apache.log4j.RollingFileAppender">
       <param name="File" value="E:/study/log4j/zhuwei.output.log" />
       <param name="Append" value="true" />
       <param name="MaxFileSize" value="10240" /> <!-- 设置文件大小 -->
       <param name="MaxBackupIndex" value="10" /> 
       <layout class="org.apache.log4j.PatternLayout">
           <param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
       </layout>
    </appender>
    <logger name="zcw.log"> <!-- 设置域名限制,即zcw.log域及以下的日志均输出到下面对应的通道中 -->
       <level value="debug" /><!-- 设置级别 -->
       <appender-ref ref="org.zblog.zcw" /><!-- 与前面的通道id相对应 -->
    </logger>
    <root> <!-- 设置接收所有输出的通道 -->
       <appender-ref ref="org.zblog.all" /><!-- 与前面的通道id相对应 -->
    </root>
    </log4j:configuration>

    三、 配置文件加载方法:

    import org.apache.log4j.Logger;
    import org.apache.log4j.PropertyConfigurator;
    import org.apache.log4j.xml.DOMConfigurator;
    public class Log4jApp {
       public static void main(String[] args) {
           DOMConfigurator.configure("E:/study/log4j/log4j.xml");//加载.xml文件
           //PropertyConfigurator.configure("E:/study/log4j/log4j.properties");//加载.properties文件
           Logger log=Logger.getLogger("org.zblog.test");
           log.info("测试");
       }
    }

    四、 项目使用log4j

    在web 应用中,可以将配置文件的加载放在一个单独的servlet中,并在web.xml中配置该servlet在应用启动时候加载。对于在多人项目中,可以给每一个人设置一个输出通道,这样在每个人在构建Logger时,用自己的域名称,让调试信息输出到自己的log文件中。

    五、 常用输出格式

    # -X号:X信息输出时左对齐;
    # %p:日志信息级别
    # %d{}:日志信息产生时间
    # %c:日志信息所在地(类名)
    # %m:产生的日志具体信息
    # %n:输出日志信息换行

    ===============================================================================================

    log4j属性含义

    1)%r输出程序开始执行之后的微秒数
    2)%t输出当前线程的名称
    3)%-5p输出消息的层次。
    4)%c 输出category的名称
    5)-%m及s是日志消息本身,%n是换行符。
      当前在模式字符串中你可以嵌入任何想要输出的字符。
      模式字符串中的模式如下:
    %m:消息本身
    %p:消息的层次
    %r:从程序开始执行到当前日志产生时的时间间隔(微秒)
    %c:输出当前日志动作所在的category名称。例如:如果category名称是"a.b.c","%c{2}"将会输出"b.c". {2}意谓着输出“以点分隔开的category名称的后两个组件”,如果 {n}没有,将会输出整个category名称.
    %t:输出当前线程的名称
    %x:输出和当前线程相关联的NDC(具体解释见下文),尤其用到像java servlets这样的多客户多线程的应用中。
    %n:输出平台相关的换行符。
    %%:输出一个"%"字符
    %d:输出日志产生时候的日期,当然可以对日期的格式进行定制。例如:%d{HH:mm:ss,SSSS}或者是%d{dd MMM yyyy HH:mm:ss,SSSS},如果没有指定后面的格式,将会输出ISO8601的格式。
    %l:输出位置信息,相当于%C.%M(%F:%L)的组合。
    %C:输出日志消息产生时所在的类名,如果类名是“test.page.Class1”%C{1}表示输出类名"Class1",%C{2}输出"page.Class1",而%C则输出"test.page.Class1"。
    %M:输出日志消息产生时的方法名称
    %F:输出日志消息产生时所在的文件名称
    %L:输出代码中的行号
       可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
       1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
      2) %-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
      3) %.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
      4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉。
      4)%20.30c:
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    利用spring aop对日志进行管理,还是采用对比的方式进行,

    修改前:

    偶们的做法是在action里记录日志,注意这个日志是面向用户的日志,姑且称它为业务日志,至于后台日志,则在此文章中暂不考虑,基本是通过log4j打印到后台日志文件中。看下面一段代码: 


       1.  try {   
       2.     employeInfoManageService.saveEmploye(vo, authForm.getLoginName());   
       3.   
       4.     LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,   
       5.                 Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
       6.                             + "增加员工成功!");   
       7.     logService.saveLog(logVO);   
       8. } catch (Exception e) {   
       9.     log.error(e);   
      10.     LogVO logVO = new LogVO(Constants.LOG_LEVEL_ERROR,   
      11.             Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
      12.                             + "增加员工失败!");   
      13.     try {   
      14.         logService.saveLog(logVO);   
      15.     } catch (Exception e1) {   
      16.         log.error(e1);     
      17.     return messageForward("error", "alert.db.exception",      
      18.                     new Object[] {});   }   
      19. }  

    这段代码实际上已经将写日志的过程封装起来,开发者只需要传入3个参数:操作者、是前台系统还是后台系统、以及日志的错误等级,其它的如操作者机器IP, 日志时间等信息由系统统一设定,即使是这样,如果一个action里面有多个操作,代码看起来也非常臃肿,而且给开发者增加了工作量,既然有了aop,为 什么不利用一下?看下面改造的代码:

       1.  LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,   
       2.                 Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()   
       3.                             + "增加员工");   
       4. try {   
       5.     employeInfoManageService.saveEmploye(vo, authForm.getLoginName(), logVO);   
       6. } catch (Exception e) {   
       7.     log.error(e);   
       8.     return messageForward("error", "alert.db.exception",   
       9.                     new Object[] {});   
      10. }  
    既然是应用到aop,当然少不了aop的配置了,看下面的配置代码:
       1.  <aop:config>  
       2.     <aop:advisor pointcut="execution(* *..*Service.*(..))" advice-ref="txAdvice"/>  
         3.     <aop:advisor pointcut="execution(* *..*Service.save*(..)) || execution(* *..*Service.update*(..)) || execution(* *..*Service.delete*(..))" advice-ref="logAfterAdvice"/>  
       4. </aop:config>  
       5.   
       6. <bean id="logAfterAdvice" class="com.fudannet.framework.aop.LogAfterAdvice"/>  
    噢,aop:config的第一行是不是很熟悉啊,对,就是我们前面所配置的事务管理,这里,应该很清楚采用统一的aop配置的好处了吧。下面贴出logAfterAdvice的代码:
       1.  public void afterReturning(Object returnObj, Method method, Object[] args,   
       2.             Object targetObj) throws Throwable {   
       3.     if(method.getName().equals("saveLog")) return;   
       4.     for(int i = 0; i < args.length; i++){   
       5.         if(args[i] instanceof LogVO){   
       6.             log.info("开始写入日志......");   
       7.             writeLog((LogVO)args[i]);   
       8.         }   
       9.     }   
      10. }   
      11.   
      12. private void writeLog(LogVO vo){   
      13.     try {   
      14.         vo.setDescription(vo.getDescription() + "成功!");   
      15.         logService.saveLog(vo);   
      16.     } catch (RuntimeException e) {   
      17.         log.error(e);   
      18. }   
      19.   
      20. public void setLogService(LogService logService) {   
      21.     this.logService = logService;   
      22. }  

    这段代码应该很清楚了,将logService注入到拦截log的advice里,进行正确操作的日志记录,而afterReturning方法里 的第一行判断是由于logService里的写日志的方法是以save开始的。所以,如果拦截器拦截到此方法,不需要记录日志。

    正确的日志记录完,当然如果发生异常,我们需要记录操作的失败日志,当然了,我们也是通过aop来做,但是这次是通过实现exception advice来实现,代码如下: 

       1.  public void afterThrowing(Method method,Object[] args,Object target,Exception e) throws Throwable {   
       2.     if(method.getName().equals("saveLog")) return;   
       3.     for(int i = 0; i < args.length; i++){   
       4.         if(args[i] instanceof LogVO){   
       5.             log.info开始写入日志......");  
       6.             writeLog((LogVO)args[i]);  
       7.         }  
       8.     }  
       9. }  
      10.  
      11. private void writeLog(LogVO vo){  
      12.     try {  
      13.         vo.setDescription(vo.getDescription() + "失败!");   
      14.         logThrowService.saveLog(vo);   
      15.     } catch (RuntimeException e) {   
      16.         log.error(e);   
      17.     }   
      18. }   
      19.   
      20. public void setLogThrowService(LogService logThrowService) {   
      21.     this.logThrowService = logThrowService;   
      22. }  
    上面代码已经很好的说明了,如果发生exception的话,日志是怎么记录的,这里要提到的一点的是,异常的处理稍微有一些复杂,就拿本例的代码能看出 来,只要在service层有异常的时候,都会记录失败日志,实际上,很多时候,未必是这样,在某个模块,可能需要定义一种特殊的异常,而一旦这种异常发 生,则需要进入另外一个流程或者做一些特殊的处理,这个时候需要根据具体情况做一些变更,比如在上面代码我们加上:
       1.  public void afterThrowing(Method method,Object[] args,Object target,OrderException e) throws Throwable {   
       2.     log.info("......");   
       3.     //do something   
       4. }  
    则如果OrderException被抛出,就会到此方法中执行,而不会去写日志。
    --------------------------------------------------------------------------------
    其中的封装方式虽然一般,但是还是比较好的解决了问题!对于LogVO类我们可以把他继续扩展下去,比如设定访问用户,IP,seq文等.

    Spring AOP与log4j做简单的异常日志处理

    1.在网上看了不少例子,下面自己实践了一下。由于系统开发的时候忘记了对异常的日志处理,所以现在考虑加上,经过考虑决定使用spring的aop与log4j来做,这样做的好处就是我不用在每个类里面try{}catch或者抛出异常。因为类已经写了好多好多了。要是一个一个弄工作量是很大的 。 
    下面说下简单的实现过程,首先啊,在项目工程中的src目录中加入log4j.properties,内容如下: 

    ###设置日志级别### 
    ###这部分是将info信息输出到控制台### 
    log4j.rootLogger = info,stdout,F 
    log4j.appender.stdout = org.apache.log4j.ConsoleAppender 
    log4j.appender.stdout.Target = System.out 
    log4j.appender.stdout.layout = org.apache.log4j.PatternLayout 
    log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{1}:%L - %m%n 

    ###错误日志配置### 
    log4j.appender.F = org.apache.log4j.DailyRollingFileAppender 
    ##输出格式为自定义的HTML## 
    log4j.appender.F.layout = com.yale.sys.log.FormatHTMLLayout 
    log4j.appender.F.Threshold = ERROR 
    log4j.appender.F.Append=true 
    ##错误文件存放位置## 
    log4j.appender.F.File=error.html 
    ##每天滚动一次文件,即每天产生一个新的文件,文件名字eg:error.html.2012-06-18.html## 
    log4j.appender.F.DatePattern='.'yyyy-MM-dd'.html' 

    -------------------------------耐心的看下去 ----------------------------------- 
    其次呢,看上面红色那部分,因为是要将输出日志信息存储到html文件中,所以重写了下log4j中HTMLLayout类,代码片段: 

    Java代码  收藏代码
    1. package com.yale.sys.log;  
    2.   
    3. import java.text.SimpleDateFormat;  
    4. import org.apache.log4j.HTMLLayout;  
    5. import org.apache.log4j.Layout;  
    6. import org.apache.log4j.Level;  
    7. import org.apache.log4j.helpers.Transform;  
    8. import org.apache.log4j.spi.LocationInfo;  
    9. import org.apache.log4j.spi.LoggingEvent;  
    10. /** 
    11.  * log4j输出到html格式重写 
    12.  * @author yale 
    13.  * 
    14.  */  
    15. public class FormatHTMLLayout extends HTMLLayout {     
    16.         
    17.     public FormatHTMLLayout() {     
    18.     }     
    19. [/size]    
    20.     protected final int BUF_SIZE = 256;     
    21.     
    22.     protected final int MAX_CAPACITY = 1024;     
    23.     
    24.     static String TRACE_PREFIX = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";     
    25.     
    26.     // output buffer appended to when format() is invoked     
    27.     private StringBuffer sbuf = new StringBuffer(BUF_SIZE);     
    28.          
    29.     String title="系统错误日志";     
    30.     
    31.     /**   
    32.      * A string constant used in naming the option for setting the the HTML   
    33.      * document title. Current value of this string constant is <b>Title</b>.   
    34.      */    
    35.     public static final String TITLE_OPTION = "Title";     
    36.     
    37.     // Print no location info by default     
    38.     boolean locationInfo = true;     
    39.          
    40.     public String format(LoggingEvent event) {     
    41.         if (sbuf.capacity() > MAX_CAPACITY) {     
    42.             sbuf = new StringBuffer(BUF_SIZE);     
    43.         } else {     
    44.             sbuf.setLength(0);     
    45.         }     
    46.         sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);     
    47.              
    48.      
    49.         sbuf.append("<td>");     
    50.         sbuf.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));     
    51.         sbuf.append("</td>" + Layout.LINE_SEP);     
    52.     
    53.    
    54.         sbuf.append("<td title="级别">");     
    55.         if (event.getLevel().equals(Level.FATAL)) {     
    56.             sbuf.append("<font color="#339933">");     
    57.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
    58.             sbuf.append("</font>");     
    59.         } else if (event.getLevel().isGreaterOrEqual(Level.WARN)) {     
    60.             sbuf.append("<font color="#993300"><strong>");     
    61.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
    62.             sbuf.append("</strong></font>");     
    63.         } else {     
    64.             sbuf.append("<font color="green">");     
    65.             sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));     
    66.             sbuf.append("</font>");     
    67.         }     
    68.         sbuf.append("</td>" + Layout.LINE_SEP);     
    69.              
    70.   
    71.         if (locationInfo) {     
    72.             LocationInfo locInfo = event.getLocationInformation();     
    73.             sbuf.append("<td title="错误">");   
    74.             sbuf.append("<font color="red">");   
    75.             sbuf.append(Transform.escapeTags(locInfo.getFileName()));    
    76.             sbuf.append(':');    
    77.             sbuf.append(locInfo.getMethodName()).append("()方法中第");  
    78.             sbuf.append(locInfo.getLineNumber()).append("行出现错误");   
    79.             sbuf.append("</font>");   
    80.             sbuf.append("</td>" + Layout.LINE_SEP);    
    81.         }    
    82.             
    83.             
    84.   
    85.             
    86.         sbuf.append("<td title="错误信息">");     
    87.         sbuf.append(Transform.escapeTags(event.getRenderedMessage()));     
    88.         sbuf.append("</td>" + Layout.LINE_SEP);     
    89.         sbuf.append("</tr>" + Layout.LINE_SEP);     
    90.     
    91.         if (event.getNDC() != null) {     
    92.             sbuf.append("<tr><td bgcolor="#EEEEEE" style="font-size : xx-small;" colspan="6" title="Nested Diagnostic Context">");     
    93.             sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));     
    94.             sbuf.append("</td></tr>" + Layout.LINE_SEP);     
    95.         }     
    96.     
    97.         String[] s = event.getThrowableStrRep();     
    98.         if (s != null) {     
    99.             sbuf.append("<tr><td bgcolor="#993300" style="color:White; font-size : xx-small;" colspan="4">");     
    100.             appendThrowableAsHTML(s, sbuf);     
    101.             sbuf.append("</td></tr>" + Layout.LINE_SEP);     
    102.         }     
    103.         return sbuf.toString();     
    104.     }     
    105.     
    106.     private void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {     
    107.         if (s != null) {     
    108.             int len = s.length;     
    109.             if (len == 0)     
    110.                 return;     
    111.             sbuf.append(Transform.escapeTags(s[0]));     
    112.             sbuf.append(Layout.LINE_SEP);     
    113.             for (int i = 1; i < len; i++) {     
    114.                 sbuf.append(TRACE_PREFIX);     
    115.                 sbuf.append(Transform.escapeTags(s[i]));     
    116.                 sbuf.append(Layout.LINE_SEP);     
    117.             }     
    118.         }     
    119.     }     
    120.     
    121.     /**   
    122.      * Returns appropriate HTML headers.   
    123.      */    
    124.     public String getHeader() {     
    125.         sbuf.append("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">" + Layout.LINE_SEP);     
    126.         sbuf.append("<html>" + Layout.LINE_SEP);     
    127.         sbuf.append("<head>" + Layout.LINE_SEP);     
    128.         sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);     
    129.         sbuf.append("<style type="text/css">" + Layout.LINE_SEP);     
    130.         sbuf.append("<!--" + Layout.LINE_SEP);     
    131.         sbuf.append("body, table {font-family: '宋体',arial,sans-serif; font-size: 12px;}" + Layout.LINE_SEP);     
    132.         sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);     
    133.         sbuf.append("-->" + Layout.LINE_SEP);     
    134.         sbuf.append("</style>" + Layout.LINE_SEP);     
    135.         sbuf.append("</head>" + Layout.LINE_SEP);     
    136.         sbuf.append("<body bgcolor="#FFFFFF" topmargin="6" leftmargin="6">" + Layout.LINE_SEP);     
    137.         sbuf.append("<table cellspacing="0" cellpadding="4" border="1" bordercolor="#224466" width="100%">" + Layout.LINE_SEP);     
    138.         sbuf.append("<tr>" + Layout.LINE_SEP);     
    139.         sbuf.append("<th>执行时间</th>" + Layout.LINE_SEP);     
    140.         sbuf.append("<th>级别</th>" + Layout.LINE_SEP);     
    141.         if (locationInfo) {     
    142.             sbuf.append("<th>所在行</th>" + Layout.LINE_SEP);     
    143.         }     
    144.         sbuf.append("<th>错误信息</th>" + Layout.LINE_SEP);     
    145.         sbuf.append("</tr>" + Layout.LINE_SEP);     
    146.         sbuf.append("<br></br>" + Layout.LINE_SEP);     
    147.         return sbuf.toString();     
    148.     }     
    149.     
    150. }   


    ----------------------------耐心点往下看,就要没了 -------------------------------------------------- 
    再来就是错误文件error.html的存储位置,想要放在项目的WebRoot下,于是就写了个servlet,代码片段: 

    Java代码  收藏代码
    1. package com.yale.sys.log;  
    2. import java.io.FileNotFoundException;  
    3. import java.io.IOException;  
    4. import java.io.InputStream;  
    5. import java.util.Properties;  
    6.   
    7. import javax.servlet.Servlet;  
    8. import javax.servlet.ServletConfig;  
    9. import javax.servlet.ServletException;  
    10. import javax.servlet.http.HttpServlet;  
    11.   
    12.   
    13. import org.apache.log4j.PropertyConfigurator;  
    14.   
    15. /** 
    16.  * 初始化日志错误文件存放的路径 
    17.  */  
    18. public class LogFileSavePathServlet extends HttpServlet {  
    19.     private static final long serialVersionUID = 1L;  
    20.          
    21.     /** 
    22.      * @see HttpServlet#HttpServlet() 
    23.      */  
    24.     public LogFileSavePathServlet() {  
    25.         super();  
    26.         // TODO Auto-generated constructor stub  
    27.     }  
    28.   
    29.     /** 
    30.      * @see Servlet#init(ServletConfig) 
    31.      */  
    32.     public void init() throws ServletException {  
    33.         //获得系统的路径 /WebRoot  
    34.       
    35.         String rootPath = this.getServletContext().getRealPath("/");  
    36.         //获得log4j.properties的输入流  
    37.         InputStream is =this.getClass().getClassLoader().getResourceAsStream("log4j.properties");  
    38.         Properties prop = new Properties();       
    39.         try {  
    40.             prop.load(is);  
    41.         } catch (FileNotFoundException e) {  
    42.             e.printStackTrace();  
    43.         } catch (IOException e) {  
    44.             e.printStackTrace();  
    45.         }   
    46.          //设置日志文件的输出路径     
    47.         prop.setProperty("log4j.appender.F.File",rootPath+prop.getProperty("log4j.appender.F.File"));  
    48.         prop.setProperty("log4j.appender.F.DatePattern",rootPath+prop.getProperty("log4j.appender.F.DatePattern"));  
    49.         //加载配置项     
    50.         PropertyConfigurator.configure(prop);   
    51.         super.init();  
    52.     }  
    53.   
    54.   
    55.   
    56. }  


    注意啦,错误文件存储的路径不允许空格上面乱码七糟的,一定要注意哦。 
    写完这个servlet,我们不能忘记初始化,您说对不对啊,所以啊,web.xml就像下面这个样子了: 

    Java代码  收藏代码
    1. <!DOCTYPE web-app PUBLIC  
    2.  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
    3.  "http://java.sun.com/dtd/web-app_2_3.dtd" >  
    4. <web-app>  
    5. <!-- 日志文件存储路径初始化-->  
    6.     <servlet>  
    7.         <servlet-name>LogFileSavePathServlet</servlet-name>  
    8.         <display-name>LogFileSavePathServlet</display-name>  
    9.         <description></description>  
    10.     <servlet-class>com.peoplespot.sys.log.LogFileSavePathServlet</servlet-class>  
    11.         <load-on-startup>0</load-on-startup>   
    12.     </servlet>  
    13.       <servlet-mapping>  
    14.         <servlet-name>LogFileSavePathServlet</servlet-name>  
    15.         <url-pattern>/LogFileSavePathServlet</url-pattern>  
    16.     </servlet-mapping>  
    17. </web-app>  


    --------------------------------下面就开始和spring aop相关啦,看吧,看吧----------------------- 
    再一次首先,写一个系统异常日志拦截器类,您看: 

    Java代码  收藏代码
    1. package com.yale.sys.log;  
    2.   
    3. import org.apache.log4j.Logger;  
    4. import org.aspectj.lang.ProceedingJoinPoint;  
    5.   
    6. /** 
    7.  * 系统异常日志拦截器 
    8.  * @author yale 
    9.  * 
    10.  */  
    11. public class LogInterceptor {  
    12.       
    13.      static Logger logger = Logger.getLogger(LogInterceptor.class);  
    14.      public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {    
    15.          StringBuffer sb = new StringBuffer();  
    16.         try{    
    17.             Object result = joinPoint.proceed();    
    18.             return result;    
    19.         }catch(Exception e){    
    20.             sb.append("开始方法:"+joinPoint.getTarget().getClass() + "." + joinPoint.getSignature().getName()+ "()  ");  
    21.             sb.append("错误信息如下:["+e.getMessage()+"]");  
    22.             logger.error(sb.toString());   
    23.         }  
    24.         return "error";//因为用到了strut2,所以出现异常会返回到<result name="error">/erreo.jsp</result>这个页面中,当然啦,你也可以配置成全局的异常返回页。  
    25.     }    
    26. }  


    上面这个类,主要用到了aspectj中的ProceedingJoinPoint,支持的是<aop:around />。 
    类写完了,但是spring配置文件applicationContext.xml还没有搞啊,所以搞一下: 

    Java代码  收藏代码
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
    4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    5.     xsi:schemaLocation="   
    6.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
    7.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd   
    8.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
    9.   
    10. <!-- 配置日志拦截器 -->  
    11.     <bean id="logInterceptor" class="com.yale.sys.log.LogInterceptor"></bean>  
    12.       
    13.     <aop:config proxy-target-class="true">  
    14.         <aop:aspect id="logAspectSYS" ref="logInterceptor">  
    15.             <aop:around method="invoke" pointcut="execution(public * com.yale.live.action..*.*(..))" />  
    16.         </aop:aspect>  
    17.             <aop:aspect id="logAspectDNA" ref="logInterceptor">  
    18.             <aop:around method="invoke" pointcut="execution(public * com.yale.sys.action..*.*(..))" />  
    19.         </aop:aspect>  
    20.     </aop:config>  
    21. </beans>  


    小插曲:看见<aop:config>节点中proxy-target-class="true"这个属性了吧,当我不加的时候,启动项目,访问action代码,就比如是LoginAction中的login()方法,不幸的是他报错了,类似于 
    java.lang.NoSuchMethodException: $Proxy54.login(),可是回去一看,有写过这个login方法啊, $Proxy54又是怎么回事呢?因为你加入aop功能了,可是spring是这么干的,默认啊实现的是接口注入,关联的实现类。这里实现注入类,所以出现了异常。要怎么解决呢,于是就要加上proxy-target-class="true"属性,接下来启动项目吧,你会发现不幸的事情又发生了,又报错了: 
    org.springframework.aop.framework.AopConfigException: Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces. 
    提示的很明显,少jar包了,所以就加吧,但是加jar的时候也要注意了: 
    需要导入的jar包是cglib-nodep-2.1_3.jar(这里面整合了asm)或者(asm-2.2.3.jar和cglib-2.2.jar 。)因为cglib需要asm的支持。 
    到此完成。 
    启动项目开始运行吧,模拟了下一个异常,输出到html最终这样啦: 


     
  • 相关阅读:
    《修改代码的艺术》读书笔记
    《软件架构师的12项修炼》阅读笔记2
    《软件架构师的12项修炼》阅读笔记1
    python 包
    《编程珠玑》阅读笔记1
    Darknet和YOLO的区别和关系
    darknet
    yolov3
    软件质量属性
    酷客 机器学习十讲(一)机器学习介绍
  • 原文地址:https://www.cnblogs.com/wnlja/p/3912821.html
Copyright © 2020-2023  润新知