全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

JAVA实现通用日志记录方法

前言:

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

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


# java实现日志记录  # JAVA日志记录  # java实现随机数生成器  # java项目打包成可执行jar用log4j将日志写在jar所在目录操作  # java启动jar包将日志打印到文本的简单操作  # Java中 log4j日志级别配置详解  # Java实时监控日志文件并输出的方法详解  # Java项目如何引入日志生成器及其日志分级  # 返回值  # 的是  # 遍历  # 吃了  # 才发现  # 不能用  # 转换成  # 第二步  # 第三步  # 大家多多  # 则将  # 为空  # 第四步  # 客户端  # 准备用  # 情况下  # 完成了  # 就好像  # 请求者  # 就没了 


相关文章: 昆明高端网站制作公司,昆明公租房申请网上登录入口?  如何在建站宝盒中设置产品搜索功能?  宝塔建站助手安装配置与建站模板使用全流程解析  定制建站如何定义?其核心优势是什么?  宝塔面板创建网站无法访问?如何快速排查修复?  网站制作说明怎么写,简述网页设计的流程并说明原因?  招贴海报怎么做,什么是海报招贴?  制作国外网站的软件,国外有哪些比较优质的网站推荐?  官网网站制作腾讯审核要多久,联想路由器newifi官网  如何通过VPS建站无需域名直接访问?  网站制作网站,深圳做网站哪家比较好?  网站制作培训多少钱一个月,网站优化seo培训课程有哪些?  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  如何做静态网页,sublimetext3.0制作静态网页?  商务网站制作工程师,从哪几个方面把握电子商务网站主页和页面的特色设计?  如何制作网站标识牌,动态网站如何制作(教程)?  如何快速搭建二级域名独立网站?  网站制作费用多少钱,一个网站的运营,需要哪些费用?  如何在宝塔面板中创建新站点?  ,南京靠谱的征婚网站?  网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?  外贸公司网站制作哪家好,maersk船公司官网?  小建面朝正北,A点实际方位是否存在偏差?  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  代刷网站制作软件,别人代刷火车票靠谱吗?  Python如何创建带属性的XML节点  清单制作人网站有哪些,近日“兴风作浪的姑奶奶”引起很多人的关注这是什么事情?  上海网站制作网站建设公司,建筑电工证网上查询系统入口?  建站之星云端配置指南:模板选择与SEO优化一键生成  用v-html解决Vue.js渲染中html标签不被解析的问题  如何解决VPS建站LNMP环境配置常见问题?  网站专业制作公司有哪些,做一个公司网站要多少钱?  东莞专业网站制作公司有哪些,东莞招聘网站哪个好?  如何设计高效校园网站?  已有域名能否直接搭建网站?  巅云智能建站系统:可视化拖拽+多端适配+免费模板一键生成  潮流网站制作头像软件下载,适合母子的网名有哪些?  娃派WAP自助建站:免费模板+移动优化,快速打造专业网站  c# 在高并发下使用反射发射(Reflection.Emit)的性能  西安专业网站制作公司有哪些,陕西省建行官方网站?  如何访问已购建站主机并解决登录问题?  电脑免费海报制作网站推荐,招聘海报哪个网站多?  深圳防火门网站制作公司,深圳中天明防火门怎么编码?  中山网站推广排名,中山信息港登录入口?  微课制作网站有哪些,微课网怎么进?  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  建站之星备案流程有哪些注意事项?  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  如何快速上传建站程序避免常见错误?  外汇网站制作流程,如何在工商银行网站上做外汇买卖? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。