基于AOP实现登录日志和操作日志(新手入门版)

news2024/12/29 11:06:28

基于AOP实现登录日志和操作日志

  • 目录结构
  • 代码
  • PostMan测试代码
  • 控制台查看输出
  • 解析成JSON
  • 如果你觉得对你有帮助的话,请点赞收藏

目录结构

在这里插入图片描述

代码


package com.demo.mymaintest.constants;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 系统日志注解
 *
 * @author Mark sunlightcs@gmail.com
 */
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.METHOD,ElementType.PARAMETER })
public @interface SysLog {

	String value() default "";

}

package com.demo.mymaintest.aop;


import com.alibaba.fastjson.JSONObject;
import com.demo.mymaintest.constants.SysLog;
import com.demo.mymaintest.entity.SysLogEntity;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统日志,切面处理类
 *
 * @author yhj
 */
@Aspect
@Component
public class SysLogAspect {

  // 定义切点 切点表达式指向SysLog注解,我们再业务方法上可以加上SysLog注解,然后所标注
  // 的方法都能进行日志记录
  @Pointcut("@annotation(com.demo.mymaintest.constants.SysLog)")
  public void logPointCut() {}

  @Around(value = "logPointCut()")
  private Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    HttpServletRequest request  = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    String requestURI = request.getRequestURI();
    String requestMethod = request.getMethod();
    String remoteAddr = request.getRemoteAddr();
    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Long nowDate = System.currentTimeMillis(); // 步入时间戳
    String startTime = dateformat.format(nowDate);

    MethodSignature method1 = (MethodSignature) proceedingJoinPoint.getSignature();
    Class<?> currentClass = proceedingJoinPoint.getTarget().getClass();
    Object proceed = proceedingJoinPoint.proceed();
    List<Object> allArgs = Arrays.asList(proceedingJoinPoint.getArgs());
    List<Object> args =
        allArgs.stream()
            .map(
                arg -> {
                  if (!(arg instanceof HttpServletRequest)
                      && !(arg instanceof HttpServletResponse)) {
                    return arg;
                  } else {
                    return null;
                  }
                })
            .filter(arg -> arg != null)
            .collect(Collectors.toList());

    SysLogEntity sysLogEntity = new SysLogEntity();
    sysLogEntity.setUsername("登录人从request中获取");
    MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
    		Method method = signature.getMethod();
    SysLog syslog = method.getAnnotation(SysLog.class);
    if(syslog != null){
            //注解上的描述
            sysLogEntity.setOperation(syslog.value());
        }
    sysLogEntity.setRequestPath(requestURI);
    sysLogEntity.setRequestMethod(requestMethod);
    sysLogEntity.setCurrentTimeMills(startTime);
    sysLogEntity.setArgsType(getMethodArgumentTypeName(method1));
    sysLogEntity.setAllArgs(args);
    sysLogEntity.setResponseData(proceed != null ? proceed.toString() : "null");
    sysLogEntity.setExecuteTimeMills((System.currentTimeMillis() - nowDate) + "ms");
    sysLogEntity.setClassMethodLocation(currentClass.getName() + "." + method.getName());
    sysLogEntity.setRemoteAddr(remoteAddr);
    sysLogEntity.setNowTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    sysLogEntity.setResponseType(method.getReturnType().getName());

    // TODO 将sysLogEntity存入ES

    System.out.println(JSONObject.toJSONString(sysLogEntity));
    return proceed;
  }

  @AfterThrowing(value = "logPointCut()")
  private void AfterThrowing() {
    System.out.println("异常通知");
  }

  private Map<String, String> getMethodArgumentTypeName(MethodSignature method) {
    Map<String, String> map = new HashMap<>();
    String[] argTypeNames = method.getParameterNames();
    Class[] parameterTypes = method.getParameterTypes();
    for (int i = 0; i < parameterTypes.length; i++) {
      map.put(parameterTypes[i].getName(), argTypeNames[i]);
    }
    return map;
  }
}
package com.demo.mymaintest.controller;


import com.demo.mymaintest.constants.SysLog;
import com.demo.mymaintest.entity.BookEntity;
import com.demo.mymaintest.entity.SysUser;
import com.demo.mymaintest.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.*;

/**
 * @ClassName TestApiController
 * @Author yhj
 * @Date 2023/7/15 13:22
 * @Description
 * @Version 1.0
 */

@RestController
@RequestMapping("/api")
@Slf4j
public class TestApiController {

