SpringBoot入门系列~使用AOP切面记录用户的访问日志

 

 

使用Aop切面记录用户访问日志

1、记录日志目的

  网站一般都会记录某个用户的访问信息,分析某个用户经常访问那些业务,针对用户的访问量进行一下营销策略、还可以记录用户的日活量和月活量,针对一下活跃的用户进行进行一些优惠的活动

2、AOP的基本介绍

  AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,实现AOP记录日志主要有以下几个步骤

  使用@Aspect注解将一个java类定义为切面类
      使用@Pointcut定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等根据需要在切入点不同位置的切入内容
        使用@Before在切入点开始处切入内容
        使用@After在切入点结尾处切入内容
        使用@AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
        使用@Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容
        使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑

  具体步骤如下    

3、创建 日志实体

  1 package com.sun.spring.boot.pojo;
  2 
  3 import java.util.Date;
  4 
  5 import javax.persistence.Column;
  6 import javax.persistence.Entity;
  7 import javax.persistence.GeneratedValue;
  8 import javax.persistence.Id;
  9 import javax.persistence.Table;
 10 
 11 /**
 12  * 系统日志实体Bean
 13  * @ClassName: SysLogInfoBean  
 14  * @author sunt  
 15  * @date 2017年11月10日 
 16  * @version V1.0
 17  */
 18 @Entity
 19 @Table(name = "F_SYS_LOG")
 20 public class SysLogInfoBean {
 21 
 22     /**
 23      * 主键
 24      */
 25     @Id
 26     @GeneratedValue
 27     private Integer Id;
 28     
 29     /**
 30      * 用户名
 31      */
 32     @Column(name = "F_USER_NAME",length = 20)
 33     private String userName;
 34     
 35     /**
 36      * 访问的IP
 37      */
 38     @Column(name = "F_IP",length = 20)
 39     private String ip;
 40     
 41     /**
 42      * 访问接口名称
 43      */
 44     @Column(name = "F_METHOD_NAME", length = 100)
 45     private String methodNmae;
 46     
 47     /**
 48      * 访问的类名称
 49      */
 50     @Column(name = "F_CLASS_NAME", length = 200)
 51     private String className;
 52     
 53     /**
 54      * 访问时间
 55      */
 56     @Column(name = "F_CREATE_DATE")
 57     private Date createDate;
 58     
 59     /**
 60      * 主机名
 61      */
 62     @Column(name = "F_REMOTE_HOST", length = 50)
 63     private String remoteHost;
 64     
 65     /**
 66      * 访问的URL
 67      */
 68     @Column(name = "F_URL", length = 50)
 69     private String url;
 70 
 71     public Integer getId() {
 72         return Id;
 73     }
 74 
 75     public void setId(Integer id) {
 76         Id = id;
 77     }
 78 
 79     public String getUserName() {
 80         return userName;
 81     }
 82 
 83     public void setUserName(String userName) {
 84         this.userName = userName;
 85     }
 86 
 87     public String getIp() {
 88         return ip;
 89     }
 90 
 91     public void setIp(String ip) {
 92         this.ip = ip;
 93     }
 94 
 95     public String getMethodNmae() {
 96         return methodNmae;
 97     }
 98 
 99     public void setMethodNmae(String methodNmae) {
100         this.methodNmae = methodNmae;
101     }
102 
103     public String getClassName() {
104         return className;
105     }
106 
107     public void setClassName(String className) {
108         this.className = className;
109     }
110 
111     public Date getCreateDate() {
112         return createDate;
113     }
114 
115     public void setCreateDate(Date createDate) {
116         this.createDate = createDate;
117     }
118 
119     public String getRemoteHost() {
120         return remoteHost;
121     }
122 
123     public void setRemoteHost(String remoteHost) {
124         this.remoteHost = remoteHost;
125     }
126 
127     public String getUrl() {
128         return url;
129     }
130 
131     public void setUrl(String url) {
132         this.url = url;
133     }
134     
135 }

4、创建日志dao接口

 1 package com.sun.spring.boot.dao;
 2 
 3 import org.springframework.data.jpa.repository.JpaRepository;
 4 import org.springframework.stereotype.Repository;
 5 
 6 import com.sun.spring.boot.pojo.SysLogInfoBean;
 7 
 8 /**
 9  * 系统日志Dao接口
10  * @ClassName: ISysLogInfoDao  
11  * @author sunt  
12  * @date 2017年11月10日 
13  * @version V1.0
14  */
15 @Repository
16 public interface ISysLogInfoDao extends JpaRepository<SysLogInfoBean, Integer> {
17 
18 }

5、创建日志记录Service接口和实现

 1 package com.sun.spring.boot.service;
 2 
 3 import com.sun.spring.boot.pojo.SysLogInfoBean;
 4 
 5 /**
 6  * 日志service接口
 7  * @ClassName: ISysLogInfoService  
 8  * @author sunt  
 9  * @date 2017年11月10日 
10  * @version V1.0
11  */
12 public interface ISysLogInfoService {
13 
14     /**
15      * 保存日志信息
16      * @Title: insertSysLog 
17      * @author sunt  
18      * @date 2017年11月10日
19      * @param bean 日志实体
20      * @return void
21      */
22     void insertSysLog(SysLogInfoBean bean);
23 }
 1 package com.sun.spring.boot.service.impl;
 2 
 3 import org.apache.log4j.Logger;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.stereotype.Service;
 6 
 7 import com.sun.spring.boot.dao.ISysLogInfoDao;
 8 import com.sun.spring.boot.pojo.SysLogInfoBean;
 9 import com.sun.spring.boot.service.ISysLogInfoService;
