【SpringBoot】SpringBoot中使用AOP实现日志记录功能

06-01 990阅读

62e497765dbab90f9e55a16b241cca6d.png

  📝个人主页:哈__

期待您的关注 

47f09392526c71b5885ec838a3ea7ffe.gif

目录

📕AOP简介

📂创建日志数据库 

🔥创建日志记录表

🌼创建用户表 

🍉SpringBoot使用AOP

一、导入依赖

二、创建我们的项目结构

三、使用AOP

1.创建枚举类

2..创建Log注解

3.创建切面类

4.IpUtil

5.进行测试


 

在我之前的一篇文章中我已经讲解过了AOP的基本概念,在这里无非也就是在重复一遍。

📕AOP简介

AOP的全称是Aspect-Oriented Programming,即面向切面编程(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。


在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想要关闭某个功能,或者对其进行修改,就必须要修改所有的相关方法。这不但增加了开发人员的工作量,而且提高了代码的出错率。


为了解决这一问题,AOP思想随之产生。AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,采用传统的OOP思想显然是无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充。

32b56909b12d7dae97e5dd72d1c5b671.png

想要再详细了解AOP的大家可以看看我这篇文章。这篇文章我主要将在SpringBoot中使用AOP实现日志记录。

【Spring】Spring中AOP的简介和基本使用,SpringBoot使用AOP-CSDN博客

📂创建日志数据库 

🔥创建日志记录表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_oper_log
-- ----------------------------
DROP TABLE IF EXISTS `sys_oper_log`;
CREATE TABLE `sys_oper_log`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
  `operation` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作',
  `business_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '业务类型',
  `method` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '方法名称',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '操作时间',
  `oper_name` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '操作用户',
  `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '参数',
  `ip` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '请求的ip地址',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2058 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志记录' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

🌼创建用户表 

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名 ',
  `age` int(11) NULL DEFAULT NULL COMMENT '年龄 ',
  `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱 ',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (2, 'Jack', 20, 'test2@baomidou.com');
INSERT INTO `user` VALUES (3, 'Tom', 28, 'test3@baomidou.com');
INSERT INTO `user` VALUES (4, 'Sandy', 21, 'test4@baomidou.com');
INSERT INTO `user` VALUES (5, 'Billie', 24, 'test5@baomidou.com');
INSERT INTO `user` VALUES (6, 'sss', 18, '123@qq.com');
INSERT INTO `user` VALUES (8, 'sss', 18, '123@qq.com');
SET FOREIGN_KEY_CHECKS = 1;

简单看一下表格的结构,我这里的数据就不给大家展示了。

adfe62ee67012a413c9e75042a56e312.png 

b39c7cb2f930f0e92d66703c360abec9.png 

🍉SpringBoot使用AOP

一、导入依赖

下边的三个依赖是我们的核心依赖。

        
            org.springframework.boot
            spring-boot-starter-aop
        
         
            mysql
            mysql-connector-java
            8.0.29
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.4.3
        
        
            org.projectlombok
            lombok
        
        
            org.springframework.boot
            spring-boot-starter-web
        

二、创建我们的项目结构

  • 创建UserMapper
    @Mapper
    public interface UserMapper extends BaseMapper {
    }
    • 创建UserService
      public interface UserService extends IService {
      }
      • 创建UserServiceImpl
        @Service
        public class UserServiceImpl extends ServiceImpl implements UserService {
        }
        • 创建UserController
          @RestController
          @RequestMapping("/user")
          public class UserController {
              @Autowired
              private UserService userService;
              @Log(operation = "查找用户",businessType = BusinessType.LIST)
              @RequestMapping("/find-user")
              public String findUser(){
                  return userService.list().toString();
              }
          }

          创建两个实体

          • 创建User
            @Data
            public class User {
                @TableId(type = IdType.ASSIGN_ID)
                private Long id;
                private String name;
                private Integer age;
                private String email;
                
            }
            • 创建SysOperLog
              @Data
              @TableName("sys_oper_log")
              public class SysOperLog {
                      @TableId(type = IdType.AUTO)
                      private Long id;
                      private String operation;
                      private String businessType;
                      private String method;
                      @TableField(fill = FieldFill.INSERT)
                      private LocalDateTime createTime;
                      private String operName;
                      private String params;
                      private String ip;
              }

               

              三、使用AOP

              1.创建枚举类

              这个枚举类的作用就是记录我们调用的接口是什么样的一个类型的,是查找、删除还是其他。

              public enum BusinessType {
                  /**
                   * 其它
                   */
                  OTHER,
                  /**
                   * 新增
                   */
                  INSERT,
                  /**
                   * 修改
                   */
                  UPDATE,
                  /**
                   * 删除
                   */
                  DELETE,
                  
                  /**
                   * 浏览
                   */
                  LIST
              }

              2..创建Log注解

              默认的操作为空,默认的操作类型是OTHER。

              @Target({ElementType.METHOD})
              @Retention(RetentionPolicy.RUNTIME)
              @Documented
              public @interface Log {
                  /**
                   * 操作名称
                   * @return
                   */
                  String operation() default "";
                  /**
                   * 操作的类型
                   * @return
                   */
                  BusinessType businessType() default BusinessType.OTHER;
              }

              3.创建切面类

              @Aspect
              @Component
              public class LogAspect {
                  @Pointcut("@annotation(com.qcby.annotation.Log)")
                  public void pointCut(){}
                  @Autowired
                  HttpServletRequest request;
                  @Autowired
                  SysOperLogMapper sysOperLogMapper;
                  @After(value = "pointCut()")
                  public void afterLogWrite(JoinPoint joinPoint){
                      // 创建日志对象
                      SysOperLog sysOperLog = new SysOperLog();
                      // 获取我们调用的方法
                      MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                      Method method = signature.getMethod();
                      // 获取方法上的Log注解,因为我们要获取注解中的一些信息
                      Log log = method.getAnnotation(Log.class);
                      // 获取我们调用的类的名称
                      String className = joinPoint.getTarget().getClass().getName();
                      // 获取调用的方法的名称
                      String methodName = method.getName();
                      // 重新修改一下我们调用的方法 是全路径的
                      methodName = className + methodName;
                      // 获取方法的参数
                      Object[] args = joinPoint.getArgs();
                      ObjectMapper objectMapper = new ObjectMapper();
                      String params = "";
                      try {
                          params =  objectMapper.writeValueAsString(args);
                      } catch (JsonProcessingException e) {
                          e.printStackTrace();
                      }
                      // 获取注解中的操作名称
                      String operation = log.operation();
                      // 获取注解中的操作类型
                      String businessType = log.businessType().toString();
                      // 这里的操作人员仅靠后端是写不了的  需要前端的token认证  我直接把操作人员改为admin
                      String username = "admin";
                      // 获取ip地址
                      String ipAddress = IpUtil.getIpAddr(request);
                      sysOperLog.setBusinessType(businessType);
                      sysOperLog.setOperation(operation);
                      sysOperLog.setMethod(methodName);
                      sysOperLog.setParams(params);
                      sysOperLog.setIp(ipAddress);
                      sysOperLog.setOperName(username);
                      sysOperLog.setCreateTime(LocalDateTime.now());
                      
                      sysOperLogMapper.insert(sysOperLog);
                      
                  }
              }
              

              4.IpUtil

              public class IpUtil {
                  private static final String UNKNOWN = "unknown";
                  private static final String LOCALHOST = "127.0.0.1";
                  private static final String SEPARATOR = ",";
                  public static String getIpAddr(HttpServletRequest request) {
                      System.out.println(request);
                      String ipAddress;
                      try {
                          ipAddress = request.getHeader("x-forwarded-for");
                          if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
                              ipAddress = request.getHeader("Proxy-Client-IP");
                          }
                          if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
                              ipAddress = request.getHeader("WL-Proxy-Client-IP");
                          }
                          if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
                              ipAddress = request.getRemoteAddr();
                              if (LOCALHOST.equals(ipAddress)) {
                                  InetAddress inet = null;
                                  try {
                                      inet = InetAddress.getLocalHost();
                                  } catch (UnknownHostException e) {
                                      e.printStackTrace();
                                  }
                                  ipAddress = inet.getHostAddress();
                              }
                          }
                          // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
                          // "***.***.***.***".length()
                          if (ipAddress != null && ipAddress.length() > 15) {
                              if (ipAddress.indexOf(SEPARATOR) > 0) {
                                  ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                              }
                          }
                      } catch (Exception e) {
                          ipAddress = "";
                      }
                      return ipAddress;
                  }
              }

              5.进行测试

              我们在浏览器上输入网址:

              127.0.0.1:8080/user/find-user

              数据是没问题的,接下来我们只需要查看数据的日志文件是否插入了日志就好了。 

              d693b679ffda67278924914e179974cd.png

              这里我查找了两次,一次使用的localhost,另一次使用的127.0.0.1。日志可以成功记录。 

              2d3d9119096467509ca76f4d0a74f5b3.png 

               

               

               

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码