说明

最近有个项目需要增加日志记录功能,因为这个项目原来是基于spring开发的,在查阅了相关资料以后,我采用了spring aop的方式实现该需求,然后就有了本篇文章。

思路

我这边需求是这样的:要统计各个接口的调用次数,然后我想加上客户端ip、请求参数、返回结果等信息,而我的接口都是通过controller实现的,所以从原理上讲就是要通过aop拦截所有controller,实现日志记录。项目本身用到了swagger,每个接口都有ApiOperation注解,所以我的实现方式就变成了拦截ApiOperation注解,为什么要拦截ApiOperation,因为ApiOperation注解有对每个接口的描述信息,当然也是因为每个接口方法上都有ApiOperation注解,当然如果你愿意你也可以拦截RequestMapping,下面是我的aop实现:

package com.mytest.aop;

import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date; /**
* @program: publicCoreServer
* @description: aop 打印 接收参数日志
* @author: liu yan
* @create: 2019-11-21 09:15
*/ @Aspect
@Component//定义一个切面
public class LogRecordAspect {
private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class); private static final String UTF_8 = "utf-8"; @Autowired
private UpmsLogService upmsLogService; @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
public void logPointCut() { } @Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime; //保存日志
saveSysLog(point, beginTime, time, result); return result;
} /**
* 日志记录
*
* @param joinPoint
* @param beginTime 开始时间
* @param spendTime 用时
* @param result 返回结果
*/
private void saveSysLog(ProceedingJoinPoint joinPoint,long beginTime, long spendTime, Object result) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod(); UpmsLog upmsLog = new UpmsLog();
upmsLog.setLogId(UUIDUtil.getUUID());
upmsLog.setAppId("wx"); ApiOperation annotation = method.getAnnotation(ApiOperation.class);
if(annotation != null){
//注解上的描述
upmsLog.setDescription(annotation.value());
} //请求的参数
Object[] args = joinPoint.getArgs();
String params = JSON.toJSONString(args[0]);
upmsLog.setParameter(params); // 返回结果
String resultJson = JSON.toJSONString(result);
upmsLog.setResult(resultJson); //获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//设置IP地址
upmsLog.setIp(IPUtils.getIpAddr(request));
// 请求路径
String requestUrl = request.getRequestURL().toString();
upmsLog.setUrl(requestUrl);
String requestURI = request.getRequestURI();
upmsLog.setUri(requestURI); // 请求头
String agentString = request.getHeader("User-Agent");
upmsLog.setUserAgent(agentString); // 请求方式
String authType = request.getMethod();
upmsLog.setMethod(authType); //用户名
Subject subject = SecurityUtils.getSubject();
if (subject.isAuthenticated()) {
Object userId = subject.getPrincipal();
upmsLog.setUsername(userId.toString());
upmsLog.setUserId(userId.toString());
} String path = request.getContextPath();
String baseURL = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
upmsLog.setBasePath(baseURL); // 开始时间
upmsLog.setStartTime(beginTime);
// 用时
upmsLog.setSpendTime(spendTime);
upmsLog.setCreatetime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
//保存系统日志
logger.info("日志信息:"+ upmsLog);
upmsLogService.saveLog(upmsLog);
} }

我的spring xml的配置如下:

 <context:component-scan
base-package="com.mytest.aop">
<context:include-filter type="annotation"
expression="org.aspectj.lang.annotation.Aspect" />
</context:component-scan> <!-- 设置AOP为自动代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

我的controller(部分)

@Api(value = "info", description = "相关控制器")
@Controller
@RequestMapping(value = "/test/getInfo")
public class InfoController { @Autowired
private InfoService infoService; @ApiOperation(value = "aop日志测试")
@RequestMapping("/getInfo")
@ResponseBody
public AjaxJson getInfo(String datas) {
JSONObject data = JSONObject.parseObject(datas); AjaxJson result = infoService.getInfo(data.toString());
return result;
}
}

其他的servic、entity等代码这里就不放了,有需求的小伙伴可以留言。

解释

这里简单说明下,aop的实现中最核心最重要的就是切点的定义,也就是如下代码:

 @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
public void logPointCut() { }

上面定义了类型为注解的切点,切点方法及方式如下:

 @Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime; //保存日志
saveSysLog(point, beginTime, time, result); return result;
}

我们aop作用的方式是Around,也就是环绕,为啥要用这个,因为我们要拿到方法的入参和返回值,所以这个就是最优解。对于aop,好多知识点早都忘记了,而且平时基本没有用到过,后面一定要抽时间做一次研究,深入探讨一下。

最近确实没有太多时间来学习,而且晚上回来太晚了,家里也没有电脑,只能利用周末时间来学习、整理和总结。再过段时间,尽量保证每天能抽时间写点东西,谢谢大家支持,晚安!

