通过AOP切面实现系统各个模块的用户操作记录

需求:查看系统各个模块的用户操作记录,通过AOP切面实现,在不同模块的增删改接口上加切面注解

部分示例代码如下,剩下的自行补充

流程:
1.根据配置确定是否启用用户操作记录。UserTraceAspectCondition:实现Condition接口的matches方法,根据配置文件决定是否初始化类
2.切面配置类:AspectConfig 增加@Configuration和 @Bean注解,根据@Conditional注解来确定确认切面的执行条件。配置开启的话,实例化切面类;增加切面注解@interface OperateLog,定义UserTraceAspect切面类代表用户操作痕迹的服务类、操作模块、操作类型、操作内容等参数
3.切面具体实现类:增加@Aspect注解,方法上增加@AfterReturning @AfterThrowing,分别在方法返回后执行切面方法或抛出异常后执行切面方法
4.接口上增加@OperateLog切面注解,并指定该接口对应的模块参数和操作类型的参数、及根据切面处理用户的操作痕迹类(默认DefaultOperateLogServiceImpl)

AspectConfig 切面配置类
UserTraceAspect:用户操作痕迹切面类
@annotation(operateLog)
@interface OperateLog
ApplicationContextUtil.getBean(operateLog.operateLogService()); 接口切面注解上对operateLogService进行了赋值
注意点:处理切面的类分为正常返回对象的切面或者抛出异常的切面;处理用户操作记录的切面处理类的事务是新建的,不影响前面业务操作;切点JoinPoint 的.getArgs方法能从方法中或请求中获取参数值,如果以对象接口的,在方法中无法获取参数值,需要通过request.getParameter(parameter) 获取参数值

UserTraceAspectCondition implements Condition{

@Override

publlic Boolean matches(conditionContext.getEnvironment().getProperty("ams.userTrace.use"))

}

@Configuration

AspectConfig {

@Bean

@Conditional(UserTraceAspectCondition.class)

public UserTraceAspect uerTraceAspect(){

return new UserTraceAspect();

}

}

切面注解

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface OperateLog {

Class<? extends  OperateLogService> operateLogService() default  DefaultOperateLogServiceImpl.class;

OperateModule operateModule();

OperateType operateType();

String operateContent() default "";

boolean cover() default false;

}

切面类

@Slf4j

@Aspect

