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);

  

posted @ 2020-06-01 08:46  smartcat994  阅读(376)  评论(0编辑  收藏  举报