SSM中 实现日志记录(AOP+log4j2)

本人使用:

  • 集成开发环境:idea
  • 项目管理工具:maven
  • 数据库:oracle
  • 框架:Spring+SpringMVC+myBatis

主要步骤:

  1. 在pom.xml中引入插件依赖
  2. log4j2.xml文件配置
  3. web.xml文件配置
  4. 编写日志管理类LogInterceptor.class
  5. spring-mvc.xml中配置AOP【可以使用注解和自定义注解,我这使用的是xml】
  6. 在controller中编写一个运行时异常

具体实现:

  1,在pom.xml中引入插件依赖

<!--slf4j与log4j的桥接包,里面包括了:log4j-api,log4j-core和slf4j-api-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.10.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
    <version>2.10.0</version>
    <scope>runtime</scope>
</dependency>

<!--另外需要jar-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.1</version>
</dependency>

  2,log4j2.xml文件配置

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<configuration  status="info">
    <!-- 变量配置 应该是日志文件保存路径-->
    <Properties>
        <!-- (*必须,各应用需要修改) 部署应用的名称,命名规则 :全部小写字母、中短横线、数字,与微服务命名,disconf中命名一致 -->
        <property name="APPNAME">park-service</property>
        <!-- (各应用需要修改)日志文件本地存放目录路径 建议各个环境跟生产环境统一起来,方便维护 -->
        <!--sys:catalina.home  tomcat的根目录-->
        <Property name="logBaseFolder">${sys:catalina.home}/logs/zcrTest/</Property>
        <!-- *必须并强制遵守 日志文件的编码 -->
        <property name="log_charset">UTF-8</property>
        <!--输出日志格式-->
        <property name="log_pattern">
            %d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n
        </property>
    </Properties>

    <!--先定义所有的appender-->
    <appenders>
        <!--这个输出控制台的配置-->
        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式 %l :表示某个类-->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%t] %-5p %c{1}:%L - %msg%n"/>
        </console>

        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileInfo" fileName="${logBaseFolder}/${APPNAME}-info.log"
                     filePattern="${logBaseFolder}/%d{yyyy-MM}/${APPNAME}-info-%d{dd HH:mm:ss}.%i.log.gz">
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 日志输出格式 -->
            <PatternLayout charset="${log_charset}" pattern="${log_pattern}" />
            <!-- 以下是日志压缩包目录的建议格式名称 建议1天归档依次,压缩文件上线建议为200,这里预估每个磁盘存储空间200G左右,每个压缩包最大值200MB -->
            <Policies>
                <TimeBasedTriggeringPolicy  modulate="true" interval="1"/>
                <SizeBasedTriggeringPolicy size="20 MB"/>
            </Policies>
        </RollingFile>

        <RollingFile name="RollingFileError" fileName="${logBaseFolder}/${APPNAME}-error.log"
                     filePattern="${logBaseFolder}/%d{yyyy-MM}/${APPNAME}-error-%d{dd HH:mm:ss}.%i.log.gz">
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout charset="${log_charset}" pattern="${log_pattern}" />
            <Policies>
                <TimeBasedTriggeringPolicy  modulate="true" interval="1"/>
                <SizeBasedTriggeringPolicy size="20 MB"/>
            </Policies>
        </RollingFile>
    </appenders>

    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.springframework" level="INFO"/>
        <logger name="org.mybatis" level="INFO"/>

        <root level="all">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>

</configuration>

  3,web.xml文件配置

<!-- 日志记录 -->
<context-param>
    <param-name>log4jConfiguration</param-name>
    <param-value>classpath:log4j2.xml</param-value>
</context-param>
<!--动态修改log4j2.xml:容器会每60秒扫描log4j的配置文件-->
<context-param>
    <param-name>log4jRefreshInterval</param-name>
    <param-value>60000</param-value>
</context-param>

<!-- log4j2-begin: 监听器和过滤器-->
<listener>
    <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
</listener>

<filter>
    <filter-name>log4jServletFilter</filter-name>
    <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>log4jServletFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
<!-- log4j2-end -->

  4,编写日志管理类LogInterceptor.class

package com.zrkj.interceptor;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Component
public  class LogInterceptor {
    /**
     * 因为我这引入的是slf4j与log4j的桥接包,即可用log4j也可用slf4j输出日志
     * log4j:
     *      import org.apache.logging.log4j.LogManager;
     *      import org.apache.logging.log4j.Logger;
     * slf4j:
     *      import org.slf4j.Logger;
     *      import org.slf4j.LoggerFactory;
     */
    private static final Logger logger = LogManager.getLogger(LogInterceptor.class);
//    private static final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);

