当前位置: 移动技术网 > IT编程>开发语言>Java > JAVA实现通用日志记录方法

JAVA实现通用日志记录方法

2019年07月22日  | 移动技术网IT编程  | 我要评论

前言:

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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网