You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AEM OTB删除工作流删除JCR Node前读取其属性?

确保在AEM OTB删除工作流中JCR节点删除前审核属性的方案

我完全理解你遇到的痛点——默认的EventListener和ResourceChangeListener大多是在节点已经被持久化删除后才触发,导致你拿不到节点数据,竞态条件更是雪上加霜。下面给你两个最可靠的解决方案,直接命中你的需求:


方案1:关联现有OTB删除工作流(最可控的方式)

AEM的原生删除工作流(比如页面删除、资产删除的默认工作流)都是由一系列顺序执行的步骤组成的,我们可以直接在删除动作前插入自定义审核步骤,从根源上避免删除后才触发的问题:

  1. 定位目标OTB工作流模型
    找到你要修改的原生工作流,比如:

    • 页面删除工作流:/etc/workflow/models/delete-page
    • 资产删除工作流:/etc/workflow/models/dam-delete
  2. 添加自定义工作流步骤
    复制原工作流模型(避免直接修改原生配置),在Delete核心步骤之前添加一个自定义的工作流进程(WorkflowProcess):

    • 写一个实现com.adobe.granite.workflow.exec.WorkflowProcess的类,在execute方法中获取要删除的节点路径:
      @Component(service = WorkflowProcess.class, property = {
          "process.label=Pre-Delete Attribute Audit"
      })
      public class PreDeleteAuditProcess implements WorkflowProcess {
          @Reference
          private ResourceResolverFactory resolverFactory;
      
          @Override
          public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaDataMap) throws WorkflowException {
              // 从工作流负载中获取要删除的节点路径
              String payloadPath = workItem.getWorkflowData().getPayload().toString();
              // 使用system用户获取资源(确保权限足够)
              try (ResourceResolver resolver = resolverFactory.getServiceResourceResolver(Map.of(ResourceResolverFactory.SUBSERVICE, "audit-service"))) {
                  Resource targetResource = resolver.getResource(payloadPath);
                  if (targetResource != null) {
                      // 读取节点属性做审核逻辑
                      ValueMap properties = targetResource.getValueMap();
                      String auditAttr = properties.get("your-audit-property", String.class);
                      // 示例:如果属性不符合要求,终止工作流
                      if (!isValid(auditAttr)) {
                          workflowSession.terminateWorkflow(workItem.getWorkflow());
                          return;
                      }
                  }
              } catch (LoginException e) {
                  // 处理登录异常
              }
          }
      
          private boolean isValid(String attrValue) {
              // 你的审核逻辑
              return attrValue != null && !attrValue.isEmpty();
          }
      }
      
    • 在工作流模型编辑器中,把这个自定义步骤拖到Delete步骤之前,设置为必选执行。
  3. 设置为默认工作流
    将修改后的工作流模型设置为对应删除操作的默认工作流(比如页面删除的默认工作流),这样所有OTB删除操作都会先执行你的审核步骤。


方案2:使用JCR BEFORE_NODE_REMOVED事件(覆盖非工作流删除场景)

如果需要覆盖直接通过节点删除(比如CRXDE中删除、代码删除)的场景,JCR提供了BEFORE类型的事件,可以在节点物理删除前触发:

  1. 注册JCR BEFORE事件监听器
    不要用默认的ResourceChangeListener,而是注册一个监听Event.BEFORE_NODE_REMOVED的JCR监听器:

    @Component(service = EventListener.class)
    public class PreDeleteNodeListener implements javax.jcr.observation.EventListener {
    
        @Reference
        private SlingRepository repository;
    
        @Activate
        protected void activate() throws RepositoryException {
            Session session = repository.loginService("audit-service", null);
            try {
                ObservationManager obsManager = session.getWorkspace().getObservationManager();
                // 监听BEFORE_NODE_REMOVED事件,指定路径范围
                obsManager.addEventListener(
                    this,
                    Event.BEFORE_NODE_REMOVED,
                    "/content/your-target-path", // 你要监听的根路径
                    true, // isDeep
                    null, // uuidFilter
                    null, // nodeTypeNameFilter
                    false // noLocal
                );
            } finally {
                session.logout();
            }
        }
    
        @Override
        public void onEvent(EventIterator events) {
            while (events.hasNext()) {
                Event event = events.nextEvent();
                String nodePath = event.getPath();
                // 使用system会话获取节点(此时节点尚未删除)
                try (Session session = repository.loginService("audit-service", null)) {
                    Node targetNode = session.getNode(nodePath);
                    // 读取属性做审核
                    String auditAttr = targetNode.getProperty("your-audit-property").getString();
                    // 这里注意:BEFORE事件是在会话提交阶段触发的,不能修改当前会话,但可以记录日志、发送通知等
                    if (!isValid(auditAttr)) {
                        // 可以抛出异常中断删除操作(注意:需要确保异常能传递到会话提交环节)
                        throw new RepositoryException("Attribute audit failed for node: " + nodePath);
                    }
                } catch (RepositoryException e) {
                    // 处理异常
                }
            }
        }
    
        private boolean isValid(String attrValue) {
            // 你的审核逻辑
            return attrValue != null && !attrValue.isEmpty();
        }
    }
    
  2. 关键注意事项

    • BEFORE_NODE_REMOVED事件是同步触发的,在会话提交过程中、节点删除前执行,完全不会有竞态条件。
    • 监听器的运行用户必须有足够的权限读取目标节点的属性,建议使用service用户。

为什么之前的方案有竞态条件?

你之前用的EventListener或ResourceChangeListener默认监听的是AFTER类型的事件(比如NODE_REMOVED或Resource/REMOVE),这些事件是在节点删除后异步触发的,所以会出现有时能拿到节点、有时拿不到的竞态情况。而上面的两种方案都是在删除动作执行前触发,从根本上解决了这个问题。

内容的提问来源于stack exchange,提问作者Dee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:32:32