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

posted @ 2017-11-10 16:08  sunny1009  阅读(2305)  评论(1编辑  收藏  举报