前言
AOP的原理:AOP将业务逻辑组件和切面类都加入到容器中,负责在业务逻辑运行的时候将日志进行打印,切面类负责动态感知MathCalculator.div运行到哪里然后执行。通过@Aspect通知注解给切面类的目标方法标注何时何地运行。
文章目录
- 前言
- 一、Aop是什么?
- 二、使用步骤
- 1.导入AOP依赖
- 2.自定义操作日志注解
- 3.设置操作日志切入点,在注解的位置切入
- 4.request获取的参数数组转Map便于存储
- 5.连接点正常执行完成后执行(连接点抛出异常,则不会执行)
- 6.Controller添加创建的注解@OperLog
- 7.PostMan测试
- 更多功能(抛出异常日志记录)
一、Aop是什么?
Aop,面向切面编程,“切面”就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来的部分,Aop的存在有助于减少系统的冗余代码,降低模块间的耦合度,能有效提高可操作性和可维护性。
其作用,就是把业务中冗余的代码整合提取,在不变更业务代码的同时,为已存在业务增加可扩展性。(例如:日志记录,性能统计,安全控制,事务处理,异常处理及扩展)
二、使用步骤
1.导入AOP依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.自定义操作日志注解
代码如下(示例):
@Target(ElementType.METHOD)/*注解放置的目标位置,METHOD是可注解在方法级别上*/
@Retention(RetentionPolicy.RUNTIME)/*注解在哪个阶段执行,RUNTIME是注释将由编译器记录在类文件中,并在运行时由VM保留*/
@Documented
public @interface OperLog {
/**
* 创建注解-操作描述
* @return
*/
String operDescribe() default "";
}
3.设置操作日志切入点,在注解的位置切入
@Pointcut("@annotation(com.XX.XX.OperLog)")
public void operLogPoinCut() {
}
4.request获取的参数数组转Map便于存储
public Map<String, String> ParameterMapToMap(Map<String, String[]> parameterMap) {
Map<String, String> map = new HashMap<>();
for (String key : parameterMap.keySet()) {
map.put(key, parameterMap.get(key)[0]);
}
return map;
}
5.连接点正常执行完成后执行(连接点抛出异常,则不会执行)
@AfterReturning(value = "operLogCutIn()", returning = "returnParameters")
public void saveOperLog(JoinPoint joinPoint, Object returnParameters) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();/*获取RequestAttributes*/
HttpServletRequest request = (HttpServletRequest) requestAttributes/*从获取RequestAttributes中获取HttpServletRequest的信息*/
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
OperLogDto operLogDto = new OperLogDto();
try {
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取注解
OperLog opLog = method.getAnnotation(OperLog.class);
if (ObjectUtils.isNotEmpty(opLog)) {
operLogDto.setLogDescribe(opLog.operDescribe());/*操作描述*/
}
String className = joinPoint.getTarget().getClass().getName();/*获取请求的类名*/
String methodName = method.getName();/*获取请求的方法名*/
operLogDto.setLogMethod(className + "." + methodName);/*类名.方法名==请求方法*/
operLogDto.setLogRequestParameters(String.valueOf(ParameterMapToMap(request.getParameterMap()))); /*请求参数*/
operLogDto.setLogReturnParameters(String.valueOf(returnParameters)); /*返回结果*/
operLogDto.setLogIp(IpUtils.getIP(request)); /*请求IP*/
operLogDto.setLogUrl(request.getRequestURI()); /*请求URI*/
operLogDto.setLogOperateUserId("获取当前登录用户ID"); /*请求用户ID*/
operLogDto.setLogOperateUserName("获取当前登录用户姓名"); /*请求用户名称*/
operLogDto.setLogCreateTime(new Date());/*操作时间*/
operLogDto.setSystemName(systemName); /*操作系统*/
operLogService.save(operLogDto);/*储存日志*/
} catch (Exception e) {
e.printStackTrace();
}
}
6.Controller添加创建的注解@OperLog
/**
* 分页列表查询
* @param dto
* @param page
* @return
*/
@GetMapping(value = "/getAllByPage")
@OperLog(operDescribe = "分页列表查询日志记录")/*自定义日志记录-操作描述*/
public Map<String, Object> getAllByPage(OperLogDto dto, Page page) {
return operLogService.queryPage(dto, page);
}
7.PostMan测试