    @PostMapping("/add")
    @SysLog(value = "添加数据测试")
    public R test(@RequestBody BookEntity bookEntity) {
        bookEntity.setBookImg("testImg");
        bookEntity.setBookIntro("书籍简介");
        return R.ok(200,"添加成功",bookEntity);
    }
    @PostMapping("/login")
    @SysLog(value = "用户登录")
    public ResponseEntity login(@RequestBody SysUser sysUser){
            String ok = "恭喜你登录成功";
            if(sysUser.getUserName().equals("test")){
                return ResponseEntity.ok(ok);
            }
            return ResponseEntity.ok().body("登录失败");
    }
    @DeleteMapping("/delete")
    @SysLog("删除")
    public ResponseEntity<String> deleteById(@PathVariable("id") Integer id){
        return ResponseEntity.ok("删除成功");
    }
}

package com.demo.mymaintest.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

/**
 *
 *
 * @author yhj
 * @date 2023-06-12 09:47:10
 */
@Data
public class BookEntity implements Serializable {
	private static final long serialVersionUID = 1L;
	/**
	 *
	 */
	@TableId
	private Integer bookId;
	/**
	 * 书籍编号
	 */
	private String bookIsbn;
	/**
	 * 书籍名称
	 */
	private String bookName;
	/**
	 * 书籍价格
	 */
	private Float bookPrice;

	/**
	 * 书籍封面
	 */
	private String bookImg;
	/**
	 * 简介
	 */
	private String bookIntro;
	/**
	 * 已购数量
	 */
	private int bookPurchasedNumber;
}

package com.demo.mymaintest.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 * 用户表
 * </p>
 *
 * @author jerry
 * @since 2021-06-16
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)

public class SysUser implements Serializable {

private static final long serialVersionUID=1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 用户编号
     */
    //@ApiModelProperty("用户编号")
    private String userCode;

    /**
     * 用户名
     */
    //@ApiModelProperty("用户名")
    private String userName;

    /**
     * 登录密码
     */
    //@ApiModelProperty("登录密码")
    private String password;

    /**
     * 真实姓名
     */
    //@ApiModelProperty("真实姓名")
    private String realName;

    /**
     * 手机号码
     */
    //@ApiModelProperty("手机号码")
    private String mobile;

    /**
     * 邮箱地址
     */
    //@ApiModelProperty("邮箱地址")
    private String email;

    /**
     * 组织机构id
     */
    //@ApiModelProperty("组织机构id")
    private Long orgId;

    /**
     * 组织机构名称
     */
    //@ApiModelProperty("组织机构名称")
    private String orgName;

    /**
     * 用户类型
     */
    //@ApiModelProperty("用户类型")
    private Integer userType;

    /**
     * 描述
     */
    //@ApiModelProperty("描述")
    private String userDesc;

    /**
     * 联系地址
     */
    //@ApiModelProperty("联系地址")
    private String address;

    /**
     * 传真
     */
    //@ApiModelProperty("传真")
    private String fax;

    /**
     * 邮编
     */
    //@ApiModelProperty("邮编")
    private String postalcode;

    /**
     * 状态(0:禁用 1:正常)
     */
    //@ApiModelProperty("状态(0:禁用 1:正常)")
    private Integer status;

    /**
     * 数据权限类型(role user group)
     */
    //@ApiModelProperty("数据权限类型(role user group)")
    private String permissionType;

    /**
     * 创建时间
     */
    //@ApiModelProperty("创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

    /**
     * 创建人
     */
    //@ApiModelProperty("创建人")
    private String createBy;

    /**
     * 更新时间
     */
    //@ApiModelProperty("更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date updateTime;

    /**
     * 更新人
     */
    //@ApiModelProperty("更新人")
    private String updateBy;

    /**
     * 是否删除(0-否 1-是)
     */
    //@ApiModelProperty("是否删除(0-否 1-是)")
    private Integer isDeleted;

    /**
     * 公司地址
     */
    //@ApiModelProperty("公司地址")
    private String orgAddress;

    /**
     * 部门id
     */
    //@ApiModelProperty("部门id")
    private String jobId;

    /**
     * 部门名称
     */
    //@ApiModelProperty("部门名称")
    private String jobName;


    /**
     * 过期期限
     */
    //@ApiModelProperty("过期期限")
    @JsonFormat(pattern = "yyyyMM", timezone = "GMT+8")
    private Date expire;

    private String orgCode;

}

PostMan测试代码

在这里插入图片描述

控制台查看输出

在这里插入图片描述

解析成JSON

