使用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