当前位置: 首页 > news >正文

Spring Boot AOP记录用户操作日志

一、添加依赖

在Spring框架中,使用AOP配合自定义注解可以方便的实现用户操作的监控。首先搭建一个基本的Spring Boot Web环境开启Spring Boot,然后引入必要依赖:

<!-- aop依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.22</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

二、自定义注解

定义一个方法级别的@Log注解,用于标注需要监控的方法:

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceLog{Stringvalue()default"";}

三、创建库表和实体

3.1 建表

在数据库中创建一张sys_log表,用于保存用户的操作日志,数据库采用mysql5.7.23

droptableifexists`sys_log`;createtable`sys_log`(`id`int(20)notnullauto_incrementcomment'id',`username`varchar(50)charactersetutf8collateutf8_general_cinullcomment'用户名',`operation`varchar(50)charactersetutf8collateutf8_general_cinullcomment'用户操作',`time`int(11)nullcomment'响应时间',`method`varchar(200)charactersetutf8collateutf8_general_cinullcomment'请求方法',`params`varchar(500)charactersetutf8collateutf8_general_cinullcomment'请求参数',`ip`varchar(64)charactersetutf8collateutf8_general_cinullcomment'ip地址',`create_time`DATETIMEnullcomment'创建时间',primarykey(`id`)usingbtree)engine=innodbauto_increment=1characterset=utf8collate=utf8_general_ci row_format=dynamic;

3.2 创建实体

库表对应的实体:

@Getter@SetterpublicclassSysLogimplementsSerializable{privatestaticfinallongserialVersionUID=-6309732882044872293L;privateIntegerid;privateStringusername;privateStringoperation;privateIntegertime;privateStringmethod;privateStringparams;privateStringip;@JsonFormat(timezone="GMT+8",pattern="yyyy-MM-dd HH:mm:ss")privateDatecreateTime;}

四、保存日志的方法

为了方便,这里直接使用Spring JdbcTemplate来操作数据库。定义一个SysLogDao接口,包含一个保存操作日志的抽象方法:

publicinterfaceSysLogDao{voidsaveSysLog(SysLogsyslog);}

其实现方法:

@RepositorypublicclassSysLogDaoImplimplementsSysLogDao{@AutowiredprivateJdbcTemplatejdbcTemplate;@OverridepublicvoidsaveSysLog(SysLogsyslog){StringBuffersql=newStringBuffer("insert into sys_log ");sql.append("(username,operation,time,method,params,ip,create_time) ");sql.append("values(:username,:operation,:time,:method,");sql.append(":params,:ip,:createTime)");NamedParameterJdbcTemplatenpjt=newNamedParameterJdbcTemplate(this.jdbcTemplate.getDataSource());npjt.update(sql.toString(),newBeanPropertySqlParameterSource(syslog));}}

五、切面和切点

定义一个LogAspect类,使用@Aspect标注让其成为一个切面,切点为使用@Log注解标注的方法,使用@Around环绕通知:

