介绍
Spring AOP的相关知识点是面试中的老八股文了,对于初中级几乎是必问的。不过咱不仅要知道其概念和原理,更要掌握都有哪些应用场景以及如何使用它。今天就来介绍一下基于AOP实现系统访问日志的功能。
AOP相关的概念在此不再做介绍,如果有不了解的,自行百度或者可以看下这篇文章。AOP面向切面编程
代码示例
需要注意:
1. 使用HttpServletRequest 对象需要在配置文件中配置RequestContextListener,如图。完整版web.xml文件
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
/**
* @Description: 代码实现中共获取了以下六个值
* 访问时间
* 操作者用户名
* 访问ip
* 访问资源url
* 执行时长
* 访问方法
*
* @Author: nn
* @CreateTime: 2021-07-31 15:49
*/
@Component
@Aspect
public class LogAop {
/**
* Request对象 需要配置 RequestContextListener
*/
@Autowired
private HttpServletRequest request;
/**
* 保存日志信息的业务层
*/
@Autowired
private SysLogService sysLogService;
/**
* 访问时间
*/
private Date visitTime;
/**
* 访问的类
*/
private Class accessClass;
/**
* 访问方法
*/
private Method accessMethod;
/**
* 前置通知,在方法执行前进入
* @param jp
*/
// 表达式语法规范 execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名] ([参数列表]))
@Before("execution(* com.nn.web.*.*(..))")
public void doBefore(JoinPoint jp) throws NoSuchMethodException {
// 访问时间
visitTime = new Date();
// 访问的类
accessClass = jp.getTarget().getClass();
// 获取访问的方法名称
String methodName = jp.getSignature().getName();
// 访问方法的参数
Object[] args = jp.getArgs();
if (args == null || args.length == 0) {
// 只能获取无参方法
accessMethod = accessClass.getMethod(methodName);
} else {
// 获取有参数的方法
Class[] classArgs = new Class[args.length];
for (int i = 0; i < args.length; i++) {
classArgs[i] = args[i].getClass();
}
accessMethod = accessClass.getMethod(methodName, classArgs);
}
}
/**
* 后置通知,在方法执行后进入
* @param jp
*/
@After("execution(* com.nn.web.*.*(..))")
public void doAfter(JoinPoint jp) {
// 访问时长
Long executionTime = System.currentTimeMillis() - visitTime.getTime();
// 访问资源url
String url = null;
if (Objects.nonNull(accessClass) && Objects.nonNull(accessMethod) && !Objects.equals(accessClass, LogAop.class)) {
// 获取类上的@RequestMapping的value值
RequestMapping classAnnotation = (RequestMapping) accessClass.getAnnotation(RequestMapping.class);
if (Objects.nonNull(classAnnotation)) {
// 获取方法上的@GetMapping的value值
GetMapping methodAnnotation = accessMethod.getAnnotation(GetMapping.class);
String[] methodValue = methodAnnotation.value();
// 类上的@RequestMapping的value值
String[] classValue = classAnnotation.value();
// 类上的路径拼接上方法的路径等于访问路径
url = classValue[0] + methodValue[0];
}
}
// 访问ip
String ip = request.getRemoteAddr();
// 获取当前操作的用户(因为使用了Spring Security,所以这里获取用户名是从SecurityContext拿到的。
// 如果没有使用Spring Security,也可以通过Session中getAttribute拿到当前操作者的用户名)
SecurityContext context = SecurityContextHolder.getContext();
User user = (User) context.getAuthentication().getPrincipal();
String username = user.getUsername();
// 保存日志对象
SysLog sysLog = new SysLog();
sysLog.setIp(ip);
sysLog.setMethod("[类名] " + accessClass.getName() + "[方法名] " + accessMethod.getName());
sysLog.setExecutionTime(executionTime);
sysLog.setUrl(url);
sysLog.setUsername(username);
sysLog.setVisitTime(visitTime);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sysLog.setVisitTimeStr(dateFormat.format(visitTime));
sysLogService.saveSysLog(sysLog);
}