10 
11 /**
12  * 系统日志Service实现
13  * @ClassName: SysLogInfoServiceImpl  
14  * @author sunt  
15  * @date 2017年11月10日 
16  * @version V1.0
17  */
18 @Service
19 public class SysLogInfoServiceImpl implements ISysLogInfoService{
20 
21     private Logger logger = Logger.getLogger(SysLogInfoServiceImpl.class);
22     
23     @Autowired
24     private ISysLogInfoDao sysLogInfoDao;
25     
26     @Override
27     public void insertSysLog(SysLogInfoBean bean) {
28         logger.info("++++++++执行日志入库操作++++++++++");
29         sysLogInfoDao.save(bean);
30     }
31 
32 }

6、创建日志切面类

具体逻辑代码里面都有详细的注释

 1 package com.sun.spring.boot.aspect;
 2 
 3 import java.util.Date;
 4 
 5 import javax.servlet.http.HttpServletRequest;
 6 
 7 import org.apache.log4j.Logger;
 8 import org.aspectj.lang.JoinPoint;
 9 import org.aspectj.lang.annotation.After;
10 import org.aspectj.lang.annotation.AfterReturning;
11 import org.aspectj.lang.annotation.Aspect;
12 import org.aspectj.lang.annotation.Before;
13 import org.aspectj.lang.annotation.Pointcut;
14 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.stereotype.Component;
16 import org.springframework.web.context.request.RequestContextHolder;
17 import org.springframework.web.context.request.ServletRequestAttributes;
18 
19 import com.sun.spring.boot.pojo.SysLogInfoBean;
20 import com.sun.spring.boot.service.ISysLogInfoService;
21 
22 /**
23  * 发送请求的切面入口类,需要在Spring中注入
24  * @ClassName: RequestAsprct  
25  * @author sunt  
26  * @date 2017年11月10日 
27  * @version V1.0
28  */
29 @Component
30 @Aspect
31 public class RequestAsprct {
32 
33     private Logger logger = Logger.getLogger(RequestAsprct.class);
34     
35     @Autowired
36     private ISysLogInfoService sysLogInfoService;
37     
38     /**
39      * 记录日志,定义切入点:指定那些业务(业务对应的方法)
40      * @Title: log 
41      * @author sunt  
42      * @date 2017年11月10日
43      * @return void
44      */
45     @Pointcut("execution(public * com.sun.spring.boot.controller.*.*(..))")
46     //切入点说明:包下的任意类,任意方法,任意参数,任意返回值的方法都进行切入
47     public void sysLog() {
48         
49     }
50     
51     @Before("sysLog()")
52     public void doBefore(JoinPoint joinPoint) {
53         
54         ServletRequestAttributes servletRequestAttributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
55         HttpServletRequest request = servletRequestAttributes.getRequest();
56             
57         String requestUri = request.getRequestURI();// 得到请求的资源
58         String remoteAddr = request.getRemoteAddr();// 得到来访者的IP地址
59         String method = request.getMethod();// 得到请求URL地址时使用的方法
60         String remoteHost = request.getRemoteHost();//客户端主机名
61         String className = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();
62         
63         logger.info("+++++++从切入点开始处切入内容...");
64         logger.info("requestUri=" + requestUri + ",remoteAddr=" + remoteAddr
65                     + ",method=" + method + ",remoteHost=" + remoteHost + ",className=" + className);
66         SysLogInfoBean bean = new SysLogInfoBean();
67         bean.setUserName("1号活跃用户");
68         bean.setIp(remoteAddr);
69         bean.setCreateDate(new Date());
70         bean.setMethodNmae(method);
71         bean.setRemoteHost(remoteHost);
72         bean.setClassName(className);
73         bean.setUrl(requestUri);
74         
75         //TODO :测试直接入库操作,用户量比较大的网站一般缓存到消息队列执行批量入库,推荐Apache Kafka
76         sysLogInfoService.insertSysLog(bean);
77     }
78     
79     @After("sysLog()")
80     public void doAfter(JoinPoint joinPoint) {
81         logger.info("------------->在切入点结尾处(方法执行后)切入内容...");
82     }
83     
84     
85     @AfterReturning(returning = "result",pointcut = "sysLog()")
86     public void doAfterReturning(Object result) {
87         logger.info("在切入点return内容之后切入内容:" + result);
88     }
89     
90 }

7、Request的常用方法

详细讲解HttpServletRequest参考这篇博客: http://www.cnblogs.com/love540376/p/5336881.html

   getRequestURL方法返回客户端发出请求时的完整URL。
  getRequestURI方法返回请求行中的资源名部分。
  getQueryString 方法返回请求行中的参数部分。
  getPathInfo方法返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。
  getRemoteAddr方法返回发出请求的客户机的IP地址。
  getRemoteHost方法返回发出请求的客户机的完整主机名。
  getRemotePort方法返回客户机所使用的网络端口号。
  getLocalAddr方法返回WEB服务器的IP地址。
  getLocalName方法返回WEB服务器的主机名。

8、访问之前做的商品增删改查记录用户的操作信息

http://127.0.0.1:8088/goods/list

9、后台日志分析

10、查看数据库记录的信息

11、svn地址:svn://gitee.com/SunnySVN/SpringBoot

最新同步更新地址:https://www.sunnyblog.top/ 感谢您花时间阅读此篇文章,如果您觉得这篇文章你学到了东西也是为了犒劳下博主的码字不易不妨打赏一下吧,让博主能喝上一杯咖啡,在此谢过了! 如果您觉得阅读本文对您有帮助,请点一下左下角“推荐”按钮,您的“推荐”将是我最大的写作动力!另外您也可以选择【关注我】,可以很方便找到我! 本文版权归作者和博客园共有,来源网址:https://www.cnblogs.com/sunny1009 欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利!
posted @ 2021-12-09 09:16  满Sir  阅读(949)  评论(0编辑  收藏  举报