原文: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);
}
}
}
}

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

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

    此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:20 ...

  2. slf4j+log4j在Java中实现日志记录

    小Alan今天来跟大家聊聊开发中既简单又常用但必不可少的一样东西,那是什么呢?那就是日志记录,日志输出,日志保存. 后面就统一用日志记录四个字来形容啦. 日志记录是项目的开发中必不可少的一个环节,特别 ...

  3. 在云环境上使用SLF4J对Java程序进行日志记录

    我开发了一个Java应用,部署到云环境上之后,用postman测试发现不能按照我期望的工作,但是返回的消息对我没有任何帮助. 因为部署在云端的应用很难像本地Java应用一样调试,所以我打算用SLF4J ...

  4. java中开源日志记录工具log4j

    日志:除了能记录异常信息,还可以记录程序正常运行时的关键信息. 使用log4j来进行日志文件记录经典步骤: 001.在项目中创建一个lib文件夹,然后将下载好的jar包copy到该文件夹下 002.对 ...

  5. mysql错误日志与通用日志

    错误日志 MySQL错误日志是记录MySQL 运行过程中较为严重的警告和错误信息,以及MySQL每次启动和关闭的详细信息. 1.错误日志路径查询 show variables like '%log_e ...

  6. Java日志记录的事儿

    一.java日志组件 1.common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的 ...

  7. Java日志记录的5条规则

    日志记录是在软件开发过程中常常需要考虑的关键因素. 当产品运行出错时,日志文件通常是我们进行错误分析的首要选择. 而且,在很多情况下,它们是我们手上唯一可以用来查明发生状况和问题根本原因的信息. 可见 ...

  8. 基于java.util.logging实现轻量级日志记录库(增加根据当前类class初始化,修复线程池模型(javaEE)下的堆栈轨迹顺序与当前调用方法不一致问题)

    前言: 本章介绍自己写的基于java.util.logging的轻量级日志记录库(baseLog). 该版本的日志记录库犹如其名,baseLog,是个实现日志记录基本功能的小库,适合小型项目使用,方便 ...

  9. Java 日志记录规则

    Java 日志记录规则 规则一:日志是面向读者的 我们不应该让无价值的信息使日志文件变得乱糟糟,比如说完整打印所有的实体字段. 通常,实体名字和其逻辑关键字足以识别在表格中的一条记录了. 规则二:匹配 ...

随机推荐

  1. HDU 4669 Mutiples on a circle 动态规划

    参考了官方题解给的方法: 对于处理循环,官方给了一种很巧妙的方法: #include <cstdio> #include <cstring> #include <cstd ...

  2. IO多路复用的理解

    最近看了<后台开发核心技术与应用实践>有关select.poll和epoll部分以及相关的一些博客,学习了这三个函数的使用方法和区别,写一个易理解的总结. IO多路复用 之前程序中使用的I ...

  3. POJ 3090 Visible Lattice Points | 其实是欧拉函数

    题目: 给一个n,n的网格,点可以遮挡视线,问从0,0看能看到多少点 题解: 根据对称性,我们可以把网格按y=x为对称轴划分成两半,求一半的就可以了,可以想到的是应该每种斜率只能看到一个点 因为斜率表 ...

  4. node_module删除

    https://segmentfault.com/q/1010000002972327 npm install rimraf -g rimraf node_modules

  5. Quartus 调试中的Nios 程序

    FPGA的程序通常包含硬件和软件两部分.正常情况下调试需要分别进行下载,过程繁琐. 为了将Nios II的软件程序包含到.sof文件中方便调试,可以在SOPC Builder中的RAM初始化为Nios ...

  6. Linux getcwd()的实现【转】

    转自:http://www.cnblogs.com/alan-forever/p/3721908.html 通过getcwd()可以获取当前工作目录. 1 #include <unistd.h& ...

  7. 移动web开发问题和优化小结

    之前在微信公众号上看到的一篇文章,直接给拷过来了....原文链接http://mp.weixin.qq.com/s/0LwTz-Mw2WumSztIrHucdQ 2.Meta标签 页面在手机上显示时, ...

  8. koa2-cors应答跨域请求实现

    var koa = require('koa'); var app = new koa(); var router = require('koa-router')(); // CORS是一个W3C标准 ...

  9. Shiro自定义realm实现密码验证及登录、密码加密注册、修改密码的验证

    一:先从登录开始,直接看代码 @RequestMapping(value="dologin",method = {RequestMethod.GET, RequestMethod. ...

  10. 中控考勤机WEB主动上报接收SERVER程序

    using System; using System.IO; using System.Net; using System.Text.RegularExpressions; namespace Con ...