package com.casic.missiles.aop; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.casic.missiles.annotation.EquipmentLog; import com.casic.missiles.core.application.service.AbstractAuthService; import com.casic.missiles.core.model.auth.AuthUser; import com.casic.missiles.model.equipment.EquipmentInfo; import com.casic.missiles.model.equipment.EquipmentModifyLog; import com.casic.missiles.service.equipment.IEquipmentInfoService; import com.casic.missiles.service.equipment.IEquipmentModifyLogService; import com.casic.missiles.utils.CasicBeanUtil; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.stereotype.Component; import java.beans.Expression; import java.lang.reflect.Method; import java.util.Date; import java.util.Optional; @Aspect @Component @EnableAsync @Slf4j public class EquipmentLogAop { @Autowired private IEquipmentInfoService equipmentInfoService; @Autowired private IEquipmentModifyLogService modifyLogService; @Autowired private AbstractAuthService authService; /** * 用于SpEL表达式解析. */ private final SpelExpressionParser parser = new SpelExpressionParser(); /** * 用于获取方法参数定义名字. */ private final DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer(); private Long equipmentId; private EquipmentInfo oldInfo; /** * 注解的位置 */ @Pointcut("@annotation(com.casic.missiles.annotation.EquipmentLog)") public void logPointCut() {} @Before(value="logPointCut()") public void before(JoinPoint joinPoint) throws Exception { equipmentId = getEquipmentId(joinPoint); if(ObjectUtil.isNotEmpty(equipmentId)){ oldInfo = equipmentInfoService.getById(equipmentId); }else { oldInfo = null; } } private Long getEquipmentId(JoinPoint joinPoint) throws Exception { //1.1获取目标对象对应的字节码对象 Class<?> targetCls= joinPoint.getTarget().getClass(); //1.2获取目标方法对象 //1.2.1 获取方法签名信息从而获取方法名和参数类型 Signature signature= joinPoint.getSignature(); //1.2.1.1将方法签名强转成MethodSignature类型,方便调用 MethodSignature ms= (MethodSignature)signature; //1.2.2通过字节码对象以及方法签名获取目标方法对象 Method targetMethod=targetCls.getDeclaredMethod(ms.getName(),ms.getParameterTypes()); //1.3获取目标方法对象上注解中的属性值 //1.2.3 获取方法上的自定义requiredLog注解 EquipmentLog equipmentLog=targetMethod.getAnnotation(EquipmentLog.class); String val = generateKeyBySpEL(equipmentLog.key(), joinPoint); return ObjectUtil.isNotEmpty(val) ? Long.valueOf(val) : null; } // @Async @After(value="logPointCut()") public void after(JoinPoint joinPoint){ if(ObjectUtil.isNotEmpty(equipmentId) && ObjectUtil.isNotEmpty(oldInfo)){ EquipmentInfo newInfo = equipmentInfoService.getById(equipmentId); log.info("equipment info:{}, {},{}",equipmentId,JSONObject.toJSON(oldInfo),JSONObject.toJSON(newInfo)); JSONArray res = CasicBeanUtil.fieldCompareDetail(oldInfo,newInfo,null); if(ObjectUtil.isNotEmpty(res) && res.size() > 0){ StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < res.size(); i++) { JSONObject item = res.getJSONObject(i); String filedName = equipmentInfoService.getFieldName(item.getString("field")); if(StrUtil.isNotBlank(filedName)){ String oldValue = equipmentInfoService.getFieldValue(item.getString("field"),item.getString("oldVal")); String newValue = equipmentInfoService.getFieldValue(item.getString("field"),item.getString("newVal")); String msg = String.format("[%s]由 %s 变更为 %s;\n\r",filedName, StrUtil.isNotBlank(oldValue) ? oldValue : "空值", StrUtil.isNotBlank(newValue) ? newValue : "空值"); // String msg = String.format("字段名=%s,变更前=%s,变更后=%s;",filedName,oldValue,newValue); stringBuilder.append(msg); } } log.info("equipment modify: {}",stringBuilder); saveLog(equipmentId,stringBuilder.toString()); } } } private void saveLog(Long equipmentId,String content){ if(StrUtil.isNotBlank(content)){ EquipmentModifyLog modifyLog = new EquipmentModifyLog(); modifyLog.setEquipmentId(equipmentId); modifyLog.setContent(content); modifyLog.setOperateTime(new Date()); AuthUser authUser = authService.getLoginUser(); if(ObjectUtil.isNotEmpty(authUser)){ modifyLog.setOperateUserId(authUser.getId()); } modifyLogService.save(modifyLog); } } public String generateKeyBySpEL(String spELString, JoinPoint joinPoint) throws Exception { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod()); SpelExpression expression = (SpelExpression) parser.parseExpression(spELString); EvaluationContext context = new StandardEvaluationContext(); Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { context.setVariable(paramNames[i], args[i]); } return expression.getValue(context).toString(); } }