SpringBoot @Aspect 自定义注解记录系统日志【SpringBoot系列19】
创始人
2025-05-31 01:47:06

SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见。
程序员每天的CV 与 板砖,也要知其所以然,本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCloud 微服务系列项目开发

我的需求是 用户修改了基本信息,管理员从管理后台可以查询到相关的记录。

1 自定义 SysLog 注解

import java.lang.annotation.*;/*** 系统日志注解* * @author 早起的年轻人* @date 2023年3月8日*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {String value() default "";
}
  • @Retention修饰注解,用来表示注解的生命周期,生命周期的长短取决于@Retention的属性RetentionPolicy指定的值

    • RetentionPolicy.SOURCE 表示注解只保留在源文件,当java文件编译成class文件,就会消失 源文件 只是做一些检查性的操作,

    • RetentionPolicy.CLASS 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期 class文件(默认) 要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife)

    • RetentionPolicy.RUNTIME 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 运行时也存在 需要在运行时去动态获取注解信息

  • @Target 说明了Annotation所修饰的对象范围

    • 1.CONSTRUCTOR:用于描述构造器
    • 2.FIELD:用于描述域
    • 3.LOCAL_VARIABLE:用于描述局部变量
    • 4.METHOD:用于描述方法
    • 5.PACKAGE:用于描述包
    • 6.PARAMETER:用于描述参数
    • 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

2 自定义 @Aspect 切面获取用户行为

添加依赖如下,版本要对应自己的 SpringBoot 版本,我这使用的是 2.7.9 版本

 org.springframework.bootspring-boot-starter-aop2.7.9

AOP:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。而@Aspect 就是把一个类定义为切面供容器读取。

@Aspect
@Component
public class SysLogAspect {@Autowiredprivate SysLogService sysLogService;/*** 自己定义的注解*/@Pointcut("@annotation(com.biglead.demo.anno.SysLog)")public void logPointCut() {}@Around("logPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {long beginTime = System.currentTimeMillis();//执行方法Object result = point.proceed();//执行时长(毫秒)long time = System.currentTimeMillis() - beginTime;//保存日志saveSysLog(point, time);return result;}private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();SysLogEntity sysLog = new SysLogEntity();SysLog syslog = method.getAnnotation(SysLog.class);if (syslog != null) {//注解上的描述sysLog.setOperation(syslog.value());}//请求的方法名String className = joinPoint.getTarget().getClass().getName();String methodName = signature.getName();sysLog.setMethod(className + "." + methodName + "()");//请求的参数Object[] args = joinPoint.getArgs();try {String params = new Gson().toJson(args[0]);if (params.length() > 1000) {params = params.substring(0, 500);}sysLog.setParams(params);} catch (Exception e) {}//获取requestHttpServletRequest request = HttpContextUtils.getHttpServletRequest();//设置IP地址sysLog.setIp(IPUtils.getIpAddr(request));//用户名是用户IDString username = request.getHeader("userId");sysLog.setUsername(username);sysLog.setTime(time);sysLog.setCreateDate(new Date());//保存系统日志sysLogService.save(sysLog);}
}
  • @before: 前置通知,在方法执行之前执行。
  • @After:后置通知,在方法执行后执行。
  • @AfterReturning: 返回通知,在方法返回结果之后执行。
  • @AfterThrowing:异常通知,在方法抛出异常之后执行。
  • @Around:环绕通知,围绕着方法执行。

3 SysLogService 就是自己实现的操作数据保存这一系列