{
    "allArgs":[                           // 所有入参
        {
            "bookId":123,
            "bookImg":"testImg",
            "bookIntro":"书籍简介",
            "bookIsbn":"123213414",
            "bookName":"test",
            "bookPrice":12.77,
            "bookPurchasedNumber":0
        }
    ],
    "argsType":{                        // 入参实体类
        "com.demo.mymaintest.entity.BookEntity":"bookEntity"
    },
    "classMethodLocation":"com.demo.mymaintest.controller.TestApiController.test",     // 方法
    "currentTimeMills":"2023-07-21 16:30:49",     // 时间
    "executeTimeMills":"9ms",   // 运行时间
    "nowTime":"2023-07-21 16:30:49",  // 时间
    "operation":"添加数据测试",      //  controller上面的注释
    "remoteAddr":"0:0:0:0:0:0:0:1",  // 这个其实是127.0.0.1 没有进行封装
    "requestMethod":"POST",       
    "requestPath":"/api/add",     // 路径  
    "responseData":"{msg=添加成功, code=200, data=BookEntity(bookId=123, bookIsbn=123213414, bookName=test, bookPrice=12.77, bookImg=testImg, bookIntro=书籍简介, bookPurchasedNumber=0)}",
    "responseType":"com.demo.mymaintest.utils.R",    // 所有返参
    "username":"登录人从request中获取"     // 根据项目详情从token或者session中获取登录人
}

如果你觉得对你有帮助的话,请点赞收藏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/782929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Debian 12 上安装 PHP 5.6, 7.4

环境&#xff1a;Debian 12 Debian 12 默认的PHP版本为 8.2 如果直接安装php7.4就出现下面的报错&#xff1a; sudo apt-get install libapache2-mod-php7.4 php7.4 php7.4-gd php7.4-opcache php7.4-mbstring php7.4-xml php7.4-json php7.4-zip php7.4-curl php7.4-imap p…

【人工智能】神经网络、前向传播、反向传播、梯度下降、局部最小值、多层前馈网络、缓解过拟合的策略

神经网络、前向传播、反向传播 文章目录 神经网络、前向传播、反向传播前向传播反向传播梯度下降局部最小值多层前馈网络表示能力多层前馈网络局限缓解过拟合的策略前向传播是指将输入数据从输入层开始经过一系列的权重矩阵和激活函数的计算后,最终得到输出结果的过程。在前向…

HarmonyOS/OpenHarmony应用开发-Stage模型UIAbility组件使用(六)

UIAbility组件间交互&#xff08;设备内&#xff09; UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时&#xff0c;会涉及到启动特定的UIAbility&#xff0c;该UIAbility可以是应用内的其他UIAbility&#xff0c;也可以是其他应用的UIAbility&#xff08;例如启…

unity 调用C++追踪物体后的位姿通过 dll,左右手坐标转化2

外参矩阵转四元数,左右手坐标系转化1_天人合一peng的博客-CSDN博客 在之前1的基础上更新 通过定位已经求得了物体的4*4的位姿矩阵&#xff0c;将其变化为四元数并从opengl的右手坐标转化为unity的左手坐标系。 body2world_pose().matrix()为计算得到的4*4的位姿矩阵 例 body…

Go语言之结构体

在实际开发中&#xff0c;我们可以将一组类型不同的、但是用来描述同一件事物的变量放到结构体中。例如&#xff0c;在校学生有姓名、年龄、身高、成绩等属性&#xff0c;学了结构体后&#xff0c;我们就不需要再定义多个变量了&#xff0c;将它们都放到结构体中即可。 在Go语言…

基于linux下的高并发服务器开发(第三章)- 3.7 线程属性

int pthread_attr_init(pthread_attr_t *attr);- 初始化线程属性变量int pthread_attr_destroy(pthread_attr_t *attr);- 释放线程属性的资源int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);- 获取线程分离的状态属性int pthread_attr_setdet…

【Redis】所以延迟双删有啥用

文章目录 1、何为延时双删2、常用缓存策略2.1、介绍2.2、先删缓存后更库2.3、先更库后删缓存2.4、使用场景 3、延时双删实现4、为什么要使用延时双删5、方案选择6、延时双删真的完美吗7、如何确定延时的时间 1、何为延时双删 延迟双删&#xff08;Delay Double Delete&#xf…

Jupyter 安装、简单操作及工作路径更换

一、Jupyter下载安装 pip install jupyterAnaconda是Python另一个非常流行的发行版&#xff0c;它之后有着自己的叫做“conda”的安装工具。用户可以使用它来安装很多第三方包。然而&#xff0c;Anaconda会预装很多包&#xff0c;包括了Jupyter Notebook,所以若已经安装了Anac…

VUE3 语法教程

vue3 起步 刚开始学习 Vue&#xff0c;我们不推荐使用 vue-cli 命令行工具来创建项目&#xff0c;更简单的方式是直接在页面引入 vue.global.js 文件来测试学习。 Vue3 中的应用是通过使用 createApp 函数来创建的&#xff0c;语法格式如下&#xff1a; const app Vue.crea…