@Aspect@ComponentpublicclassLogAspect{@AutowiredprivateSysLogDaosysLogDao;@Pointcut("@annotation(com.wno704.boot.aspect.Log)")publicvoidpointcut(){}@Around("pointcut()")publicObjectaround(ProceedingJoinPointpoint){Objectresult=null;longbeginTime=System.currentTimeMillis();try{// 执行方法result=point.proceed();}catch(Throwablee){e.printStackTrace();}// 执行时长(毫秒)longtime=System.currentTimeMillis()-beginTime;// 保存日志saveLog(point,time);returnresult;}privatevoidsaveLog(ProceedingJoinPointjoinPoint,longtime){MethodSignaturesignature=(MethodSignature)joinPoint.getSignature();Methodmethod=signature.getMethod();SysLogsysLog=newSysLog();LoglogAnnotation=method.getAnnotation(Log.class);if(logAnnotation!=null){// 注解上的描述sysLog.setOperation(logAnnotation.value());}// 请求的方法名StringclassName=joinPoint.getTarget().getClass().getName();StringmethodName=signature.getName();sysLog.setMethod(className+"."+methodName+"()");// 请求的方法参数值Object[]args=joinPoint.getArgs();// 请求的方法参数名称LocalVariableTableParameterNameDiscovereru=newLocalVariableTableParameterNameDiscoverer();String[]paramNames=u.getParameterNames(method);if(args!=null&&paramNames!=null){Stringparams="";for(inti=0;i<args.length;i++){params+=" "+paramNames[i]+": "+args[i];}sysLog.setParams(params);}// 获取requestHttpServletRequestrequest=HttpContextUtils.getHttpServletRequest();// 设置IP地址sysLog.setIp(IPUtils.getIpAddr(request));// 模拟一个用户名sysLog.setUsername("mrbird");sysLog.setTime((int)time);sysLog.setCreateTime(newDate());// 保存系统日志sysLogDao.saveSysLog(sysLog);}}

六、测试

TestController:

@RestControllerpublicclassTestController{@Log("执行方法一")@GetMapping("/one")publicvoidmethodOne(Stringname){}@Log("执行方法二")@GetMapping("/two")publicvoidmethodTwo()throwsInterruptedException{Thread.sleep(2000);}@Log("执行方法三")@GetMapping("/three")publicvoidmethodThree(Stringname,Stringage){}}

最终项目目录如下图所示:

启动项目,分别访问:

http://localhost:8080/web/one?name=wno704

http://localhost:8080/web/two

http://localhost:8080/web/three?name=wno704&age=28

查询数据库:

http://www.cnnetsun.cn/news/4106466.html

相关文章:

  • 嵌入式开发入门:从LED与传感器控制到物联网系统构建
  • 基于EasyUI与KnockoutJS的通用分页查询与数据导出ViewModel设计
  • 广州微闻网络AI落地技术实践:Agent定制、Token供应与云计算全栈技术解析
  • 在线教育平台开课前三网验收:视频域、直播与 API
  • 多个人同时提问但位置有限
  • UnrealPakViewer 完整上手教程:三步摸清任意 UE4 Pak 文件内部结构
  • Think-a-Tron Mini:从复古玩具到DIY电子项目,探索伪随机数生成与电路设计
  • 102.环形缓冲区之读指针与写指针:原理、实现与完整代码
  • BBDown完整使用手册:让哔哩哔哩视频下载变成一行命令的事
  • 计算机网络学习笔记(六)---网络层与IP协议
  • AI家庭机器人技术解析:从ROS架构到嵌入式开发实践
  • 从零构建智能体:基于Coze平台的可视化AI助手开发实战
  • C语言基础知识-学习笔记
  • 基于大模型与持续学习的人形机器人叠衣系统实战解析
  • 光度立体成像全栈拆解 | 多视角光影法向量求解+梯度积分重建,助力漫反射工件微划痕凹坑褶皱高速高精度2.5D缺陷检测
  • 深挖C语言:深入理解指针(2)
  • 线性可调双路输出电源:原理、设计与噪声抑制全解析
  • 当“让用户满意”变成“让用户更不满意”:AI防御误触发的根源与破解之道
  • OptiCommPy模拟光马赫-曾德尔调制器
  • CAD绘图效率提升:从练习图29拆解系统绘图流程与高效命令组合
  • snpe-VGG案例(uv环境-全流程 教程)
  • 实测通勤15分钟出片全流程,不用电脑不用大内存手机
  • 基于树莓派的智能交互装置:从硬件搭建到AI对话引擎实现
  • 企业信息管理:从“罗生门”到一致性回应的体系构建
  • OPOR-Bench: Evaluating Large Language Models on Online Public Opinion Report Generation
  • AE字体动画核心技巧:从基础动画器到批量预设应用
  • 2026毕业论文AI生成工具打分:6款谁更靠谱
  • 百度网盘Mac版免费提速完整方案:1个开源插件解锁SVIP高速下载(附避坑指南)
  • 使用CD4051实现8路模拟信号复用:硬件设计与Arduino编程指南
  • 用Python打造智能双模机械键盘:从硬件焊接、CircuitPython编程到高级功能实现