• AOP切面日志


    最近在公司做项目的时候,需要实现甲方的一个需求,修改操作的记录。
    XXX被谁修改为了XXX
    这个看起来很简单,例如修改只要得到参数的实体类Vo然后进行记录就行,但是在进行修改记录和新增记录的时候就会有问题了,首先update方法是可以得到主键ID的,因为是updateById,而新增是进行主键自增的,而删除如果是记录之前的数据就需要根据ID先去查然后再去删除。
    这三个其实对应的就是切面的三个顺序
    @After @Around @Before
    对于删除操作应该对应的是@Before需要在执行之间,先去完成查询,然后再由进程完成删除。
    对应修改则应该使用@Before。
    对应新增应该是@After操作,不然无法获得到Id。
    其实AOP的注解还有另外两种。

    • @Before: 前置通知, 在方法执行之前执行
    • @After: 后置通知, 在方法执行之后执行 。
    • @AfterRunning: 返回通知, 在方法返回结果之后执行
    • @AfterThrowing: 异常通知, 在方法抛出异常之后
    • @Around: 环绕通知, 围绕着方法执行

    简单说一下我是如何实现日志记录的。
    首先是需求:

     由于在权限方面我是用了shiro进行管理,所以我可以通过shiro的subject获得到我需求的“人名”

    String username = ((MemberEntity) SecurityUtils.getSubject().getPrincipal()).getName();
    

      

    然后我需要获得到发生切面的具体模块,这边可以有很多方法,例如通过方法判断
     
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    

      

    我选择是的根据注解名字的不同来进行判断,然后通过具体的Key值得到我需要的value。
     
    if ("新增合同".equals(syslog.value())) {
    			//处理参数
    			Object[] args = joinPoint.getArgs();
    			//处理为Json字符串
    			String params = new Gson().toJson(args);
    			//处理字符串的[]
    			String replace = params.replace("[", "");
    			String s = replace.replace("]", "");
    			System.out.println(s);
    			//处理为Json对象
    			JSONObject jsonObject = JSON.parseObject(s);
    			//得到合同ID号
    			Object contractId = jsonObject.get("contractId");
    			//得到炼厂计划ID
    			Object filiale_plan_id = jsonObject.get("filialePlanId");
    			Integer ID = Integer.valueOf(String.valueOf(filiale_plan_id));
    			//得到合同号
    			Object contracts = jsonObject.get("contracts");
    			//得到合同价格
    			Object agreement_price = jsonObject.get("agreementPrice");
    			//得到资源大体流向
    			Object resource_stream = jsonObject.get("resourceStream");
    			log.append(username).append("新增了合同,合同号为:").append(contracts).append(",合同价格为:").append(agreement_price);
    			sysLog.setParams(log.toString());
    			sysLog.setFilialePlanId(ID);
    		}
    

      

    这样写的缺点就是无法复用,只能针对某一个去写,所以这个需求我一共写了388行代码.....很笨重,后续是肯定要修改这个方法的。

    AOP只是一个概念并没有设定具体语言的实现,它能克服那些只有单继承特性语言的缺点。实现AOP的技术主要分为两类:一类是采用动态代理技术利用截取消息的方式,对消息进行装饰以取代原有对象行为的执行。另一类是采用静态织入的方式,引入特定语法创建切面,从而使编译器可以在编译期间织入相关的切面代码。
     
    切面的使用:
    1.切入点:对哪些方法进行拦截,拦截后怎样处理。应用通知进行增强的目标方法
    2.切面:也就是具体的写代码的地方(例如日志模块)。是切入点和通知的结合
    3.连接点:连接点是程序执行过程中明确的点,一般是类中方法的调用。连接点是程序在运行过程中能够插入切面的地点,比如方法调用、异常抛出、字段修改等。连接点就是可以应用通知进行增强的方法

     案例代码:

    @Aspect
    @Component
    public class SysLogAspect {
    
    	@Pointcut("@annotation(io.ref.common.annotation.SysLog)")
    	public void logPointCut() { 
    		
    	}
    
    	@Before("logPointCut()")
    	public Object before(JoinPoint point) throws Throwable {
    		long beginTime = System.currentTimeMillis();
    		//执行方法
    		Object result = point.getTarget();
    		//执行时长(毫秒)
    		long time = System.currentTimeMillis() - beginTime;
    		//保存日志
    		saveSysLog(point, time);
    
    		return result;
    	}
    	private void saveSysLog(JoinPoint 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());
    		}
    
    		//获取request
    		HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
    		//设置IP地址
    		sysLog.setIp(IPUtils.getIpAddr(request));
    
    		//用户名
    		String username = ((MemberEntity) SecurityUtils.getSubject().getPrincipal()).getName();
    		sysLog.setName(username);
    

      

  • 相关阅读:
    Nginx+keepalived高可用配置
    kubespahere安装kubenetes
    Fastdfs原理及集群搭建
    Spark 3.0.3集群安装文档
    Mybatis Plus 代码生成器
    redis集群方案
    Go 语言并发之道
    重构-改善即有代码的设计
    QT线程
    QT中的cout
  • 原文地址:https://www.cnblogs.com/SmartCat994/p/13023268.html
Copyright © 2020-2023  润新知