一个注解轻松搞定审计日志服务!

2024-08-22 00:12

本文主要是介绍一个注解轻松搞定审计日志服务!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

审计日志】,简单的说就是系统需要记录谁,在什么时间,对什么数据,做了什么样的更改!任何一个 IT 系统,如果要过审,这项任务基本上也是必审项!

实现【审计日志】这个需求,我们有一个很好的技术解决方案,就是使用 Spring 的切面编程。

  • 先创建审计日志表

图片

然后编写一个注解类

图片

接着编写一个代理类

@Component
@Aspect
public class SystemAuditLogAspect {@Autowiredprivate SystemAuditLogService systemAuditLogService;/*** 定义切入点,切入所有标注此注解的类和方法*/@Pointcut("@within(com.example.demo.core.annotation.SystemAuditLog)|| @annotation(com.example.demo.core.annotation.SystemAuditLog)")public void methodAspect() {}/*** 方法调用前拦截*/@Before("methodAspect()")public void before(){System.out.println("SystemAuditLog代理 -> 调用方法执行之前......");}/*** 方法调用后拦截*/@After("methodAspect()")public void after(){System.out.println("SystemAuditLog代理 -> 调用方法执行之后......");}/*** 调用方法结束拦截*/@AfterReturning(value = "methodAspect()")public void afterReturning(JoinPoint joinPoint) throws Exception {System.out.println("SystemAuditLog代理 -> 调用方法结束拦截......");//封装数据AuditLog entity = warpAuditLog(joinPoint);entity.setResult(0);//插入到数据库systemAuditLogService.add(entity);}/*** 抛出异常拦截*/@AfterThrowing(value="methodAspect()", throwing="ex")public void afterThrowing(JoinPoint joinPoint, Exception ex) throws Exception {System.out.println("SystemAuditLog代理 -> 抛出异常拦截......");//封装数据AuditLog entity = warpAuditLog(joinPoint);entity.setResult(1);//封装错误信息entity.setExMsg(ex.getMessage());//插入到数据库systemAuditLogService.add(entity);}/*** 封装插入实体* @param joinPoint* @return* @throws Exception*/private AuditLog warpAuditLog(JoinPoint joinPoint) throws Exception {//获取请求上下文HttpServletRequest request = getHttpServletRequest();//获取注解上的参数值SystemAuditLog systemAuditLog = getServiceMethodDescription(joinPoint);//获取请求参数Object requestObj = getServiceMethodParams(joinPoint);//封装数据AuditLog auditLog = new AuditLog();auditLog.setId(SnowflakeIdWorker.getInstance().nextId());//从请求上下文对象获取相应的数据if(Objects.nonNull(request)){auditLog.setUserAgent(request.getHeader("User-Agent"));//获取登录时的ip地址auditLog.setIpAddress(IpAddressUtil.getIpAddress(request));//调用外部接口,获取IP所在地auditLog.setIpAddressName(IpAddressUtil.getLoginAddress(auditLog.getIpAddress()));}//封装操作的表和描述if(Objects.nonNull(systemAuditLog)){auditLog.setTableName(systemAuditLog.tableName());auditLog.setOperateDesc(systemAuditLog.description());}//封装请求参数auditLog.setRequestParam(JSON.toJSONString(requestObj));//封装请求人if(Objects.nonNull(requestObj) && requestObj instanceof BaseRequest){auditLog.setOperateUserId(((BaseRequest) requestObj).getLoginUserId());auditLog.setOperateUserName(((BaseRequest) requestObj).getLoginUserName());}auditLog.setOperateTime(new Date());return auditLog;}/*** 获取当前的request* 这里如果报空指针异常是因为单独使用spring获取request* 需要在配置文件里添加监听** 如果是spring项目,通过下面方式注入* <listener>* <listener-class>* org.springframework.web.context.request.RequestContextListener* </listener-class>* </listener>** 如果是springboot项目,在配置类里面,通过下面方式注入* @Bean* public RequestContextListener requestContextListener(){*     return new RequestContextListener();* }* @return*/private HttpServletRequest getHttpServletRequest(){RequestAttributes ra = RequestContextHolder.getRequestAttributes();ServletRequestAttributes sra = (ServletRequestAttributes)ra;HttpServletRequest request = sra.getRequest();return request;}/*** 获取请求对象* @param joinPoint* @return* @throws Exception*/private Object getServiceMethodParams(JoinPoint joinPoint) {Object[] arguments = joinPoint.getArgs();if(Objects.nonNull(arguments) && arguments.length > 0){return arguments[0];}return null;}/*** 获取自定义注解里的参数* @param joinPoint* @return 返回注解里面的日志描述* @throws Exception*/private SystemAuditLog getServiceMethodDescription(JoinPoint joinPoint) throws Exception {//类名String targetName = joinPoint.getTarget().getClass().getName();//方法名String methodName = joinPoint.getSignature().getName();//参数Object[] arguments = joinPoint.getArgs();//通过反射获取示例对象Class targetClass = Class.forName(targetName);//通过实例对象方法数组Method[] methods = targetClass.getMethods();for(Method method : methods) {//判断方法名是不是一样if(method.getName().equals(methodName)) {//对比参数数组的长度Class[] clazzs = method.getParameterTypes();if(clazzs.length == arguments.length) {//获取注解里的日志信息return method.getAnnotation(SystemAuditLog.class);}}}return null;}
}
  • 最后,只需要在对应的接口或者方法上添加审计日志注解即可

图片

