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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: SpringBoot日志收集-Aop方式-存进数据库

微信截图_20220524210328.png

现在大多数项目都会输出日志或保存日志,现在这个大数据时代,数据已经是一种非常非常重要的资源了。


日志也有很大作用的,不要小瞧它哦。😁

很喜欢一句话:“八小时内谋生活,八小时外谋发展”

如果你也喜欢,让我们一起坚持吧!!

共勉😁


我们:待别日相见时,都已有所成


一、前言


本文使用的SpringBoot版本为:2.5.2


1)概述:


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


2)介绍:


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


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


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


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


3)使用场景:


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


  1. 排查bug,从日志查看错误出现地方


  1. 异地登录。(登录日志会记录下你的Ip)


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


二、前期准备


案例


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


项目结构


微信截图_20220524210854.png


说明:因为习惯了用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.


微信截图_20220524211218.png


再访问/log


微信截图_20220524211255.png


我们再看一下后台输出:


微信截图_20220524211316.png


四、自言自语


本文只是给大家提供一个小思路,代码写的较为粗糙,请见谅。😁


还有很多地方可以扩展和完善,大家感兴趣的话,可以多试一试,这样学习才有乐趣啦。😂


日志的话他还会分很多类的,大家可以根据自己的需求扩展。


微信截图_20220524211402.png


我知道咱们掘金的大佬,讲话又好听,长的又帅,女朋友随便new,给小弟一个赞👍,这肯定的吧。😁


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
7天前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
29 4
SpringBoot入门(4) - 添加内存数据库H2
|
10天前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
21 2
SpringBoot入门(4) - 添加内存数据库H2
|
2天前
|
Java 数据库连接 测试技术
SpringBoot入门(4) - 添加内存数据库H2
SpringBoot入门(4) - 添加内存数据库H2
35 13
|
4天前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
21 1
|
11天前
|
SQL Java 数据库
Spring Boot与Flyway:数据库版本控制的自动化实践
【10月更文挑战第19天】 在软件开发中,数据库的版本控制是一个至关重要的环节,它确保了数据库结构的一致性和项目的顺利迭代。Spring Boot结合Flyway提供了一种自动化的数据库版本控制解决方案,极大地简化了数据库迁移管理。本文将详细介绍如何使用Spring Boot和Flyway实现数据库版本的自动化控制。
12 2
|
22天前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
35 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
22天前
|
Java 关系型数据库 MySQL
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
这篇文章是关于如何使用Spring Boot框架通过JdbcTemplate操作MySQL数据库的教程。
19 0
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
|
26天前
|
Java Maven Spring
SpringBoot日志整合
SpringBoot日志整合
16 2
|
28天前
|
SQL Java 关系型数据库
Springboot引入jpa来管理数据库
Springboot引入jpa来管理数据库
26 0
Springboot引入jpa来管理数据库
|
26天前
|
SQL XML 监控
SpringBoot框架日志详解
本文详细介绍了日志系统的重要性及其在不同环境下的配置方法。日志用于记录系统运行时的问题,确保服务的可靠性。文章解释了各种日志级别(如 info、warn、error 等)的作用,并介绍了常用的日志框架如 SLF4J 和 Logback。此外,还说明了如何在 SpringBoot 中配置日志输出路径及日志级别,包括控制台输出与文件输出的具体设置方法。通过这些配置,开发者能够更好地管理和调试应用程序。