SpringBoot日志收集-Aop方式-存进数据库

SpringBoot日志收集-Aop方式-存进数据库

八月 20, 2023 评论 10 阅读 1626 点赞 0 收藏 0

一、前言

本文使用的SpringBoot版本为:2.5.2

1)概述:

日志网络设备、系统及服务程序等,在运作时都会产生一个叫log的事件记录;每一行日志都记载着日期、时间、使用者及动作等相关操作的描述

2)介绍:

Windows网络操作系统设计有各种各样的日志文件,如应用程序日志,安全日志、系统日志、Scheduler服务日志、FTP日志、WWW日志、DNS服务器日志等等,这些根据你的系统开启的服务的不同而有所不同。

本文介绍的更多的是偏向于行为日志,并非系统日志级别的

我们在系统上进行一些操作时,这些日志文件通常会记录下我们操作的一些相关内容,这些内容也许对我们来说并没有什么用处,但是对系统安全工作人员却相当有用。

比如说有人对系统进行了IPC探测,系统就会在安全日志里迅速地记下探测者探测时所用的IP、时间、用户名等,用FTP探测后,就会在FTP日志中记下IP、时间、探测所用的用户名等。

3)使用场景:

简单介绍几个(我还菜很多不晓得,狗头保命😂)

  1. 排查bug,从日志查看错误出现地方
  2. 异地登录。(登录日志会记录下你的Ip)

对了哈,本文更多的是提供一个方法、思路和用一个完整案例来让大家对SpringBoot-注解Aop记录日志有一个认识

二、前期准备

案例

使用SpringBoot的Aop方式,将访问者的信息写入数据库中。

项目结构

说明:因为习惯了用MybatisPlus,拿了之前的完整配置,所以看起来java文件有多,但是关于log的其实并不复杂,代码中也带有注释, 请放心食用。

对MybatisPlus感兴趣的可以点👉SpringBoot整合MybatisPlus

2.1、数据库

tb_user表