cmder 使用简介

文章目录 1. cmder 简介2. 下载地址3. 安装4. 配置环境变量5. 添加 cmder 到右键菜单6. 解决中文乱码问题 1. cmder 简介 cmder 是一个增强型命令行工具&#xff0c;不仅可以使用 windows 下的所有命令&#xff0c;更爽的是可以使用 linux的命令, shell 命令。 2. 下载地址 …

机器学习深度学习——预备知识(下)

机器学习&&深度学习——预备知识&#xff08;下&#xff09; 4 微积分4.1 导数和微分4.2 偏导数4.3 梯度4.4 链式法则 5 自动微分5.1 简单例子5.2 非标量变量的反向传播5.3 分离计算5.4 Python控制流的梯度计算 6 概率6.1 基本概率论6.1.1 概率论公理 6.2 处理多个随机…

5.1 Bootstrap 插件概览

文章目录 Bootstrap 插件概览data 属性编程方式的 API避免命名空间冲突事件 Bootstrap 插件概览 在前面 布局组件 章节中所讨论到的组件仅仅是个开始。Bootstrap 自带 12 种 jQuery 插件&#xff0c;扩展了功能&#xff0c;可以给站点添加更多的互动。即使您不是一名高级的 Jav…

超参数优化 - 贝叶斯优化的实现

目录 1. 基于Bayes_opt实现GP优化 1.1 定义目标函数 1.2 定义参数空间 1.3 定义优化目标函数的具体流程 4. 定义验证函数&#xff08;非必须&#xff09; 5. 执行实际优化流程 2. 基于HyperOpt实现TPE优化 2.1 定义目标函数 2.2 定义参数空间 2.3 定义优化目标函数的…

Asp.Net WebForm ViewState

ViewState用于保存服务器控件(runat"server")状态便于在触发回调后&#xff08;PostBack&#xff09;恢复页面。 页面拖入一个Form id"form1" runat"server",里面添加一个<asp:Button id"Button1" Text"删除" OnClick&q…

python:对 GEDI 数据进行高斯滤波处理

作者:CSDN @ _养乐多_ 在本篇博客中,我们将学习如何使用 Python 对 GEDI(Global Ecosystem Dynamics Investigation)激光雷达数据进行高斯滤波处理。高斯滤波是一种平滑滤波方法,可以有效减少噪声和突变,提高数据的平滑性和连续性。我们将使用 pandas 和 scipy.signal 库…

STM32MP157驱动开发——LED 驱动( GPIO 子系统)

文章目录 编写思路GPIO子系统的LED驱动程序(stm32mp157)如何找到引脚功能和配置信息在设备树中添加 Pinctrl 信息leddrv.cledtest.cMakefile编译测试 编写思路 阅读&#xff1a;STM32MP157驱动开发——GPIO 和 和 Pinctrl 子系统的概念可知利用GPIO子系统去编写LED驱动&#x…

Mysql基础(下)之函数,约束,多表查询,事务

&#x1f442; 回到夏天&#xff08;我多想回到那个夏天&#xff09; - 傲七爷/小田音乐社 - 单曲 - 网易云音乐 截图自 劈里啪啦 -- 黑马Mysql&#xff0c;仅学习使用 &#x1f447;原地址 47. 基础-多表查询-表子查询_哔哩哔哩_bilibili 目录 &#x1f982;函数 &#x1f3…

Spark(35):Structured Streaming 概述

目录 0. 相关文章链接 1. 什么是Structured Streaming 2. Structure Streaming 快速入门 2.1. 导入依赖 2.2. 代码实现 2.3. 程序测试 2.4. 代码说明 0. 相关文章链接 Spark文章汇总 1. 什么是Structured Streaming 从 spark2.0 开始, spark 引入了一套新的流式计算模…

新Viewport单位

本文为翻译本文译者为 360 奇舞团前端开发工程师原文标题&#xff1a;New Viewport Units原文作者&#xff1a;Ahmad Shadeed原文地址&#xff1a;https://ishadeed.com/article/new-viewport-units/ 自 2012 年以来&#xff0c;我们一直在使用 CSS viewport 单位。它们对于帮助…

RGB简单人脸活体检测(Liveness Detection)

参考&#xff1a; https://github.com/minivision-ai/Silent-Face-Anti-Spoofing&#xff08;主要这个库&#xff09; https://github.com/computervisioneng/face-attendance-system&#xff08;使用案例&#xff09; ##概念&#xff1a; 活体检测是指针对人脸识别过程中的人脸…