  • 相关的实体类

@Data
public class AuditLog {/*** 审计日志,主键ID*/private Long id;/*** 操作的表名,多个用逗号隔开*/private String tableName;/*** 操作描述*/private String operateDesc;/*** 请求参数*/private String requestParam;/*** 执行结果,0:成功,1:失败*/private Integer result;/*** 异常信息*/private String exMsg;/*** 请求代理信息*/private String userAgent;/*** 操作时设备IP*/private String ipAddress;/*** 操作时设备IP所在地址*/private String ipAddressName;/*** 操作时间*/private Date operateTime;/*** 操作人ID*/private String operateUserId;/*** 操作人*/private String operateUserName;
}
public class BaseRequest implements Serializable {/*** 请求token*/private String token;/*** 登录人ID*/private String loginUserId;/*** 登录人姓名*/private String loginUserName;public String getToken() {return token;}public void setToken(String token) {this.token = token;}public String getLoginUserId() {return loginUserId;}public void setLoginUserId(String loginUserId) {this.loginUserId = loginUserId;}public String getLoginUserName() {return loginUserName;}public void setLoginUserName(String loginUserName) {this.loginUserName = loginUserName;}
}
@Data
public class UserLoginDTO extends BaseRequest {/*** 用户名*/private String userName;/*** 密码*/private String password;
}

整个程序的实现过程,主要使用了 Spring AOP 特性,对特定方法进行前、后拦截,从而实现业务方的需求。

最后说一句(求关注!别白嫖!)

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记  就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

这篇关于一个注解轻松搞定审计日志服务!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1094682

相关文章

自定义注解SpringBoot防重复提交AOP方法详解

《自定义注解SpringBoot防重复提交AOP方法详解》该文章描述了一个防止重复提交的流程,通过HttpServletRequest对象获取请求信息,生成唯一标识,使用Redis分布式锁判断请求是否... 目录防重复提交流程引入依赖properties配置自定义注解切面Redis工具类controller

Mysql中RelayLog中继日志的使用

《Mysql中RelayLog中继日志的使用》MySQLRelayLog中继日志是主从复制架构中的核心组件,负责将从主库获取的Binlog事件暂存并应用到从库,本文就来详细的介绍一下RelayLog中... 目录一、什么是 Relay Log(中继日志)二、Relay Log 的工作流程三、Relay Lo

MySQL日志UndoLog的作用

《MySQL日志UndoLog的作用》UndoLog是InnoDB用于事务回滚和MVCC的重要机制,本文主要介绍了MySQL日志UndoLog的作用,文中介绍的非常详细,对大家的学习或者工作具有一定的... 目录一、Undo Log 的作用二、Undo Log 的分类三、Undo Log 的存储四、Undo

Springboot请求和响应相关注解及使用场景分析

《Springboot请求和响应相关注解及使用场景分析》本文介绍了SpringBoot中用于处理HTTP请求和构建HTTP响应的常用注解,包括@RequestMapping、@RequestParam... 目录1. 请求处理注解@RequestMapping@GetMapping, @PostMappin

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Python轻松实现Word到Markdown的转换

《Python轻松实现Word到Markdown的转换》在文档管理、内容发布等场景中,将Word转换为Markdown格式是常见需求,本文将介绍如何使用FreeSpire.DocforPython实现... 目录一、工具简介二、核心转换实现1. 基础单文件转换2. 批量转换Word文件三、工具特性分析优点局

Python中4大日志记录库比较的终极PK

《Python中4大日志记录库比较的终极PK》日志记录框架是一种工具,可帮助您标准化应用程序中的日志记录过程,:本文主要介绍Python中4大日志记录库比较的相关资料,文中通过代码介绍的非常详细,... 目录一、logging库1、优点2、缺点二、LogAid库三、Loguru库四、Structlogphp

nacos服务无法注册到nacos服务中心问题及解决

《nacos服务无法注册到nacos服务中心问题及解决》本文详细描述了在Linux服务器上使用Tomcat启动Java程序时,服务无法注册到Nacos的排查过程,通过一系列排查步骤,发现问题出在Tom... 目录简介依赖异常情况排查断点调试原因解决NacosRegisterOnWar结果总结简介1、程序在

Spring Boot/Spring MVC核心注解的作用详解

《SpringBoot/SpringMVC核心注解的作用详解》本文详细介绍了SpringBoot和SpringMVC中最常用的15个核心注解,涵盖了请求路由映射、参数绑定、RESTfulAPI、... 目录一、Spring/Spring MVC注解的核心作用二、请求映射与RESTful API注解系列2.1

Springmvc常用的注解代码示例

《Springmvc常用的注解代码示例》本文介绍了SpringMVC中常用的控制器和请求映射注解,包括@Controller、@RequestMapping等,以及请求参数绑定注解,如@Request... 目录一、控制器与请求映射注解二、请求参数绑定注解三、其他常用注解(扩展)四、注解使用注意事项一、控制