UserTraceAspect {

@AfterReturning(value = "@annotation(operateLog)",returning = "object")

public void doAterReturning(JoinPoint joinPoint, OperateLog operateLog ,Object object)throws Throwable{

try{

OperateLogService operateLogService = ApplicationContextUtil.getBean(operateLog.operateLogService());

operateLogService.process(joinPoint,getUserTraceDTO(operateLog),object);

}catch (Exception e){

log.warn("保存用户操作痕迹时发生异常:",e);

}

异常情况

public  void doAfterThrowing(JoinPoint joinPoint, OperateLog operateLog, Throwable e) throws Throwable{

try{

OperateLogService operateLogService = ApplicationContextUtil.getBean(operateLog.operateLogService());

operateLogService.process(joinPoint,getUserTraceDTO(operateLog),e);

}catch (Exception e2){

log.warn("保存用户操作痕迹时发生异常:",e2);

}

}

@Service

public class DefaultOperateLogServiceImpl extends AbstractOperateLogService{

@Override

@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)

public void process(JoinPoint joinPoint, UserTraceDTO userTraceDTO)throws Exception {

super.process(joinPoint,userTraceDTO);

setOperateContent(joinPoint,userTraceDTO);

userTraceService.insert(userTraceDTO);

}

abstract class AbstractOperateLogService implements OperateLogService {

@Override

public void process(JoinPoint joinPoint, UserTraceDTO userTraceDTO) throws Exception{

//默认成功

userTraceDTO.setOperateResult(Boolean.TRUE);

userTraceDTO.setUsername(SecurityUtils.getCurrentUsername());

userTraceDTO.setOrganFullId(SecurityUtils.getCurrentOrgFullId());

userTraceDTO.setOperateDate(new Date());

userTraceDTO.setClassName(joinPoint.getSignature().getDeclaringTypeName());

userTraceDTO.setMethodName(joinPoint.getSignature().getName());

}

@Slf4j@Servicepublic class ConfigOperateLogServiceImpl extends AbstractOperateLogService{

}

public Object getParameter(JoinPoint joinPoint,String parameter) throws Exception{

// 参数值

Object[] args = joinPoint.getArgs();

// 参数名

String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();

//参数打印

for (int i = 0,length = argNames.length;i<length;i++) {

if (parameter.equals(argNames[i])){

return args[i];

}

}

//参数形式提交请求的,对象形式提交请求的需要以request

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

return request.getParameter(parameter);

}

对应用户模块接口上增加切面注解,默认执行DefaultOperateLogServiceImpl

@OperateLog(operateModule = OperateModule.USER,operateType = OperateType.INSERT)
@OperateLog(operateModule = OperateModule.USER,operateType = OperateType.UPDATE)
@OperateLog(operateModule = OperateModule.USER,operateType = OperateType.DELETE)
需要指定执行模块的加上operateLogService参数,做二次开发@OperateLog(operateLogService = ConfigOperateLogServiceImpl.class,operateModule = OperateModule.CONFIG,operateType = OperateType.UPDATE)

原文地址:https://www.cnblogs.com/renjiaqi/p/12418716.html

时间: 2024-10-03 22:09:46

通过AOP切面实现系统各个模块的用户操作记录的相关文章

linux 系统登录用户操作记录

1,mkdir /usr/local/proxy cat proxy #!/bin/bashUser=$USERIp=${SSH_CLIENT%% *}Date="`date +%Y-%m-%d`"Logfile=/var/log/myaudit/${User}_${Ip}_${Date}.log#export Logfile=/var/log/myaudit/${User}_${Ip}_${Date}.logexport PROMPT_COMMAND='{ date "+%

SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务

本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部

使用Spring AOP切面解决数据库读写分离

http://blog.jobbole.com/103496/ 为了减轻数据库的压力,一般会使用数据库主从(master/slave)的方式,但是这种方式会给应用程序带来一定的麻烦,比如说,应用程序如何做到把数据写到master库,而读取数据的时候,从slave库读取.如果应用程序判断失误,把数据写入到slave库,会给系统造成致命的打击. 解决读写分离的方案很多,常用的有SQL解析.动态设置数据源.SQL解析主要是通过分析sql语句是insert/select/update/delete中的哪

Spring AOP 切面编程记录日志和接口执行时间

最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx.tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特别长.知道了问题之后,就需要对查询比较慢的接口进行优化,但哪些接口需要优化.哪些不需要呢?只能通过日志里的执行时间来判断,那么如何才能知道每一个接口的执行时间呢? 如果想学习Java工程化.高性能及分布式.深入浅出.微服务.Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级

综合案例-整合办公系统后台模块

综合案例-整合办公系统后台模块 1.配置虚拟主机(如www.think.com) 2.配置hosts文件并重启Apache服务器 3.复制ThinkPHP核心文件到项目的目录中(如think目录) 4.创建Zend工程 5.创建index.php入口文件(编写四步走) 6.划分项目前后台模块 设置配置文件(./Application/Common/Conf/config.php) 7.创建Public控制器并定义login方法 编写控制器三步走 8.设置URL调度模式 9.复制模板资源到Publ

让你提前认识软件开发(52):系统某模块工作原理详述

第3部分 软件研发工作总结 系统某模块工作原理详述 [文章摘要] 某模块在系统中占有非常重要的地位,该模块能够对符合条件的动态信箱进行清理.本模块直接清理的信箱包括:过期动态信箱.冷冻信箱和空动态信箱:删除非动态信箱由本模块发送消息到其它模块完成. 本文对该模块的工作原理的详细介绍,为相关模块的开发和测试提供了有益的参考,同时也有利于现场人员对本模块进行维护. [关键词] 系统  模块  数据库  流程 1. 本模块删除的信箱类型 本模块删除的信箱类型如图1所示: 图1 本模块删除的信箱类型 2

Linux -- Samba-PAM模块应用-系统密码同步;用户与客户端访问控制;磁盘配额;回收站

PAM模块应用 Samba服务器3.X与PAM模块结合已非常完善,通过PAM模块的强大功能可以有效地丰富Samba服务器的各项功能. 6.4.1  系统密码同步 Samba服务器使用完全独立于系统之外的用户认证,这样的好处是可以提高安全性,但同样也带来了一些麻烦,比如修改用户密码是即要修改该用户登录系统的密码,又要修改登录Samba服务器的密码.但通过PAM模块所提供的功能可以有效实现系统用户密码与Samba服务器密码的自动同步. 使用passwd修改用户系统密码时,自动同步Samba服务器用户

spring AOP切面日志 拦截方法中有同名方法问题

代码: @ResponseBody @RequestMapping("/login.do") public Json login(SysUserPM sysUserPM, HttpSession session) { Json j = new Json(); SysUserPM sysUser = sysUserServiceI.doLogin(sysUserPM); if (sysUser != null) { System.out.println("后台用户登录成功!&q

动态代理和AOP切面编程

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* * 动态代理和AOP切面编程 */ //定义一个接口 interface Person { void eat(); void breath(); } // 定义一个实现接口的实现类,即为被代理类 class Student implements Person { @Overr