Spring Boot AOP记录用户操作日志
程序员文章站
2022-04-14 16:32:18
在Spring框架中,使用AOP配合自定义注解可以方便的实现用户操作的监控。首先搭建一个基本的Spring Boot Web环境开启Spring Boot,然后 引入必要依赖: org.springframework.boot
在spring框架中,使用aop配合自定义注解可以方便的实现用户操作的监控。首先搭建一个基本的spring boot web环境开启spring boot,然后
引入必要依赖:
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-jdbc</artifactid> </dependency> <!-- aop依赖 --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-aop</artifactid> </dependency> <!-- mysql驱动 --> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <version>5.1.41</version> </dependency> <!-- druid数据源驱动 --> <dependency> <groupid>com.alibaba</groupid> <artifactid>druid-spring-boot-starter</artifactid> <version>1.1.10</version> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency>
自定义注解
定义一个方法级别的@log
注解,用于标注需要监控的方法:
@target(elementtype.method) @retention(retentionpolicy.runtime) public @interface log { string value() default ""; }
创建库表和实体
在数据库中创建一张sys_log表,用于保存用户的操作日志
实体:
public class syslog implements serializable { private integer id; private string username; private string operation; private integer time; private string method; private string params; private string ip; private date createtime; ............
dao:
public interface syslogdao { void savesyslog(syslog syslog); }
@repository public class syslogdaoimpl implements syslogdao { @autowired private jdbctemplate jdbctemplate; @override public void savesyslog(syslog syslog) { system.out.println(syslog); stringbuffer sql = new stringbuffer("insert into sys_log "); sql.append("(id,username,operation,time,method,params,ip,create_time) "); sql.append("values(null,?,?,?,?,?,?,?)"); string sql2=sql.tostring(); jdbctemplate.update(sql2,syslog.getusername(),syslog.getoperation(),syslog.gettime(),syslog.getmethod(),syslog.getparams(),syslog.getip(),syslog.getcreatetime()); jdbctemplate.update(sql2); } }
aspect:
@aspect @component public class logaspect { @autowired private syslogdao syslogdao; @pointcut("@annotation(com.lc.aop.annotation.log)") public void pointcut() { } @around("pointcut()") public object around(proceedingjoinpoint point) { object result = null; long begintime = system.currenttimemillis(); try { // 执行方法 result = point.proceed(); } catch (throwable e) { e.printstacktrace(); } // 执行时长(毫秒) long time = system.currenttimemillis() - begintime; // 保存日志 savelog(point, time); return result; } private void savelog(proceedingjoinpoint joinpoint, long time) { methodsignature signature = (methodsignature) joinpoint.getsignature(); method method = signature.getmethod(); syslog syslog = new syslog(); log logannotation = method.getannotation(log.class); if (logannotation != null) { // 注解上的描述 syslog.setoperation(logannotation.value()); } // 请求的方法名 string classname = joinpoint.gettarget().getclass().getname(); string methodname = signature.getname(); syslog.setmethod(classname + "." + methodname + "()"); // 请求的方法参数值 object[] args = joinpoint.getargs(); // 请求的方法参数名称 localvariabletableparameternamediscoverer u = new localvariabletableparameternamediscoverer(); string[] paramnames = u.getparameternames(method); if (args != null && paramnames != null) { string params = ""; for (int i = 0; i < args.length; i++) { params += " " + paramnames[i] + ": " + args[i]; } syslog.setparams(params); } // 获取request httpservletrequest request = httpcontextutils.gethttpservletrequest(); // 设置ip地址 syslog.setip(iputils.getipaddr(request)); // 模拟一个用户名 syslog.setusername("mrbird"); syslog.settime((int) time); syslog.setcreatetime(new date()); // 保存系统日志 syslogdao.savesyslog(syslog); } }
controller:
@restcontroller public class testcontroller { @log("执行方法一") @getmapping("/one") public void methodone(string name) { } @log("执行方法二") @getmapping("/two") public void methodtwo() throws interruptedexception { thread.sleep(2000); } @log("执行方法三") @getmapping("/three") public void methodthree(string name, string age) { } }
工具类:
public class iputils { /** * 获取ip地址 * * 使用nginx等反向代理软件, 则不能通过request.getremoteaddr()获取ip地址 * 如果使用了多级反向代理的话,x-forwarded-for的值并不止一个,而是一串ip地址,x-forwarded-for中第一个非unknown的有效ip字符串,则为真实ip地址 */ public static string getipaddr(httpservletrequest request) { string ip = request.getheader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsignorecase(ip)) { ip = request.getheader("proxy-client-ip"); } if (ip == null || ip.length() == 0 || "unknown".equalsignorecase(ip)) { ip = request.getheader("wl-proxy-client-ip"); } if (ip == null || ip.length() == 0 || "unknown".equalsignorecase(ip)) { ip = request.getremoteaddr(); } return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; } }
public class httpcontextutils { public static httpservletrequest gethttpservletrequest() { return ((servletrequestattributes) requestcontextholder.getrequestattributes()).getrequest(); } }
application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.driver spring.datasource.url=jdbc:mysql://localhost:3306/springboot spring.datasource.username=root spring.datasource.password=123456
项目结构:
访问后:
上一篇: JS高级---函数声明和函数表达式的区别
下一篇: 对Java入口函数的认识