JAVA实现通用日志记录
原文: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实现通用日志记录的更多相关文章
- Java学习-007-Log4J 日志记录配置文件详解及实例源代码
此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:20 ...
- slf4j+log4j在Java中实现日志记录
小Alan今天来跟大家聊聊开发中既简单又常用但必不可少的一样东西,那是什么呢?那就是日志记录,日志输出,日志保存. 后面就统一用日志记录四个字来形容啦. 日志记录是项目的开发中必不可少的一个环节,特别 ...
- 在云环境上使用SLF4J对Java程序进行日志记录
我开发了一个Java应用,部署到云环境上之后,用postman测试发现不能按照我期望的工作,但是返回的消息对我没有任何帮助. 因为部署在云端的应用很难像本地Java应用一样调试,所以我打算用SLF4J ...
- java中开源日志记录工具log4j
日志:除了能记录异常信息,还可以记录程序正常运行时的关键信息. 使用log4j来进行日志文件记录经典步骤: 001.在项目中创建一个lib文件夹,然后将下载好的jar包copy到该文件夹下 002.对 ...
- mysql错误日志与通用日志
错误日志 MySQL错误日志是记录MySQL 运行过程中较为严重的警告和错误信息,以及MySQL每次启动和关闭的详细信息. 1.错误日志路径查询 show variables like '%log_e ...
- Java日志记录的事儿
一.java日志组件 1.common-logging common-logging是apache提供的一个通用的日志接口.用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的 ...
- Java日志记录的5条规则
日志记录是在软件开发过程中常常需要考虑的关键因素. 当产品运行出错时,日志文件通常是我们进行错误分析的首要选择. 而且,在很多情况下,它们是我们手上唯一可以用来查明发生状况和问题根本原因的信息. 可见 ...
- 基于java.util.logging实现轻量级日志记录库(增加根据当前类class初始化,修复线程池模型(javaEE)下的堆栈轨迹顺序与当前调用方法不一致问题)
前言: 本章介绍自己写的基于java.util.logging的轻量级日志记录库(baseLog). 该版本的日志记录库犹如其名,baseLog,是个实现日志记录基本功能的小库,适合小型项目使用,方便 ...
- Java 日志记录规则
Java 日志记录规则 规则一:日志是面向读者的 我们不应该让无价值的信息使日志文件变得乱糟糟,比如说完整打印所有的实体字段. 通常,实体名字和其逻辑关键字足以识别在表格中的一条记录了. 规则二:匹配 ...
随机推荐
- 【Android】实验7 BindService模拟通信 截止提交日期2016.5.3
实验7 BindService模拟通信 [目的] 实现启动端和BindService之间的双向通信 [要求] 1) 实现从启动端传递一个数据至BindService端: 2) 实现使用Bind ...
- hdu 1969 Pie (二分法)
Pie Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...
- 发现JDK的3个bug
1.Annotation引用非空enum数组返回空数组 首次发现时的环境:JDK 1.8 首次发现所在项目:APIJSON 测试用例: public enum RequestRole { /**未登录 ...
- 洛谷 P1606 [USACO07FEB]荷叶塘Lilypad Pond 解题报告
P1606 [USACO07FEB]荷叶塘Lilypad Pond 题目描述 FJ has installed a beautiful pond for his cows' aesthetic enj ...
- 1031. 高一学堂 (at)
题目描述 在美丽的中山纪念中学里面,有一座高一学堂.所谓山不在高,有仙则名:水不在深,有龙则灵.高一学堂,因为有了yxr,就成了现在这个样子 = =. 由于yxr的语言太过雷人,每次他发微往往都会有一 ...
- jenkins 自定义主题
一.概述 jenkins更新后,页面css布局都已改变,我现在用的jenkins.css, ( png图片需自定义) #page-body { background-image:url(http:// ...
- makefile语法
makefile很重要 什么是makefile? 或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional 的程 ...
- js j将数字每三位用逗号隔开的方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- AngularJS 作用域与数据绑定机制
AngularJS 简介 AngularJS 是由 Google 发起的一款开源的前端 MVC 脚本框架,既适合做普通 WEB 应用也可以做 SPA(单页面应用,所有的用户操作都在一个页面中完成).与 ...
- WebApi初探之路由配置
本文介绍了ASP.NET Web API路由HTTP请求控制器. 如果你熟悉ASP.NET MVC,Web API路由是和MVC路由非常相似的.主要差别是Web API使用HTTP方法而不是URI路径 ...