使用AOP实现简单的日志访问记录
前言:
在我们访问网站的时候,每次都会以不同角色,时间,地点,用户,访问的周期时间,访问的IP进行访问,我们可以通过Spring当中面向切面编程,来实现对访问日志的记录,并将它存储进入数据库,本个Demo完全基于SSM框架
一、环境准备
1.1 创建数据库表
2.2 创建数据库实体类
再次注意,本Demo完全基于SSM,本篇文章只有关于切面编写的逻辑
二、配置切面
2.1 web配置
- 在我们的切面类当中会用到Request对象,所以我们需要在web-xml监听requestContextListener
2.2 获取访问资源的切面类
- 下面就是我们获取各个访问资源的信息。
@Component
@Aspect
public class LogAop {
private Date visitTime; //访问时间
private Class clazz; //访问的类
private Method method;
private String userName;
private String url;
private long executeTime; //执行的时间
private String ip; //Ip地址
//当我们监听request之后,我们就可以使用IOC为我们生成的req对象。
@Autowired
private HttpServletRequest req;
@Autowired
private SystemLogService service;
@Pointcut("execution(* com.atjianyi.controller.*.*(..))")
private void P1(){
}
/**
* 前置通知
* @param pjp
*/
@Before("P1()")
private void beforAdvice(JoinPoint pjp) throws NoSuchMethodException {
Object[] objs = pjp.getArgs();
//获取访问时间
visitTime = new Date();
//获取当前访问
clazz = pjp.getTarget().getClass();
//获取方法名称
String methodName = pjp.getSignature().getName();
if(clazz!=null&&clazz!=LogAop.class){
if(objs!=null && objs.length>0){
//有参数的方法
Class[] argsClass = new Class[objs.length];
for (int i = 0 ; i<objs.length;i++){
argsClass[i] = objs[i].getClass();
}
method = clazz.getMethod(methodName,argsClass);
}else{
//无参数的方法
method = clazz.getMethod(methodName);
}
}
}
/**
* 后置通知
* @param pjp
*/
@After("P1()")
private void afterReturn(JoinPoint pjp) {
//执行时间
executeTime = new Date().getTime() - visitTime.getTime();
//获取URL(RequestMapping上)
if(clazz!=null && method !=null && clazz!=LogAop.class){
//获取类上和方法上的注解
RequestMapping classAnnotation = (RequestMapping)clazz.getAnnotation(RequestMapping.class);
RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
if(classAnnotation!=null && methodAnnotation!=null){
String[] value = classAnnotation.value();
String[] value1 = methodAnnotation.value();
url = value[0]+value1[0];
}
}
//获取用户名
userName = getUserInfoName();
ip = req.getRemoteAddr(); //获取Ip
saveSystemLog();
}
//保存用户
private void saveSystemLog(){
SystemLog systemLog = new SystemLog();
systemLog.setSystemLogExecutionTime(executeTime);
systemLog.setSystemLogIp(ip);
systemLog.setSystemLogMethod("[类名:]"+clazz.getName()+"[方法:]"+method.getName());
systemLog.setSystemLogUrl(url);
systemLog.setSystemLogUserName(userName);
systemLog.setSystemLogVisitTime(visitTime);
//调用LogService进行存储
service.insertSystemLog(systemLog);
}
/**
* 获取用户名
*/
private String getUserInfoName(){
SecurityContext context = SecurityContextHolder.getContext();
User principal = (User)context.getAuthentication().getPrincipal();
return principal.getUsername();
}
}
注意:关于使用注解配置AOP切面时候,最终通知和后置通知的顺寻相反,所以,我们这里的的@after也会是后置通知的执行位置!