基于aop的日志记录方式实现的更多相关文章

  1. 033 SSM综合练习09--数据后台管理系统--基于AOP的日志处理

    1.数据库与表结构 (1)日志表信息描述sysLog (2)Sql语句 CREATE TABLE sysLog ( id ) DEFAULT SYS_GUID () PRIMARY KEY, visi ...

  2. Logstash+ Kafka基于AOP 实时同步日志到es

    Logstash是一个开源数据收集引擎,具有实时管道功能.Logstash可以动态地将来自不同数据源的数据统一起来,并将数据标准化到你所选择的目的地,logstash丰富的插件(logstash-in ...

  3. 基于AOP和ThreadLocal实现的一个简单Http API日志记录模块

    Log4a 基于AOP和ThreadLocal实现的一个简单Http API日志记录模块 github地址 : https://github.com/EalenXie/log4a 在API每次被请求时 ...

  4. 基于AOP和ThreadLocal实现日志记录

    基于AOP和ThreadLocal实现的一个日志记录的例子 主要功能实现 : 在API每次被请求时,可以在整个方法调用链路中记录一条唯一的API请求日志,可以记录请求中绝大部分关键内容.并且可以自定义 ...

  5. Spring基于AOP的事务管理

                                  Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...

  6. 基于AOP的MVC拦截异常让代码更优美

    与asp.net 打交道很多年,如今天微软的优秀框架越来越多,其中微软在基于mvc的思想架构,也推出了自己的一套asp.net mvc 框架,如果你亲身体验过它,会情不自禁的说‘漂亮’.回过头来,‘漂 ...

  7. 从壹开始前后端分离 40 || 完美基于AOP的接口性能分析

    旁白音:本文是不定时更新的.net core,当前主线任务的Nuxt+VueAdmin教程的 nuxt.js 之 tibug项目已上线,大家可以玩一玩:http://123.206.33.109:70 ...

  8. Spring Boot 使用 Aop 实现日志全局拦截

    前面的章节我们学习到 Spring Boot Log 日志使用教程 和 Spring Boot 异常处理与全局异常处理,本章我们结合 Aop 面向切面编程来实现全局拦截异常并记录日志. 在 Sprin ...

  9. Spring AOP 完成日志记录

    Spring AOP 完成日志记录 http://hotstrong.iteye.com/blog/1330046

随机推荐

  1. Anaconda 安装 pytorch报错解决方法

    一.安装Pytorch: # -c 指定用pytorch镜像源下载软件conda install pytorch torchvision cpuonly -c pytorch 报错: 二.配置: ch ...

  2. CSP-S2019退役记。。。

    模拟赛的时候题目就比较迷,感觉不像联赛难度的. 考完正式赛才觉得这TM算个P. Day1: 写密码的监考同学的蜜汁字体让我傻了. 0和O是一样的,9和q是一样的,1和l是一样的-- 又没有冷静下来发现 ...

  3. 如何更改PHPCMS网站后台标题(title)

    打开PHPCMS安装目录,选择phpcms 然后选择Languages目录,打开. 打开目录后,选择zh-cn目录,选择admin.lang.php用editPlus打开,将第九行后面的引号中的内容换 ...

  4. js事件---同一个事件实现全选与反选功能

    背景: 点击头部按钮,实现全选与反选功能 1.绑定事件,把当前勾选状态传递给方法 $event <el-checkbox v-model="ModelCheckAll" cl ...

  5. CEF的备忘笔记

    CEF: Chromium Embeded Framewrok;  (Chromium嵌入式框架)可以在PC(Linux,MacOS,Windows)上把Chromium的内核嵌入到应用程序的框架: ...

  6. [CSP-S模拟测试]:游戏(最短路)

    题目传送门(内部题35) 输入格式 第一行,两个正整数$X,Y$.第二行,三个非负整数$A,B,C$.第三行,一个正整数$N$.接下来$N$行,每行两个非负整数$x_i,y_i$. 输出格式 一行,一 ...

  7. 59、salesforce实现数据的批量处理

    批处理,往自己的邮箱发一封邮件,批处理采用异步的处理方式处理数据,最多可以处理5000万条数据 global with sharing class MerchandiseBatch implement ...

  8. CentOS安装 netdata 实时监视 Linux 系统性能

    作为一个 Linux 系统的管理员,为了随时了解系统资源的占用情况,有必要使用专门的系统监视工具.如果你需要对 Linux 系统.应用程序.SNMP 设备进行实时的性能监视,那么 netdata 这个 ...

  9. 【C++第一个Demo】---控制台RPG游戏2【通用宏、背包类】

    [通用 ]--一些游戏中常用的宏.函数和枚举 #ifndef _MARCO_H_ #define _MARCO_H_ //------------------------常用系统库---------- ...

  10. JOGL教程

    本章介绍了OpenGL,Java OpenGL绑定(GL4java,LWJGL,JOGL)和JOGL比其他的OpenGL的优点. Java支持OpenGL(JOGL)是近期在Java OpenGL图形 ...