CREATE TABLE `tb_user`  (
  `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `passwrod` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `deleted` int(1) NOT NULL DEFAULT 0,
  `create_time` datetime(0) NOT NULL COMMENT '创建时间',
  `update_time` datetime(0) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `tb_user` VALUES ('1', '宁在春', '123456', 0, '2021-07-23 14:32:46', '2021-07-29 23:56:10');
INSERT INTO `tb_user` VALUES ('2', '青冬栗', 'qwerasd', 0, '2021-07-23 15:02:02', '2021-07-23 15:49:55');

tb_log表

DROP TABLE IF EXISTS `tb_log`;
CREATE TABLE `tb_log`  (
  `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `user_id` int(10) NOT NULL,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `login_ip` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `type` int(10) NOT NULL,
  `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `operation` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `create_time` datetime(0) NULL DEFAULT NULL,
  `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '',
  `update_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `tb_log` VALUES ('e5b49465-b20a-453f-b15c-b284733f2f8e', 1, '宁在春', '0:0:0:0:0:0:0:1', 1, '127.0.0.1', '查询用户信息', '2021-08-15 01:04:31', '', '2021-08-15 01:04:31');

2.2、导入依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.2</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
    <!--spring切面aop依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.1</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.6</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.72</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.23</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.6.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

依赖都是常用的哈,没啥要说的哈。😀

2.3、yml配置文件

server:
  port: 8091
spring:
  application:
    name: springboot-log
  # 数据源配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 阿里的数据库连接池
    druid:
      username: root
      password: 123456
      url: jdbc:mysql://localhost:3306/commons_utils?serverTimezone=UTC&useSSL=false&characterEncoding=utf8&serverTimezone=GMT
      # 初使化连接数(向数据库要五个连接)
      initial-size: 5
      # 最小连接数(常住10个连接)
      min-idle: 10
      # 最大连接数(最多获得10个连接,多到10个数据库将进入一个阻塞状态,等待其他连接释放)
      max-active: 20
      # 获取连接最长等待时间,单位毫秒
      max-wait: 10000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      # 配置一个连接在池中最大生存的时间,单位是毫秒
      maxEvictableIdleTimeMillis: 900000
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
mybatis-plus:
  configuration:
    cache-enabled: true #开启缓存
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql日志
  mapper-locations: classpath:/mapper/*Mapper.xml
  global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

2.3、配置自定义log注解类

如果需要收集多种日志的话,可以做扩展,增加注解也可,用编码也可,当然如果项目多的话,那么必然是要抽取出来才是最合适的。

(经验不足、如有不妥,请及时提出,蟹蟹各位大佬😁)

/**
 * 配置自定义log注解类
 * @author crush
 */
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface MyLog {
    /** 操作事件     */
    String operation () default "";

    /** 日志类型 */
    int type ();
}

2.4、SysLogAspect:切面处理类

import cn.hutool.core.lang.UUID;
import com.crush.log.annotation.MyLog;
import com.crush.log.entity.LogOperation;
import com.crush.log.entity.LogUser;
import com.crush.log.mapper.LogOperationMapper;
import com.crush.log.utils.IpUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/** 系统日志:切面处理类 */
@Aspect
@Component
public class SysLogAspect {
    /**我这里是使用log4j2把一些信息打印在控制台上面,可以不写 */
    private static final Logger log = LogManager.getLogger(SysLogAspect.class);

    /**操作数据库 */
    @Autowired
    private LogOperationMapper logOperationMapper;

    /**
     *  定义切点 @Pointcut
     *  在注解的位置切入代码
     *  这里的意思就是注解写在那个方法上,那个方法就是被切入的。
     */
    @Pointcut("@annotation(com.crush.log.annotation.MyLog)")
    public void logPoinCut() {
    }

    //切面 配置通知
    @Before("logPoinCut()")         //AfterReturning
    public void saveOperation(JoinPoint joinPoint) {
        log.info("---------------接口日志记录---------------");
        //用于保存日志
        LogOperation logOperation = new LogOperation();

        // 这里是获得当前请求的request
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();

        String requestURL = request.getRequestURL().toString();
        logOperation.setUrl(requestURL);

        // 客户端ip  这里还可以与之前做一个比较,如果不同的话,就给他推送消息什么的,说异地登录 什么的。 
        String ip = IpUtils.getIpAddr(request);
        logOperation.setLoginIp(ip);

        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        //获取切入点所在的方法
        Method method = signature.getMethod();

        //获取操作--方法上的Log的值
        MyLog myLog = method.getAnnotation(MyLog.class);
        if (myLog != null) {
            //保存操作事件
            String operation = myLog.operation();
            logOperation.setOperation(operation);

            //保存日志类型  这里也可以做扩展 根据不同的类型,你可以做不同的操作 
            int type = myLog.type();
            logOperation.setType(type);

            log.info("operation="+operation+",type="+type);
        }

        // 操作人账号、姓名(需要提前将用户信息存到session)
        // 因为这里是模拟 所以偷懒用了个 session 
        // 实际上用了security 获取的应该是当前授权对象的信息 而不是从session 中获取 
        // 也或者说是从 redis 中获取,这只是提供一个思路,请见谅
        LogUser user = (LogUser) request.getSession().getAttribute("user");
        if(user != null) {
            String userId = user.getId();
            String userName = user.getUsername();
            logOperation.setUserId(userId);
            logOperation.setUsername(userName);
            System.out.println(user);
        }
        log.info("url="+requestURL,"ip="+ip);
       
        //调用service保存Operation实体类到数据库
        //我id使用的是UUID,不需要的可以注释掉
        String id = UUID.randomUUID().toString().replace("-","");
        logOperation.setId(id);
        logOperationMapper.insert(logOperation);
    }
}

2.5、MybatisPlus相关配置类

MybatisPlusConfig

/**
 * @EnableTransactionManagement :开启事务
 * @Author: crush
 * @Date: 2021-07-23 14:14
 * version 1.0
 */
@Configuration
@EnableTransactionManagement
@MapperScan("com.crush.log.mapper")
public class MybatisPlusConfig {

    /*** 分页*/
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        // 注册乐观锁 插件
        return mybatisPlusInterceptor;
    }

    /** 配置数据源 druid*/
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.druid")
    public DruidDataSource druidDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
}

MyMetaObjectHandler:自动填充

/**
 * 填充创建和修改时间
 * @Author: crush
 * @Date: 2021-07-23 14:14
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.setFieldValByName("createTime", LocalDateTime.now(),metaObject);
        this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
    }
}

LocalDateTimeSerializerConfig:配置全局的LocalDateTime格式化

@Configuration
public class LocalDateTimeSerializerConfig {
    @Value("${spring.jackson.date-format}")
    private String DATE_TIME_PATTERN;
    
    @Value("${spring.jackson.date-format}")
    private  String DATE_PATTERN ;
    /*** string转localdate*/
    @Bean
    public Converter<String, LocalDate> localDateConverter() {
        return new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(String source) {
                if (source.trim().length() == 0) {
                    return null;
                }
                try {
                    return LocalDate.parse(source);
                } catch (Exception e) {
                    return LocalDate.parse(source, DateTimeFormatter.ofPattern(DATE_PATTERN));
                }
            }
        };
    }

    /** * string转localdatetime*/
    @Bean
    public Converter<String, LocalDateTime> localDateTimeConverter() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String source) {
                if (source.trim().length() == 0) {
                    return null;
                }
                // 先尝试ISO格式: 2019-07-15T16:00:00
                try {
                    return LocalDateTime.parse(source);
                } catch (Exception e) {
                    return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DATE_TIME_PATTERN));
                }
            }
        };
    }

    /** * 统一配置 LocalDateTime 格式化*/
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        JavaTimeModule module = new JavaTimeModule();
        LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
        return builder -> {
            builder.simpleDateFormat(DATE_TIME_PATTERN);
            builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_PATTERN)));
            builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)));
            builder.modules(module);
        };
    }
}

2.6、IpUtils

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 获取IP方法
 */
public class IpUtils
{
    public static String getIpAddr(HttpServletRequest request)
    {
        if (request == null)
        {
            return "unknown";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("X-Real-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getRemoteAddr();
        }

        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    public static boolean internalIp(String ip)
    {
        byte[] addr = textToNumericFormatV4(ip);
        return internalIp(addr) || "127.0.0.1".equals(ip);
    }

    private static boolean internalIp(byte[] addr)
    {
        if (addr == null || addr.length < 2)
        {
            return true;
        }
        final byte b0 = addr[0];
        final byte b1 = addr[1];
        // 10.x.x.x/8
        final byte SECTION_1 = 0x0A;
        // 172.16.x.x/12
        final byte SECTION_2 = (byte) 0xAC;
        final byte SECTION_3 = (byte) 0x10;
        final byte SECTION_4 = (byte) 0x1F;
        // 192.168.x.x/16
        final byte SECTION_5 = (byte) 0xC0;
        final byte SECTION_6 = (byte) 0xA8;
        switch (b0)
        {
            case SECTION_1:
                return true;
            case SECTION_2:
                if (b1 >= SECTION_3 && b1 <= SECTION_4)
                {
                    return true;
                }
            case SECTION_5:
                if (b1 == SECTION_6) {
                    return true;
                }
            default:
                return false;
        }
    }

    /**
     * 将IPv4地址转换成字节
     * 
     * @param text IPv4地址
     * @return byte 字节
     */
    public static byte[] textToNumericFormatV4(String text)
    {
        if (text.length() == 0)
        {
            return null;
        }

        byte[] bytes = new byte[4];
        String[] elements = text.split("\\.", -1);
        try
        {
            long l;
            int i;
            switch (elements.length)
            {
                case 1:
                    l = Long.parseLong(elements[0]);
                    if ((l < 0L) || (l > 4294967295L))
                        return null;
                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 2:
                    l = Integer.parseInt(elements[0]);
                    if ((l < 0L) || (l > 255L))
                        return null;
                    bytes[0] = (byte) (int) (l & 0xFF);
                    l = Integer.parseInt(elements[1]);
                    if ((l < 0L) || (l > 16777215L))
                        return null;
                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 3:
                    for (i = 0; i < 2; ++i)
                    {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L))
                            return null;
                        bytes[i] = (byte) (int) (l & 0xFF);
                    }
                    l = Integer.parseInt(elements[2]);
                    if ((l < 0L) || (l > 65535L))
                        return null;
                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 4:
                    for (i = 0; i < 4; ++i)
                    {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L))
                            return null;
                        bytes[i] = (byte) (int) (l & 0xFF);
                    }
                    break;
                default:
                    return null;
            }
        }
        catch (NumberFormatException e)
        {
            return null;
        }
        return bytes;
    }

    public static String getHostIp()
    {
        try
        {
            return InetAddress.getLocalHost().getHostAddress();
        }
        catch (UnknownHostException ignored)
        {

        }
        return "127.0.0.1";
    }

    public static String getHostName()
    {
        try{
            return InetAddress.getLocalHost().getHostName();
        }
        catch (UnknownHostException ignored) {
        }
        return "未知";
    }
}

三、业务代码

我这里没有写查看日志的接口,存数据库,管理员可以随时查看这些信息,也可以使用web页面、会方便许多。

1、entity

LogUser

/**
 * @Author: crush
 * @Date: 2021-08-14 8:43
 * version 1.0
 */
@Data
@Accessors(chain = true)
@TableName("tb_user")
public class LogUser implements Serializable {

    private static final long serialVersionUID = 1L;

    private String id;

    private String username;

    private String passwrod;

    /*** 逻辑删除字段 */
    @TableLogic
    private Integer deleted;

    /*** 创建时间*/
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /*** 修改时间*/
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}
package com.crush.log.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 日志表
 * @author crush
 */
@Data
@Accessors(chain = true)
@TableName("tb_log")
public class LogOperation implements Serializable {

    private static final long serialVersionUID = 7925874058046995566L;

    private String id;
    /*** 用户id 操作人ID */
    private String userId;
    /** * 用户名称 关联admin_user */
    private String username;
    /** * 登录ip */
    private String loginIp;
    /** * 操作类型(0登录、1查询、2修改) 这个根据自己需求定义即可 ,还有很多其他方式,这个并不完善,只是刚刚够用的那种  */
    private int type;

    /** *  操作的url*/
    private String url;
    /**  * 操作内容 */
    private String operation;
    /** * 操作时间*/
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /*** 备注*/
    private String remark;
    /*** 修改时间*/
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

2、mapper

@Repository
@Mapper
public interface LogOperationMapper extends BaseMapper<LogOperation> {
}
@Repository
public interface LogUserMapper extends BaseMapper<LogUser> {
}

3、Service

public interface ILogUserService extends IService<LogUser> {
}
@Service
public class LogUserServiceImpl extends ServiceImpl<LogUserMapper, LogUser> implements ILogUserService {
}

4、Controller

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.crush.log.annotation.MyLog;
import com.crush.log.entity.LogUser;
import com.crush.log.service.ILogUserService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@RestController
@RequestMapping("user")
public class UserController {

    private static final Logger log = LogManager.getLogger(UserController.class);

    @Autowired
    private ILogUserService userService;


    /**
     * 假装登录,将用户信息存到session(方法是我之前写的懒得改,)
     * */
    @RequestMapping("/login")
    public String login(@RequestBody LogUser logUser,HttpServletRequest request){
        QueryWrapper<LogUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username",logUser.getUsername()).eq("passwrod",logUser.getPasswrod());
        LogUser user = userService.getOne(wrapper);
        if(user!=null){
            request.getSession().setAttribute("user",user);
            return "登录成功";
        }
        return "登录失败";
    }

    /**记录日志*/
    @MyLog(operation = "查询用户信息",type = 1)
    @RequestMapping("/log")
    public List<LogUser> insertLog(HttpServletRequest request){
        List<LogUser> users = userService.list();
        return users;
    }
}

记得写个主启动类,这我就不写啦。

5、测试

直接启动测试,先登录,再访问/log.

再访问/log

我们再看一下后台输出:

*
*
*