JAVA实现通用日志记录

原文:http://blog.csdn.net/jinzhencs/article/details/51882751

前言: 
之前想在filter层直接过滤httpServerletRequest请求进行日志处理,但是之后再getWriter()的 时候报 
already been call异常。查了下,才发现原来流形式的只能读取一次。。就好像食物,吃了就没了。。 
所以在filter和inteceptor里面是没法通过获取request的流来进行日志记录的。

于是还是准备用通用的方法:controller层aop进行切面记录日志。

使用Aop记录操作日志

第一步:添加Aop

/**
 * 统一日志处理Handler
 * @author Mingchenchen
 *
 */
public class LogAopHandler {
    @Autowired
    private AuditLogDao auditLogDao;

    /**
     * controller层面记录操作日志
     * 注意此处是aop:around的 因为需要得到请求前的参数以及请求后接口返回的结果
     * @throws Throwable
     */
    public Object doSaveLog(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature method = (MethodSignature) joinPoint.getSignature();
        String methodName = method.getName();
        Object[] objects = joinPoint.getArgs();
        String requestBody = null;
        if (objects!=null && objects.length>0) {
            for (Object object : objects) {
                if (object == null) {
                    requestBody = null;//POST接口参数为空 比如删除XXX
                }else if (object instanceof String) {
                    requestBody = (String) object;//有些接口直接把参数转换成对象了
                }else {
                    requestBody = JSONObject.toJSONString(object);
                }
            }
        }

        //只记录POST方法的日志
        boolean isNeedSaveLog = false;
        //此处不能用getAnnotationByType 是JAVA8的特性,因为注解能够重名,所以得到的是数组
        RequestMapping annotation = method.getMethod().getAnnotation(RequestMapping.class);
        for (RequestMethod requestMethod : annotation.method()) {
            if (requestMethod==RequestMethod.POST) {
                isNeedSaveLog = true;
            }
        }

        JSONObject requestBodyJson = null;
        try {
            requestBodyJson = JSONObject.parseObject(requestBody);
        } catch (Exception e) {
            //do nothing 即POST请求没传body
        }
        HttpServletRequest request = RequestContextUtil.getRequestByCurrentContext();
        String userName = RequestContextUtil.getUserNameByCurrentContext();
        if (StringUtil.isEmpty(userName)) {
            try {
                userName = DmsCache.get(requestBodyJson.getString("userName")).getName();
            } catch (Exception e) {
                userName = RequestContextUtil.getAsynUserInfoByAutoDeploy().getName();
            }
        }

        //得到request的参数后让方法执行它
        //注意around的情况下需要返回result 否则将不会返回值给请求者
        Object result = joinPoint.proceed(objects);
        try {
            JSONObject resultJson = JSONObject.parseObject(result.toString());
            if (isNeedSaveLog) {//如果是POST请求 则记录日志
                LogTypeEnum logTypeEnum = LogTypeEnum.getDesByMethodName(methodName);
                if (logTypeEnum != null) {
                    AuditLogEntity auditLogEntity = new AuditLogEntity();
                    auditLogEntity.setUuid(StringUtil.createRandomUuid());
                    auditLogEntity.setOperator(userName);
                    auditLogEntity.setRequestIp(request.getRemoteAddr());
                    auditLogEntity.setRequestUrl(request.getRequestURI().replace("/cloud-master", ""));
                    auditLogEntity.setEventType(logTypeEnum.getKey());
                    auditLogEntity.setEventDesc(logTypeEnum.getDescription());
                    auditLogEntity.setRequest(requestBody);
                    int isSuccess = "200".equals(resultJson.getString("code")) ? 1 : 0;
                    auditLogEntity.setSuccessFlag(isSuccess);
                    auditLogEntity.setResponse(result.toString());
                    auditLogEntity.setCreateTime(new Date());
                    auditLogDao.insert(auditLogEntity);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

第二步:在spring的xml中声明

<!-- 记录操作日志 -->
    <bean id="operationLogAop" class="com.ming.learn.core.aop.LogAopHandler"/>
     <aop:config>
       <aop:aspect id="logAOP" ref="operationLogAop">
         <aop:pointcut id="target" expression="execution(* com.ming.learn..*Controller.*(..))"/>
         <aop:around method="doSaveLog" pointcut-ref="target"/>
       </aop:aspect>
     </aop:config>

如此一来,核心步骤就完成了,剩下的就是自己组装需要记录的东西了。

第三步:写Dao、Entity、Mapper

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * 日志审计
 * @author Mingchenchen
 *
 */
@Table(name="audit_log")
public class AuditLogEntity {
    @Id
    private String uuid;

    @Column(name="event_type")
    private String eventType;//事件类型

    @Column(name="event_desc")
    private String eventDesc;//事件中文描述

    @Column(name="operator")
    private String operator;//操作者

    @Column(name="request_ip")
    private String requestIp;//客户端地址

    @Column(name="request_url")
    private String requestUrl;//请求地址

    @Column(name="request")
    private String request;//请求body

    @Column(name="response")
    private String response;//请求返回值

    @Column(name="create_time")
    private Date createTime;

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public String getEventType() {
        return eventType;
    }

    public void setEventType(String eventType) {
        this.eventType = eventType;
    }

    public String getEventDesc() {
        return eventDesc;
    }

    public void setEventDesc(String eventDesc) {
        this.eventDesc = eventDesc;
    }

    public String getOperator() {
        return operator;
    }

    public void setOperator(String operator) {
        this.operator = operator;
    }

    public String getRequestIp() {
        return requestIp;
    }

    public void setRequestIp(String requestIp) {
        this.requestIp = requestIp;
    }

    public String getRequestUrl() {
        return requestUrl;
    }

    public void setRequestUrl(String requestUrl) {
        this.requestUrl = requestUrl;
    }

    public String getRequest() {
        return request;
    }

    public void setRequest(String request) {
        this.request = request;
    }

    public String getResponse() {
        return response;
    }

    public void setResponse(String response) {
        this.response = response;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}

第四步:根据Controller的方法名称定制响应的事件类型

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 操作日志类型
 * @author Mingchenchen
 *
 */
public enum LogTypeEnum {
    //用户
    COMMON_LOGIN("login","login","登录");
    //其他

    private String methodName;//方法名称与controller一致
    private String key;//保存到数据库的事件类型
    private String description;//保存到数据库的描述
    private LogTypeEnum(String methodName,String key,String description){
        this.methodName = methodName;
        this.key = key;
        this.description = description;
    }
    public String getMethodName() {
        return methodName;
    }
    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * 根据方法名返回
     * @param methodName
     * @return
     */
    public static LogTypeEnum getDesByMethodName(String methodName){
        return innerMap.map.get(methodName);
    }

    /**
     * 内部类 用户保存所有的enum 无须通过Enum.values()每次遍历
     * @author Mingchenchen
     *
     */
    private static class innerMap{
        private static Map<String, LogTypeEnum> map = new ConcurrentHashMap<>(128);

        static{
            //初始化整个枚举类到Map
            for (LogTypeEnum logTypeEnum : LogTypeEnum.values()) {
                map.put(logTypeEnum.getMethodName(), logTypeEnum);
            }
        }
    }
}
时间: 2024-10-08 10:28:11

JAVA实现通用日志记录的相关文章

Java学习-007-Log4J 日志记录配置文件详解及实例源代码

此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:2015-1-30 13:54:02,请知悉. 所需的 jar 包下载链接为:http://yunpan.cn/cKE56sxqtQCfP  访问密码 63d8 有关 Log4J 日志文件中日志级别及文件配置的详细情况,在 Log4J 的配置文件(xml.properties)中有详细的介绍,敬请参阅!

通用日志记录(java)

使用AOP记录操作日志信息 添加一个统一处理日志AOP /** * 统一日志处理Handler * @author Mingchenchen * */ public class LogAopHandler { @Autowired private AuditLogDao auditLogDao; /** * controller层面记录操作日志 * 注意此处是aop:around的 因为需要得到请求前的参数以及请求后接口返回的结果 * @throws Throwable */ public Ob

java中开源日志记录工具log4j

日志:除了能记录异常信息,还可以记录程序正常运行时的关键信息. 使用log4j来进行日志文件记录经典步骤: 001.在项目中创建一个lib文件夹,然后将下载好的jar包copy到该文件夹下 002.对已经copy过来的jar包,点击右键,然后执行下图操作, 项目中就会多出一个引入外部Library的项目 003.在src目录下创建一个名称为log4j.properties文件 004.编写,粘贴已经写好的配置文件内容,编码方式可以做下修正.对配置文件点击右键→属性→other→utf-8,然后应

Java日志记录的事儿

一.java日志组件 1.common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的logging, common-logging会通过动态查找的机制,在程序运行时自动找出真正使用的日志库.但由于它使用了ClassLoader寻找和载入底层的日 志库, 导致了象OSGI这样的框架无法正常工作,由于其不同的插件使用自己的ClassLoader. OSGI的这种机制保证了插件互相独立,

Java日志记录的5条规则

日志记录是在软件开发过程中常常需要考虑的关键因素. 当产品运行出错时,日志文件通常是我们进行错误分析的首要选择. 而且,在很多情况下,它们是我们手上唯一可以用来查明发生状况和问题根本原因的信息. 可见,正确记录需要的信息是极其重要的. 以下5条日志规则,让我们可以检查和改进在代码中操作日志记录的方式. 同时也请注意,我们既不会讨论怎么配置一个日志引擎,也不会相互比较. 规则1.日志是面向读者的 日志消息不仅要对书写(日志)代码的人有意义,也应该对日志文件的读者有意义. 这似乎是一条很明显但却经常

日志记录的作用和方法 java

程序中记录日志一般有两个目的:Troubleshooting和显示程序运行状态.好的日志记录方式可以提供我们足够多定位问题的依据.日志记录大家都会认为简单,但如何通过日志可以高效定位问题并不是简单的事情.这里列举下面三个方面的内容,辅以代码示例,总结如何写好日志,希望对他人有所启发和帮助: 怎样记日志可以方便Troubleshooting 程序运行状态可以记哪些 应该避免怎样的日志方式 怎样记日志可以方便Troubleshooting? 1. 对外部的调用封装 程序中对外部系统与模块的依赖调用前

java动态代理详解,并用动态代理和注解实现日志记录功能

动态代理的概念 动态代理是程序在运行过程中自动创建一个代理对象来代替被代理的对象去执行相应的操作,例如, 我们有一个已经投入运行的项目中有一个用户DAO类UserDao用来对User对象进行数据库的增删改查操作,但是有一天,要求在对用户的增删改查操作时记录相应的日志,这是怎么办呢?难道我们去直接修改UserDao的源代码,然后在UserDao的每个方法中加入日志记录功能,这显然是不合理的,它违背了java的OCP原则,即对修改关闭对扩张开放.比如改现有的代码如下: 接口类 public inte

java Web应用配置log4j日志记录

第一步:首先建立一个WEB工程,去log4j官网下log4j的JAR包导入到工程的lib目录下 第二步:在src目录下建一个log4j.properties 文件,文件命名可以由自己,只是记加载时候和这里名字一致就行: log4j.properties  里边的内容如下: ### set log levels ### log4j.rootLogger = debug,stdout,E log4j.appender.stdout = org.apache.log4j.ConsoleAppender

java日志记录之Logger.getLogger()和LogFactory.getLog()的区别

最近研究项目代码时发现同一个项目用到关于日志的两种不同写法: Logger.getLogger()和LogFactory.getLog()的区别 1.Logger.getLogger()是使用log4j的方式记录日志:API文档 2.LogFactory.getLog()则来自apache的common-logging包.API文档 根据不同的性质,日志信息通常被分成不同的级别,从低到高依次是:"调试( DEBUG )""信息( INFO )""警告( W