Newer
Older
casic-metering-eqpt-xichang / casic-metering-service / src / main / java / com / casic / missiles / aop / EquipmentLogAop.java
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();
    }
}