首页 > 开发 > Java > 正文

JAVA实现通用日志记录方法

2024-07-13 10:08:38
字体:
来源:转载
供稿:网友

前言:

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

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


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表