前言:

之前想在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项目如何引入日志生成器及其日志分级
# 返回值
# 的是
# 遍历
# 吃了
# 才发现
# 不能用
# 转换成
# 第二步
# 第三步
# 大家多多
# 则将
# 为空
# 第四步
# 客户端
# 准备用
# 情况下
# 完成了
# 就好像
# 请求者
# 就没了
相关文章:
义乌企业网站制作公司,请问义乌比较好的批发小商品的网站是什么?
专业商城网站制作公司有哪些,pi商城官网是哪个?
如何快速选择适合个人网站的云服务器配置?
如何快速搭建高效WAP手机网站吸引移动用户?
建站主机SSH密钥生成步骤及常见问题解答?
网站制作多少钱一个,建一个论坛网站大约需要多少钱?
如何在Golang中实现微服务服务拆分_Golang微服务拆分与接口管理方法
清单制作人网站有哪些,近日“兴风作浪的姑奶奶”引起很多人的关注这是什么事情?
网站制作软件免费下载安装,有哪些免费下载的软件网站?
linux top下的 minerd 木马清除方法
网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?
无锡制作网站公司有哪些,无锡优八网络科技有限公司介绍?
怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?
东莞专业网站制作公司有哪些,东莞招聘网站哪个好?
如何高效配置香港服务器实现快速建站?
网站制作大概要多少钱一个,做一个平台网站大概多少钱?
建站与域名管理如何高效结合?
零服务器AI建站解决方案:快速部署与云端平台低成本实践
如何用PHP工具快速搭建高效网站?
寿县云建站:智能SEO优化与多行业模板快速上线指南
如何高效配置IIS服务器搭建网站?
建站之星伪静态规则如何正确配置?
c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】
如何通过PHP快速构建高效问答网站功能?
高端网站建设与定制开发一站式解决方案 中企动力
如何确保西部建站助手FTP传输的安全性?
如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南
音乐网站服务器如何优化API响应速度?
建站主机功能解析:服务器选择与快速搭建指南
建站主机与虚拟主机有何区别?如何选择最优方案?
购物网站制作公司有哪些,哪个购物网站比较好?
如何在宝塔面板中修改默认建站目录?
济南网站制作的价格,历城一职专官方网站?
mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?
网站专业制作公司,网站编辑是做什么的?好做吗?工作前景如何?
如何选择适合PHP云建站的开源框架?
如何在阿里云完成域名注册与建站?
ui设计制作网站有哪些,手机UI设计网址吗?
如何在服务器上三步完成建站并提升流量?
车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?
黑客如何通过漏洞一步步攻陷网站服务器?
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
建站之星如何防范黑客攻击与数据泄露?
如何选择长沙网站建站模板?H5响应式与品牌定制哪个更优?
合肥做个网站多少钱,合肥本地有没有比较靠谱的交友平台?
我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?
建站之星代理费用多少?最新价格详情介绍
官网网站制作腾讯审核要多久,联想路由器newifi官网
,南京靠谱的征婚网站?
如何在阿里云通过域名搭建网站?
*请认真填写需求信息,我们会在24小时内与您取得联系。