3.1 数据模型

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;import java.io.Serializable;
import java.util.Date;/*** 系统日志* * @author 早起的年轻人* @date 2012-03-08 */
@TableName("sys_log")
@Data
@AllArgsConstructor
public class SysLogEntity implements Serializable {private static final long serialVersionUID = 1L;@TableIdprivate Long id;//用户名private String username;//用户操作private String operation;//请求方法private String method;//请求参数private String params;//执行时长(毫秒)private Long time;//IP地址private String ip;//创建时间private Date createDate;
}
3.2 数据库sql
3.3 Service
public interface SysLogService extends IService {/*** 管理后台 分页查询日志* @return*/Page queryPage(Integer pageInex, Integer pageSize);
}
@Service("sysLogService")
public class SysLogServiceImpl extends ServiceImpl implements SysLogService {@Overridepublic Page queryPage(Integer pageInex, Integer pageSize) {Page page = this.page(new Page<>(pageInex, pageSize), new QueryWrapper<>());return page;}
}
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.biglead.demo.pojo.SysLogEntity;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface SysLogDao extends BaseMapper {}

4 Controller 中的使用

直接在 Controller 的方法上添加 @SysLog 注解就可以实现自动记录日志的行为

@Api(tags="用户模块")
@RestController
@RequestMapping("user")
public class UserController {@SysLog("修改用户信息")@PostMapping(value="/update")@ApiOperation(value = "修改用户信息")public Object updateUser(@RequestBody UserInfo userInfo) {return userService.updateUser(userInfo);}
}

项目源码在这里 :https://gitee.com/android.long/spring-boot-study/tree/master/biglead-api-13-quartz
有兴趣可以关注一下公众号:biglead


  1. 创建SpringBoot基础项目
  2. SpringBoot项目集成mybatis
  3. SpringBoot 集成 Druid 数据源【SpringBoot系列3】
  4. SpringBoot MyBatis 实现分页查询数据【SpringBoot系列4】
  5. SpringBoot MyBatis-Plus 集成 【SpringBoot系列5】
  6. SpringBoot mybatis-plus-generator 代码生成器 【SpringBoot系列6】
  7. SpringBoot MyBatis-Plus 分页查询 【SpringBoot系列7】
  8. SpringBoot 集成Redis缓存 以及实现基本的数据缓存【SpringBoot系列8】
  9. SpringBoot 整合 Spring Security 实现安全认证【SpringBoot系列9】
  10. SpringBoot Security认证 Redis缓存用户信息【SpringBoot系列10】
  11. SpringBoot 整合 RabbitMQ 消息队列【SpringBoot系列11】
  12. SpringBoot 结合RabbitMQ与Redis实现商品的并发下单【SpringBoot系列12】
  13. SpringBoot 雪花算法生成商品订单号【SpringBoot系列13】
  14. SpringBoot RabbitMQ 延时队列取消订单【SpringBoot系列14】
  15. SpringBoot RabbitMQ 商品秒杀【SpringBoot系列15】
  16. SpringBoot ElasticSearch 【SpringBoot系列16】
  17. SpringBoot ElasticSearch 实现订单的分页查询 【SpringBoot系列17】
  18. SpringBoot 整合Quartz定时任务管理【SpringBoot系列18】

相关内容

热门资讯

蒙童守夜、龟蒙观日,记者见证近... 齐鲁晚报·齐鲁壹点记者 乔显佳2026年元旦期间,临沂蒙童胜境度假区、沂蒙山龟蒙景区联手组织“202...
原创 猪... 俗话说“小寒时处二三九,天寒地冻冷到抖”,眼下正值二九,小寒节气也快到了,这几天的温度已经下降到了零...
新的一年,蒸米饭请增加一个步骤 米饭在每日饮食中 有着不可或缺的地位 作为餐桌上的重要主食 怎么吃更健康? 蒸米饭时加点它,全身都受...
“新年第一面·大竹肉丁面”美食... 2026年1月1日,四川大竹县东湖广场人山人海、热气腾腾,“新年第一面·大竹肉丁面”美食嘉年华活动隆...
刘中才|《山家清供》里的冬日真... 江南的冬日,是湿冷且透骨的。若在不经意间逢上一场雪,天地便静默下来。在这样的日子里,我总会想起南宋林...