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】

相关内容

热门资讯

原创 5... 导读:每年除夕的年夜饭,是当天的重头戏,看着桌上热气腾腾的菜,身边坐着最亲的人,窗外万家灯火,这一顿...
(新春见闻)青海湟源: 日月山... 2月16日,中国农历除夕,才仁顿珠(左)教晚辈制作枣树,祈福新年风调雨顺,农作物丰收。当农历春节遇上...
团圆年夜饭:老字号里尝新“味” “味道正宗,性价比高,我们家过年少不了这道菜!”除夕当天,成都市民张大爷早早来到成都市锦江区华兴正街...
超100桌、每桌22道菜,成都... 100多桌,每桌22道菜,天南海北的乡音在此刻交融成一片热闹的“家”。2月15日,彭州利济村请500...
春节荐剧 | 适合全家老小一起... 新春佳节,全家老小欢聚一堂,客厅里的电视应该放点啥也是门学问,既要有合家欢的氛围,可以当成家庭聚会聊...