求助,想借助aop切入dataManage.save,在保存后执行一些操作

情况说明

项目中有一个文件管理模块,供用户创建文件夹,上传文件来管理文件。故此想把其他模块的文件统一维护到文件管理模块,根据注解中的path参数保存到相应的位置

问题

无法切入到对应的dataManage.save,想问一下来自依赖的类是无法切入吗,还是我的用法有问题呢?

代码

FileSync

/**
 * @author rockm3
 * 注解只能使用在类/接口/枚举
 * RetentionPolicy.RUNTIME:运行级别保留,编译后的class文件中存在,在jvm运行时保留,可以被反射调用。
 */
@Retention(value = RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface FileSync {
    // 保存路径
    String path();
}

FileSyncAspect

@Aspect
@Component
public class FileSyncAspect {
    private static final Logger log = org.slf4j.LoggerFactory.getLogger(FileSyncAspect.class);

    private Integer argsNum = -1;

    @Autowired
    private Metadata metadata;
    @Autowired
    private DataManager dataManager;

    /**
     * 保存或更新切点
     * */
    @Pointcut("execution(* io.jmix.core.impl.DataManagerImpl.save(..))")
    public void savePoint(){

    }

    /**
     * 删除切点
     * */
    @Pointcut("execution(* io.jmix.core.impl.DataManagerImpl.remove(..))")
    public void removePoint(){

    }


    /**
     * 前置通知
     * */
    @Before(value = "savePoint()")
    public void beforeSave(JoinPoint jp) {
        // 获取签名
        Signature signature = jp.getSignature();
        // 转为方法签名
        MethodSignature msg=(MethodSignature) signature;
        // 反射获取目标对象
        Object target = jp.getTarget();
        try {
            // 获取目标方法
            Method method = target.getClass().getMethod(msg.getName(), msg.getParameterTypes());
            Class<?>[] parameterTypes = method.getParameterTypes();
            this.argsNum = parameterTypes.length;

            if (parameterTypes.length == 1) {
                // 参数类型是SaveContext
                if (parameterTypes[0].equals(SaveContext.class)) {
                    this.argsNum = 0;
                }
            }

        } catch (Exception ignored) {

        }
    }

    /**
     * 返回通知
     * */
    @AfterReturning(value = "savePoint()", returning = "result")
    public void afterReturningSave(JoinPoint jp, Object result) {
        // 转存时使用save方法跳过转存检测
        if (result.getClass().equals(File.class)) {
            return;
        }
        if (this.argsNum > 0) {
            if (this.argsNum == 1) {
                List<Map<String,Object>> fileRefs = getFileRef(result);
                // 遍历保存
                if (fileRefs.size()>0) {
                    for (Map<String,Object> record:fileRefs) {
                        saveFileRef(record);
                    }
                }
            }
        } else if (this.argsNum == 0) {
            Object[] args = jp.getArgs();
            SaveContext saveContext = (SaveContext) args[0];
            Set<Object> entities = saveContext.getEntitiesToSave();
            saveFileRefAll(entities);
        }
    }

    /**
     * 异常通知
     * */
    @AfterThrowing(value = "savePoint()", throwing = "e")
    public void afterThrowingSave(JoinPoint jp, Exception e) {
        String name = jp.getSignature().getName();
        log.info(name + "方法抛异常了,异常是:" + e.getMessage());
    }

    /**
     * 实体对象转成Map
     * @param obj 实体对象
     */
    public static Map<String, Object> objectToMap(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (Exception e) {
            log.error("Error", e);
        }
        return map;
    }

    /**
     * @param entity 输入实体对象
     * @return 返回需要同步的文件对象和需要保存的路径
     * */
    private List<Map<String,Object>> getFileRef(Object entity) {
        MetaClass metaClass = metadata.getClass(entity);
        List<Map<String,Object>> fileRefs = new ArrayList<>();

        // 获取所有字段信息
        Collection<MetaProperty> allProperties = metaClass.getOwnProperties();
        for (MetaProperty record:allProperties) {
            // 定位到FileRef的位置
            if (record.getJavaType().equals(FileRef.class)) {
                // 获取当前字段的所有注解
                Annotation[] annotations = record.getAnnotatedElement().getAnnotations();
                // 遍历注解 寻找FileSync
                for (Annotation annotation:annotations) {
                    // 取到FileSync注解
                    if (annotation.annotationType().equals(FileSync.class)) {
                        // 强转
                        FileSync fileSync = (FileSync) annotation;
                        // 获取注解path值
                        String path = fileSync.path();
                        Map<String,Object> fileRef = new HashMap<>();
                        // 写入路径
                        fileRef.put("path",path);
                        // 写入字段名
                        fileRef.put("fieldName",record.getName());
                        fileRefs.add(fileRef);
                        break;
                    }
                }
            }
        }
        // 强转获取实体的对应map
        Map<String, Object> resultMap = objectToMap(entity);

        if (fileRefs.size()>0) {
            Iterator<Map<String,Object>> iterator = fileRefs.iterator();
            while (iterator.hasNext()) {
                Map<String,Object> record = iterator.next();
                String fieldName = (String) record.get("fieldName");
                Object fieldValue = resultMap.get(fieldName);
                if (fieldValue.getClass().equals(FileRef.class)) {
                    record.put("fieldValue",fieldValue);
                } else {
                    iterator.remove();
                }
            }
        }
        return fileRefs;
    }

    private void saveFileRef(Map<String, Object> record) {
        String path = (String) record.get("path");
        FileRef fileRef = (FileRef) record.get("fieldValue");
        // 检查path是否存在 不存在就创建
        String[] splitPath = path.split("/");
        FileFolder parentFileFolder = null;
        for (String s:splitPath) {
            try {
                parentFileFolder = dataManager
                        .load(FileFolder.class)
                        .query("select e from ef_FileFolder e where e.fileFolderName = :fileFolderName")
                        .parameter("fileFolderName",s)
                        .one();
            } catch (Exception ignored) {
                FileFolder fileFolder = dataManager.create(FileFolder.class);
                fileFolder.setFileFolderName(s);
                fileFolder.setCanDel(false);
                if (parentFileFolder == null) {
                    dataManager.save(fileFolder);
                } else {
                    fileFolder.setParentFileFolder(parentFileFolder);
                    dataManager.save(parentFileFolder,fileFolder);
                }
                parentFileFolder = fileFolder;
            }
        }
        // 更新或者新建
        // 更新
        try {
            assert parentFileFolder != null;
            File file = dataManager
                    .load(File.class)
                    .query("select e from ef_File e where e.file = :file and e.fileFolder = :fileFolder")
                    .parameter("file", fileRef)
                    .parameter("fileFolder", parentFileFolder)
                    .one();
        } catch (Exception ignored) {
            // 新建
            File file = dataManager.create(File.class);
            file.setFile(fileRef);
            file.setFileFolder(parentFileFolder);
            dataManager.save(file,parentFileFolder);
        }
    }

    private void saveFileRefAll(Set<Object> entities) {
        for (Object entity:entities) {
            if (entity.getClass().equals(File.class)) {
                continue;
            }

            List<Map<String,Object>> fileRefs = getFileRef(entity);
            // 遍历保存
            if (fileRefs.size()>0) {
                for (Map<String,Object> record:fileRefs) {
                    saveFileRef(record);
                }
            }
        }
    }
}

File

@Column(name = "FILE_", length = 1024)
    @FileSync(path = "/航迹回放")
    private FileRef file;

修改了思路,在Java包下,建立jmix的同名类,编译时覆盖源代码中的类

1 个赞

这个是 Jmix 推荐的扩展方式。

1 个赞