    String logStr=null;
//    //前置通知
//    public void before(JoinPoint jp){
//        System.out.println("==========aaaaaaaaaaaaaa");
//        logStr=jp.getTarget().getClass().getName()+"类的"
//                +jp.getSignature().getName()+"方法开始执行******Start******";
//        logger.info(logStr);
//    }
//      //最终通知
//    public void after(JoinPoint jp){
//        logStr=jp.getTarget().getClass().getName()+"类的"
//                +jp.getSignature().getName()+"方法执行结束******End******";
//        logger.info(logStr);
//    }
//      //异常抛出后通知
//    public void afterThrowing(JoinPoint call){
//        String className = call.getTarget().getClass().getName();
//        String methodName = call.getSignature().getName();
//        System.out.println(className+"."+methodName+"()方法抛出了异常...");
//    }
//     //后置通知
//    public void afterReturn(JoinPoint call){
//        String className = call.getTarget().getClass().getName();
//        String methodName = call.getSignature().getName();
//        System.out.println(className+"."+methodName+"()方法正常执行结束...");
//    }


    //用来做环绕通知的方法可以第一个参数定义为org.aspectj.lang.ProceedingJoinPoint类型
    public Object around(ProceedingJoinPoint call) throws Throwable {
        Object result = null;

        //取得类名和方法名
        String className = call.getTarget().getClass().getName();
        String methodName = call.getSignature().getName();

        //相当于前置通知
        logStr=className+"类的"+methodName+"方法开始执行******Start******";
        logger.info(logStr);

        try {
            result = call.proceed();
            //相当于后置通知
            logStr=className+"."+methodName+"()方法正常执行结束...";
            logger.info(logStr);

        } catch (Throwable e) {
            //相当于异常抛出后通知
            StackTraceElement stackTraceElement= e.getStackTrace()[e.getStackTrace().length-1];

            Object[] args=call.getArgs();

            logger.error("----------------------------------------------------------------------------------");
            logger.error ( "===执行{}类的{}()方法的{}行",className,methodName,stackTraceElement.getLineNumber());
            logger.error("===异常信息为:{}  ",e.fillInStackTrace().toString());
            logger.error("===参数信息为:{}  ",args);
            throw e;

        }finally{
            //相当于最终通知
            logStr=className+"类的" +methodName+"方法执行结束******End******";
            logger.info(logStr);
        }

        return result;
    }

}

  5,spring-mvc.xml中配置AOP,因为使用的是SSM框架,所以在SpringMvc容器中配置

<!-- 使用xml配置aop ,引入AOP的命名空间-->
<!-- 强制使用cglib代理,如果不设置,将默认使用jdk的代理,但是jdk的代理是基于接口的 -->
<aop:config proxy-target-class="true" />
<aop:config>
    <!--定义切面-->
    <aop:aspect id="logAspect" ref="logInterceptor">
        <!--定义切入点-->
        <aop:pointcut expression="execution(* com.zrkj.controller.*.*(..))"  id="logPointCut"/>
        <!--方法执行之前被调用执行的-->
        <!--<aop:before method="before" pointcut-ref="logPointCut"/>&lt;!&ndash;一个切入点的引用&ndash;&gt;-->
        <!--<aop:after method="after" pointcut-ref="logPointCut"/>&lt;!&ndash;一个切入点的引用&ndash;&gt;-->
        <!--<aop:after-throwing method="afterThrowing" pointcut-ref="logPointCut" />-->
        <!--<aop:after-returning method="afterReturn" pointcut-ref="logPointCut" />-->
        <aop:around method="around" pointcut-ref="logPointCut"/>
    </aop:aspect>
</aop:config>

  6,在controller中编写一个运行时异常

@PostMapping(value = "loginUser")
@ResponseBody
public void loginUser(String phone,String password,HttpServletResponse response){
    //1,验证该电话号码和密码是否正确
    Users users = userService.selectByPhoneAndPwd(phone,password);
    if(users!=null){
        //2.1 正确:修改token,last_login_time
        String token = userService.updateToLogin(users);
        System.out.println("制造一个运行时异常");
        int i = 1/0;//制造异常
        if(token!=null){
            //3.1 修改成功,登录
            printJson(response,result(200,"登录成功",token));
        }else{
            //3.2 修改失败,提示错误
            printJson(response,result(500,"登录异常,请重试"));
        }
    }else{
        //2.2 不正确:提示用户
        printJson(response,result(500,"手机号或密码不正确,请重试"));
    }
}

运行结果:

1,控制台显示:

 2,日志文件【tomcat的根目录】

 3,park-service-info.log内容:

4,park-service-error.log内容:

 ok。。。。

  • 9
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值