欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JAVA实现通用日志记录方法

程序员文章站 2024-02-12 09:35:40
前言: 之前想在filter层直接过滤httpserverletrequest请求进行日志处理,但是之后再getwriter()的 时候报already been...

前言:

之前想在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);
      }
    }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。