• java面向切面编程AOP案例,记录请求日志


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

    文章目录


    前言

    本文主要描述面向切面编程AOP的用例

    一、AOP是什么?

    利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

    二、使用步骤

    1.引入pom文件依赖

    代码如下(示例):

    
        org.springframework.boot
        spring-boot-starter-aop
        2.6.4
    

    2.请求日志记录

    代码如下(示例):

    1. @Documented
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Target({ElementType.TYPE, ElementType.METHOD})
    4. public @interface OptLog {
    5. /**
    6. * 操作日志类型
    7. *
    8. * @return
    9. */
    10. OperationTypeEnum scenesType();
    11. /**
    12. * 请求处理状态
    13. *
    14. * @return
    15. */
    16. int status() default 0;
    17. /**
    18. * 写SpEL表达式 获取request请求内容
    19. *
    20. * @return
    21. */
    22. String request() default "";
    23. /**
    24. * request请求内容的类型
    25. *
    26. * @return
    27. */
    28. Class requestType() default String.class;
    29. /**
    30. * 默认 系统管理员
    31. * 其他的取当前登录人
    32. *
    33. * @return
    34. */
    35. String operationUser() default "系统管理员";
    36. /**
    37. * 默认 系统管理员
    38. * 其他的取当前登录人
    39. *
    40. * @return
    41. */
    42. long operationUserId() default 0L;
    43. }
    1. @Slf4j
    2. @Aspect
    3. @Component
    4. public class OptLogAspect {
    5. /**
    6. * 用于SpEL表达式解析.
    7. */
    8. private final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
    9. /**
    10. * 用于获取方法参数定义名字.
    11. */
    12. private final DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
    13. @Autowired
    14. private InLogRepository inLogRepository;
    15. @Pointcut("@annotation(com.yssk.interfaces.biz.annotation.OptLog)")
    16. public void optLogAspect() {
    17. }
    18. @Around("optLogAspect()")
    19. public Object doAround(ProceedingJoinPoint joinPoint) {
    20. Object obj = null;
    21. try {
    22. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    23. //获取方法参数值
    24. Object[] args = joinPoint.getArgs();
    25. OptLog optLog = getTargetAnnotation(joinPoint);
    26. String request = optLog.request();
    27. Class requestType = optLog.requestType();
    28. // 获取request请求内容
    29. Object requestKeyVal = getValBySpEl(request, methodSignature, args, requestType);
    30. if(Objects.nonNull(requestKeyVal)){
    31. Long id = handleOptRecordBefore(requestKeyVal);
    32. log.info("rizhi:{}", id);
    33. obj = joinPoint.proceed();
    34. handleOptRecordAfter(id, obj);
    35. }
    36. } catch (Throwable e) {
    37. log.warn("记录请求日志出现异常...", e);
    38. }
    39. return obj;
    40. }
    41. private Long handleOptRecordBefore(Object request){
    42. log.info("请求日志保存");
    43. String jsonStr = JSONObject.toJSONString(request);
    44. String requestUrl = "";
    45. if(ObjectUtils.isNotEmpty(request)){
    46. if(request instanceof RequestDTO){
    47. requestUrl = ((RequestDTO) request).getRequestUrl();
    48. }
    49. }
    50. // 保存请求日志
    51. InLog inLog = new InLog();
    52. inLog.setRequest(jsonStr);
    53. inLog.setRequestUrl(requestUrl);
    54. inLog.setStatus(0);
    55. inLogRepository.save(inLog);
    56. return inLog.getId();
    57. }
    58. private void handleOptRecordAfter(Long id, Object response){
    59. log.info("请求日志修改");
    60. String jsonStr = JSONObject.toJSONString(response);
    61. int status = 0;
    62. if(ObjectUtils.isNotEmpty(response)){
    63. if(response instanceof ResponseDTO){
    64. if(((ResponseDTO) response).getError_code() == 0){
    65. status = 1;
    66. }
    67. }
    68. }
    69. // 修改请求日志
    70. LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>();
    71. updateWrapper.set(InLog::getStatus, status);
    72. updateWrapper.eq(InLog::getId, id);
    73. updateWrapper.set(InLog::getResponse, jsonStr);
    74. inLogRepository.update(updateWrapper);
    75. }
    76. /**
    77. * 获取注解
    78. * @param point
    79. * @return
    80. */
    81. public static OptLog getTargetAnnotation(JoinPoint point) {
    82. try {
    83. OptLog annotation = null;
    84. if (point.getSignature() instanceof MethodSignature) {
    85. Method method = ((MethodSignature) point.getSignature()).getMethod();
    86. if (method != null) {
    87. annotation = method.getAnnotation(OptLog.class);
    88. }
    89. }
    90. return annotation;
    91. } catch (Exception e) {
    92. log.warn("获取 {}.{} 的 @OptLog 注解失败", point.getSignature().getDeclaringTypeName(), point.getSignature().getName(), e);
    93. return null;
    94. }
    95. }
    96. /**
    97. * 解析spEL表达式
    98. */
    99. private Object getValBySpEl(String spEl, MethodSignature methodSignature, Object[] args, Class classType) {
    100. try {
    101. //获取方法形参名数组
    102. String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod());
    103. if (paramNames != null && paramNames.length > 0) {
    104. Expression expression = spelExpressionParser.parseExpression(spEl);
    105. // spring的表达式上下文对象
    106. EvaluationContext context = new StandardEvaluationContext();
    107. // 给上下文赋值
    108. for (int i = 0; i < args.length; i++) {
    109. context.setVariable(paramNames[i], args[i]);
    110. context.setVariable("p" + i, args[i]);
    111. }
    112. return expression.getValue(context, classType);
    113. }
    114. } catch (Exception e) {
    115. log.warn("解析请求日志的el表达式出错", e);
    116. }
    117. return null;
    118. }
    119. }

    总结


    以上就是今天要讲的内容,本文仅仅简单介绍了aop的使用法。

  • 相关阅读:
    如何判断结构体是否相等?能否用 memcmp 函数判断结构体相等?
    Mybatis sql参数自动填充
    docker搭建vulhub
    Java lambda表达式对List的常见操作记录
    Linux提权--第三方软件MYSQL数据库提权(WEB+本地)
    模拟实现vue3.x中的计算属性
    图片点击出现边框样式(一图出现边框,其他图取消边框)
    [附源码]Python计算机毕业设计Django宁财二手物品交易网站
    Redis持久化与一致性解决方案「面试必问」
    Swift学习笔记一(Array篇)
  • 原文地址:https://blog.csdn.net/qq_30270931/article/details/128101539