在多个域中使用 Dispatcher using-dispatcher-with-multiple-domains

NOTE
Dispatcher 版本独立于 AEM。您可能是在单击 AEM 或 CQ 文档中嵌入的 Dispatcher 文档链接后重定向到此页面。

使用 Dispatcher 可处理多个 Web 域中的页面请求,并支持以下条件:

  • 两个域的 Web 内容都存储在一个 AEM 存储库中。
  • 可单独为每个域使 Dispatcher 缓存中的文件失效。

例如,一家公司针对其两个品牌发布网站:品牌 A 和品牌 B。网站页面的内容是在 AEM 中创作的,并且将存储在同一存储库工作区中:

/
| - content
   | - sitea
       | - content nodes
   | - siteb
       | - content nodes

BrandA.com 的页面存储在 /content/sitea 下方。针对 URL https://BrandA.com/en.html 的客户端请求将返回到 /content/sitea/en 节点的渲染页面。同样,BrandB.com 的页面存储在 /content/siteb 下方。

在使用 Dispatcher 缓存内容时,在客户端 HTTP 请求中的页面 URL 与缓存中对应文件的路径/存储库中对应文件的路径之间建立关联。

客户端请求

当客户端向 Web 服务器发送 HTTP 请求时,请求页面的 URL 必须解析为 Dispatcher 缓存中的内容,并最终解析为存储库中的内容。

  1. 域名系统会发现为 HTTP 请求中的域名注册的 Web 服务器的 IP 地址。
  2. HTTP 请求将发送到 Web 服务器。
  3. HTTP 请求将传递到 Dispatcher。
  4. Dispatcher 确定缓存的文件是否有效。如果有效,则将缓存的文件提供给客户端。
  5. 如果缓存的文件无效,Dispatcher 会从 AEM 发布实例请求新渲染的页面。

缓存失效

当 Dispatcher Flush 复制代理请求 Dispatcher 使缓存的文件失效时,存储库中内容的路径必须解析为缓存中的内容。

  • a - 在 AEM 作者实例上激活一个页面,并将内容复制到发布实例。
  • b - Dispatcher Flush 代理调用 Dispatcher 使复制内容的缓存无效。
  • c - Dispatcher 触碰一个或多个 .stat 文件,使缓存的文件无效。

要在多个域中使用 Dispatcher,必须配置 AEM、Dispatcher 和 Web 服务器。此页面上描述的解决方案是通用的,适用于大多数环境。由于一些 AEM 拓扑的复杂性,您的解决方案可能需要进一步的自定义配置才能解决特定问题。您可能必须调整示例以符合现有的 IT 基础架构和管理策略。

URL 映射 url-mapping

要使域 URL 和内容路径能够解析为缓存的文件,必须在此过程中转换文件路径或页面 URL。提供了以下常见策略的说明,其中将在此流程的不同时间点转换路径或 URL:

  • (推荐)AEM 发布实例使用 Sling 映射进行资源解析,以实施内部 URL 重写规则。域 URL 将转换为内容存储库路径。请参阅 AEM 重写传入 URL
  • Web 服务器使用内部 URL 重写规则将域 URL 转换为缓存路径。请参阅 Web 服务器重写传入 URL

最好是使用网页的短 URL。通常,页面 URL 反映了包含 Web 内容的存储库文件夹的结构。但是,URL 不会显示最顶层的存储库节点,例如 /content。客户端不一定了解 AEM 存储库的结构。

一般要求 general-requirements

您的环境必须实施以下配置来支持在多个域中使用 Dispatcher:

  • 每个域的内容均驻留在单独的存储库分支中(请参阅下面的示例环境)。
  • Dispatcher Flush 复制代理是在 AEM 发布实例上配置的。(请参阅使发布实例中的 Dispatcher 缓存失效。)
  • 域名系统将域名解析为 Web 服务器的 IP 地址。
  • Dispatcher 缓存反映了 AEM 内容存储库的目录结构。Web 服务器的文档根目录下的文件路径与存储库中文件的路径相同。

提供的示例的环境 environment-for-the-provided-examples

提供的示例解决方案适用于具有以下特征的环境:

  • 在 Linux® 系统上部署 AEM 创作和发布实例。

  • Apache HTTPD 是 Linux® 系统上部署的 Web 服务器。

  • AEM 内容存储库和 Web 服务器的文档根目录使用以下文件结构(Apache Web Server 的文档根目录为 /usr/lib/apache/httpd-2.4.3/htdocs)

    存储库

  | - /content
    | - sitea
  |    | - content nodes
    | - siteb
       | - content nodes

Web 服务器的文档根目录

  | - /usr
    | - lib
      | - apache
        | - httpd-2.4.3
          | - htdocs
            | - content
              | - sitea
                 | - content nodes
              | - siteb
                 | - content nodes

AEM 重写传入 URL aem-rewrites-incoming-urls

用于资源解析的 Sling 映射可让您将传入 URL 与 AEM 内容路径相关联。在 AEM 发布实例上创建映射,以使来自 Dispatcher 的渲染请求解析为存储库中的正确内容。

针对页面渲染的 Dispatcher 请求使用从 Web 服务器传递的 URL 标识页面。当 URL 包含域名时,Sling 映射会将 URL 解析为内容。下图说明了 branda.com/en.html URL 与 /content/sitea/en 节点之间的映射。

Dispatcher 缓存反映了存储库节点结构。因此,在页面激活时,产生的使缓存页面失效的请求不需要 URL 或路径转换。

在 Web 服务器上定义虚拟主机 define-virtual-hosts-on-the-web-server

在 Web 服务器上定义虚拟主机,以便向每个 Web 域分配不同的文档根目录:

  • Web 服务器必须为每个 Web 域定义一个虚拟域。
  • 对于每个域,将文档根目录配置为与存储库中包含域的 Web 内容的文件夹一致。
  • 每个虚拟域还必须包含与 Dispatcher 相关的配置,如安装 Dispatcher 页面上所述。

以下示例 httpd.conf 文件为 Apache Web Server 配置两个虚拟域:

  • 服务器名称(与域名一致)是 branda.com(第 16 行)和 brandb.com(第 30 行)。
  • 每个虚拟域的文档根目录是 Dispatcher 缓存中包含站点页面的目录。(第 17 行和第 31 行)

对于此配置,Web 服务器会在收到 https://branda.com/en/products.html 的请求时执行以下操作:

  • 将 URL 与 ServerNamebranda.com. 的虚拟主机关联。

  • 将 URL 转发给 Dispatcher。

httpd.conf httpd-conf

# load the Dispatcher module
LoadModule dispatcher_module modules/mod_dispatcher.so
# configure the Dispatcher module
<IfModule disp_apache2.c>
 DispatcherConfig conf/dispatcher.any
 DispatcherLog    logs/dispatcher.log
 DispatcherLogLevel 3
 DispatcherNoServerHeader 0
 DispatcherDeclineRoot 0
 DispatcherUseProcessedURL 0
 DispatcherPassError 0
</IfModule>

# Define virtual host for brandA.com
<VirtualHost *:80>
  ServerName branda.com
  DocumentRoot /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea
   <Directory /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea>
     <IfModule disp_apache2.c>
       SetHandler dispatcher-handler
       ModMimeUsePathInfo On
     </IfModule>
     Options FollowSymLinks
     AllowOverride None
   </Directory>
</VirtualHost>

# define virtual host for brandB.com
<VirtualHost *:80>
  ServerName brandB.com
  DocumentRoot /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb
   <Directory /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb>
     <IfModule disp_apache2.c>
       SetHandler dispatcher-handler
       ModMimeUsePathInfo On
     </IfModule>
     Options FollowSymLinks
     AllowOverride None
   </Directory>
</VirtualHost>

# document root for web server
DocumentRoot "/usr/lib/apache/httpd-2.4.3/htdocs"

虚拟主机将继承主服务器部分中配置的 DispatcherConfig 属性值。虚拟主机可以包括自己的 DispatcherConfig 属性来覆盖主服务器配置。

配置 Dispatcher 以处理多个域 configure-dispatcher-to-handle-multiple-domains

要支持包含域名及其相应的虚拟主机的 URL,请定义以下 Dispatcher 场:

  • 为每个虚拟主机配置 Dispatcher 场。这些场处理来自每个域的 Web 服务器的请求,检查缓存的文件,并从渲染器请求页面。
  • 配置用于使缓存的内容失效的 Dispatcher 场,而不管内容属于哪个域。该场处理来自 Flush Dispatcher 复制代理的文件失效请求。

为虚拟主机创建 Dispatcher 场

虚拟主机的场必须具有以下配置,以使客户端 HTTP 请求中的 URL 解析为 Dispatcher 缓存中的正确文件:

  • /virtualhosts 属性设置为域名。利用此属性,Dispatcher 能够将场与域相关联。

  • 利用 /filter 属性可访问域名部分后截断的请求 URL 的路径。例如,对于 https://branda.com/en.html URL,路径将解释为 /en.html,因此过滤器必须允许对此路径的访问。

  • /docroot 属性设置为根目录的路径。即 Dispatcher 缓存中域网站内容的根目录。此路径用作原始请求中的连接的 URL 的前缀。例如,docroot 为 /usr/lib/apache/httpd-2.4.3/htdocs/sitea 会导致针对 https://branda.com/en.html 的请求解析为 /usr/lib/apache/httpd-2.4.3/htdocs/sitea/en.html 文件。

此外,必须将 AEM 发布实例指定为虚拟主机的渲染器。根据需要配置其他场属性。以下代码是 branda.com 域的缩写场配置:

/farm_sitea  {
    ...
    /virtualhosts { "branda.com" }
    /renders {
      /rend01  { /hostname "127.0.0.1"  /port "4503" }
    }
    /filter {
      /0001 { /type "deny"  /glob "*" }
      /0023 { /type "allow" /glob "*/en*" }
      ...
     }
    /cache {
      /docroot "/usr/lib/apache/httpd-2.4.3/htdocs/content/sitea"
      ...
   }
   ...
}

创建用于缓存失效的 Dispatcher 场

需要 Dispatcher 场来处理使缓存文件失效的请求。该场必须能够访问每个虚拟主机的 docroot 目录中的 .stat 文件。

利用以下属性配置,Dispatcher 能够从缓存中的文件解析 AEM 内容存储库中的文件:

  • /docroot 属性设置为 Web 服务器的默认 docroot。通常,/docroot 是在其中创建 /content 文件夹的目录。Linux® 上的 Apache 示例值为 /usr/lib/apache/httpd-2.4.3/htdocs
  • /filter 属性允许对 /content 目录下的文件的访问。

/statfileslevel 属性必须足够高,才会在每个虚拟主机的根目录中创建 .stat 文件。利用此属性,可单独使每个域的缓存失效。对于示例设置,/statfileslevel 值为 2 将在 *docroot*/content/sitea 目录和 *docroot*/content/siteb 目录中创建 .stat 文件。

此外,必须将 发布实例指定为虚拟主机的渲染器。根据需要配置其他场属性。以下代码是用于使缓存失效的场的缩写配置:

/farm_flush {
    ...
    /virtualhosts   { "invalidation_only" }
    /renders  {
      /rend01  { /hostname "127.0.0.1" /port "4503" }
    }
    /filter   {
      /0001 { /type "deny"  /glob "*" }
      /0023 { /type "allow" /glob "*/content*" }
      ...
      }
    /cache  {
       /docroot "/usr/lib/apache/httpd-2.4.3/htdocs"
       /statfileslevel "2"
       ...
   }
   ...
}

在启动 Web 服务器时,Dispatcher 日志(在调试模式下)指示所有场的初始化:

Dispatcher initializing (build 4.1.2)
[Fri Nov 02 16:27:18 2012] [D] [24974(140006182991616)] farms[farm_sitea].cache.docroot = /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea
[Fri Nov 02 16:27:18 2012] [D] [24974(140006182991616)] farms[farm_siteb].cache.docroot = /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb
[Fri Nov 02 16:27:18 2012] [D] [24974(140006182991616)] farms[farm_flush].cache.docroot = /usr/lib/apache/httpd-2.4.3/htdocs
[Fri Nov 02 16:27:18 2012] [I] [24974(140006182991616)] Dispatcher initialized (build 4.1.2)

为资源解析配置 Sling 映射 configure-sling-mapping-for-resource-resolution

使用 Sling 映射进行资源解析,使基于域的 URL 解析为 AEM 发布实例上的内容。资源映射将来自 Dispatcher(最初来自客户端 HTTP 请求)的传入 URL 转换为内容节点。

要了解 Sling 资源映射,请参阅 Sling 文档中的用于资源解析的映射

通常,以下资源需要映射,但也可能需要其他的映射:

  • 内容页面的根节点(/content 的下方)
  • 页面使用的设计节点(/etc/designs 的下方)
  • /libs 文件夹

创建内容页面的映射后,要发现更多所需的映射,请使用 Web 浏览器打开 Web 服务器上的页面。在发布实例的 error.log 文件中,找到有关未找到的资源的消息。以下示例消息指示需要 /etc/clientlibs 的映射:

01.11.2012 15:59:24.601 *INFO* [10.36.34.243 [1351799964599] GET /etc/clientlibs/foundation/jquery.js HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Resource /content/sitea/etc/clientlibs/foundation/jquery.js not found
NOTE
默认 Apache Sling 重写器的 Linkchecker 转换器会自动修改页面中的超链接以防止链接失效。但是,仅当链接目标是 HTML 或 HTM 文件时才执行链接重写。要更新指向其他文件类型的链接,请创建转换器组件并将它添加到 HTML 重写器管道中。

示例资源映射节点

下表列出了实施 branda.com 域的资源映射的节点。为 brandb.com 域创建类似的节点,例如 /etc/map/http/brandb.com。在所有情况下,只要无法在 Sling 的上下文中正确解析 HTML 页面中的引用,就需要映射。

节点路径
类型
属性
/etc/map/http/branda.com
sling:Mapping
Name: sling:internalRedirect Type: String Value: /content/sitea
/etc/map/http/branda.com/libs
sling:Mapping
Name: sling:internalRedirect <br/>Type: String <br/>Value: /libs
/etc/map/http/branda.com/etc
sling:Mapping
/etc/map/http/branda.com/etc/designs
sling:Mapping
Name: sling:internalRedirect <br/>VType: String <br/>VValue: /etc/designs
/etc/map/http/branda.com/etc/clientlibs
sling:Mapping
Name: sling:internalRedirect <br/>VType: String <br/>VValue: /etc/clientlibs

配置 Dispatcher Flush 复制代理 configuring-the-dispatcher-flush-replication-agent

AEM 发布实例上的 Dispatcher Flush 复制代理必须将失效请求发送到正确的 Dispatcher 场。要将场作为目标,请使用 Dispatcher Flush 复制代理的 URI 属性(在“传输”选项卡上)。包含为使缓存失效而配置的 Dispatcher 场的 /virtualhost 属性值:

https://*webserver_name*:*port*/*virtual_host*/dispatcher/invalidate.cache

例如,要使用上一示例的 farm_flush 场,URI 应为 https://localhost:80/invalidation_only/dispatcher/invalidate.cache

Web 服务器重写传入 URL the-web-server-rewrites-incoming-urls

使用 Web 服务器的内部 URL 重写功能将基于域的 URL 转换为 Dispatcher 缓存中的文件路径。例如,https://brandA.com/en.html 页面的客户端请求将转换为 Web 服务器的文档根目录中的 content/sitea/en.html 文件。

Dispatcher 缓存反映了存储库节点结构。因此,在页面激活时,产生的使缓存页面失效的请求不需要 URL 或路径转换。

在 Web 服务器上定义虚拟主机并重写规则 define-virtual-hosts-and-rewrite-rules-on-the-web-server

在 Web 服务器上进行如下配置:

  • 为每个 Web 域定义一个虚拟主机。
  • 对于每个域,将文档根目录配置为与存储库中包含域的 Web 内容的文件夹一致。
  • 对于每个虚拟域,创建一个 URL 重命名规则来将传入 URL 转换为缓存文件的路径。
  • 每个虚拟域还必须包含与 Dispatcher 相关的配置,如安装 Dispatcher 页面上所述。
  • 必须将 Dispatcher 模块配置为使用 Web 服务器已重写的 URL。(请参阅 安装 Dispatcher 中的 DispatcherUseProcessedURL 属性。)

以下示例 httpd.conf 文件为 Apache Web Server 配置两个虚拟主机:

  • 服务器名称(与域名一致)是 brandA.com(第 16 行)和 brandB.com(第 32 行)。

  • 每个虚拟域的文档根目录是 Dispatcher 缓存中包含站点页面的目录。(第 20 行和第 33 行)

  • 每个虚拟域的 URL 重写规则都是正则表达式。正则表达式为请求的页面的路径添加前缀。其前缀是缓存中页面的路径。(第 19 行和第 35 行)

  • DispatcherUseProcessedURL 属性设置为 1。(第 10 行)

例如,Web 服务器会在收到带 https://brandA.com/en/products.html URL 的请求时执行以下操作:

  • 将 URL 与 ServerNamebrandA.com. 的虚拟主机关联。
  • 将 URL 重写为 /content/sitea/en/products.html.
  • 将 URL 转发给 Dispatcher。

httpd.conf httpd-conf-1

# load the Dispatcher module
LoadModule dispatcher_module modules/mod_dispatcher.so
# configure the Dispatcher module
<IfModule disp_apache2.c>
 DispatcherConfig conf/dispatcher.any
 DispatcherLog    logs/dispatcher.log
 DispatcherLogLevel 3
 DispatcherNoServerHeader 0
 DispatcherDeclineRoot 0
 DispatcherUseProcessedURL 1
 DispatcherPassError 0
</IfModule>

# Define virtual host for brandA.com
<VirtualHost *:80>
  ServerName branda.com
  DocumentRoot /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea
  RewriteEngine  on
  RewriteRule    ^/(.*)\.html$  /content/sitea/$1.html [PT]
   <Directory /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea>
     <IfModule disp_apache2.c>
       SetHandler dispatcher-handler
       ModMimeUsePathInfo On
     </IfModule>
     Options FollowSymLinks
     AllowOverride None
   </Directory>
</VirtualHost>

# define virtual host for brandB.com
<VirtualHost *:80>
  ServerName brandB.com
  DocumentRoot /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb
  RewriteEngine  on
  RewriteRule    ^/(.*)\.html$  /content/siteb/$1.html [PT]
   <Directory /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb>
     <IfModule disp_apache2.c>
       SetHandler dispatcher-handler
       ModMimeUsePathInfo On
     </IfModule>
     Options FollowSymLinks
     AllowOverride None
   </Directory>
</VirtualHost>

# document root for web server
DocumentRoot "/usr/lib/apache/httpd-2.4.3/htdocs"

配置 Dispatcher 场 configure-a-dispatcher-farm

在 Web 服务器重写 URL 时,Dispatcher 需要根据配置 Dispatcher 定义的单个场。需要以下配置才能支持 Web 服务器虚拟主机和 URL 重命名规则:

  • /virtualhosts 属性必须包含所有 VirtualHost 定义的 ServerName 值。
  • /statfileslevel 属性必须足够高,才会在包含每个域的内容文件的目录中创建 .stat 文件。

以下示例配置文件基于随 Dispatcher 一起安装的示例 dispatcher.any 文件。需要进行以下更改才能支持上一个 httpd.conf 文件的 Web 服务器配置:

  • /virtualhosts 属性促使 Dispatcher 处理 brandA.combrandB.com 域的请求。(第 12 行)
  • /statfileslevel 属性设置为 2,以便在每个包含域的 Web 内容的目录中创建 stat 文件(第 41 行):/statfileslevel "2"

像往常一样,缓存的文档根目录与 Web 服务器的文档根目录相同(第 40 行):/usr/lib/apache/httpd-2.4.3/htdocs

dispatcher.any dispatcher-any

/name "testDispatcher"
/farms
  {
  /dispfarm0
    {
    /clientheaders
      {
      "*"
      }
    /virtualhosts
      {
      "brandA.com" "brandB.com"
      }
    /renders
      {
      /rend01    {  /hostname "127.0.0.1"   /port "4503"  }
      }
    /filter
      {
      /0001 { /type "deny"  /glob "*" }
      /0023 { /type "allow" /glob "*/content*" }  # disable this rule to allow mapped content only
      /0041 { /type "allow" /glob "* *.css *"   }  # enable css
      /0042 { /type "allow" /glob "* *.gif *"   }  # enable gifs
      /0043 { /type "allow" /glob "* *.ico *"   }  # enable icos
      /0044 { /type "allow" /glob "* *.js *"    }  # enable javascript
      /0045 { /type "allow" /glob "* *.png *"   }  # enable png
      /0046 { /type "allow" /glob "* *.swf *"   }  # enable flash
      /0061 { /type "allow" /glob "POST /content/[.]*.form.html" }  # allow POSTs to form selectors under content
      /0062 { /type "allow" /glob "* /libs/cq/personalization/*"  }  # enable personalization
      /0081 { /type "deny"  /glob "GET *.infinity.json*" }
      /0082 { /type "deny"  /glob "GET *.tidy.json*"     }
      /0083 { /type "deny"  /glob "GET *.sysview.xml*"   }
      /0084 { /type "deny"  /glob "GET *.docview.json*"  }
      /0085 { /type "deny"  /glob "GET *.docview.xml*"  }
      /0086 { /type "deny"  /glob "GET *.*[0-9].json*" }
      /0090 { /type "deny"  /glob "* *.query.json*" }
      }
    /cache
      {
      /docroot "/usr/lib/apache/httpd-2.4.3/htdocs"
      /statfileslevel "2"
      /allowAuthorized "0"
      /rules
        {
        /0000  { /glob "*"     /type "allow"  }
        }
      /invalidate
        {
        /0000  {   /glob "*" /type "deny"  }
        /0001 {  /glob "*.html" /type "allow"  }
        }
      /allowedClients
        {
        }
      }
    /statistics
      {
      /categories
        {
        /html  { /glob "*.html" }
        /others  {  /glob "*"  }
        }
      }
    }
  }
NOTE
由于定义了单个 Dispatcher 场,因此 AEM 发布实例上的 Dispatcher Flush 复制代理不需要特殊配置。

要重写对具有 .html 或 .htm 以外的扩展名的文件的引用,请创建 Sling 重写器转换器组件并将它添加到默认重写器管道中。

当资源路径无法在 Web 服务器上下文中正确解析时重写引用。例如,当图像生成组件创建链接(例如 /content/sitea/en/products.navimage.png)时,需要使用转换器。如何创建功能完善的 Internet 网站topnav 组件将创建此类链接。

Sling 重写器是一个后处理 Sling 输出的模块。重写器的 SAX 管道实现由一个生成器、一个或多个转换器和一个序列化器组成:

  • 生成器: ​解析 Sling 输出流(HTML 文档)并在遇到特定元素类型时生成 SAX 事件。
  • 转换器: ​侦听 SAX 事件,从而修改事件目标(一个 HTML 元素)。重写器管道包含零个或多个转换器。转换器按顺序执行,并将 SAX 事件传递到序列中的下一个转换器。
  • 序列化器: ​序列化输出,并包含每个转换器中的修改。

AEM 默认重写器管道 the-aem-default-rewriter-pipeline

AEM 使用默认管道重写器来处理 text/html 类型的文档:

  • 生成器解析 HTML 文档并在遇到 a、img、area、form、base、link、script 和 body 元素时生成 SAX 事件。生成器的别名为 htmlparser
  • 管道包含以下转换器:linkcheckermobilemobiledebugcontentsynclinkchecker 转换器将引用的 HTML 或 HTM 文件的路径外部化,以防止链接失效。
  • 序列化器写入 HTML 输出。序列化器别名为 htmlwriter。

/libs/cq/config/rewriter/default 节点定义管道。

创建转换器 creating-a-transformer

执行以下任务可创建转换器组件并将它用于管道:

  1. 实施 org.apache.sling.rewriter.TransformerFactory 接口。此类创建转换器类的实例。指定 transformer.type 属性的值(转换器别名),并将类配置为 OSGi 服务组件。
  2. 实施 org.apache.sling.rewriter.Transformer 接口。要最大限度地减少工作量,可以扩展 org.apache.cocoon.xml.sax.AbstractSAXPipe 类。重写 startElement 方法可自定义重写行为。为传递给转换器的每个 SAX 事件调用此方法。
  3. 捆绑和部署这些类。
  4. 将配置节点添加到 AEM 应用程序可将转换器添加到管道。
TIP
您可以改为将 TransformerFactory 配置为将转换器插入定义的每个重写器中。因此,无需配置管道:
  • pipeline.mode 属性设置为 global
  • service.ranking 属性设置为正整数。
  • 请勿包含 pipeline.type 属性。
NOTE
使用多模块原型的 Content Package Maven Plugin 可创建您的 Maven 项目。POM 自动创建并安装内容包。

以下示例实施了重写对图像文件的引用的转换器。

  • MyRewriterTransformerFactory 类实例化 MyRewriterTransformer 对象。管道类型属性将转换器别名设置为 mytransformer。要在管道中包含别名,管道配置节点应将此别名包含在转换器列表中。
  • MyRewriterTransformer 类覆盖 AbstractSAXTransformer 类的 startElement 方法。startElement 方法重写 img 元素的 src 属性的值。

这些例子不够有力。请勿在生产环境中使用它们。

示例 TransformerFactory 实施 example-transformerfactory-implementation

package com.adobe.example;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Property;

import org.apache.sling.rewriter.Transformer;
import org.apache.sling.rewriter.TransformerFactory;

@Component
@Service
public class MyRewriterTransformerFactory implements TransformerFactory {
    /* Define the alias */
    @Property(value="mytransformer")
    static final String PIPELINE_TYPE ="pipeline.type";

    public Transformer createTransformer() {

        return new MyRewriterTransformer ();
    }
}

示例转换器实施 example-transformer-implementation

package com.adobe.example;

import java.io.IOException;

import org.apache.cocoon.xml.sax.AbstractSAXPipe;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.rewriter.ProcessingComponentConfiguration;
import org.apache.sling.rewriter.ProcessingContext;
import org.apache.sling.rewriter.Transformer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import javax.servlet.http.HttpServletRequest;

public class MyRewriterTransformer extends AbstractSAXPipe implements Transformer {

 private static final Logger log = LoggerFactory.getLogger(MyRewriterTransformer.class);
 private SlingHttpServletRequest httpRequest;
 /* The element and attribute to act on  */
 private static final String ATT_NAME = new String("src");
 private static final String EL_NAME = new String("img");

 public MyRewriterTransformer () {
 }
 public void dispose() {
 }
 public void init(ProcessingContext context, ProcessingComponentConfiguration config) throws IOException {
  this.httpRequest = context.getRequest();
  log.debug("Transforming request {}.", httpRequest.getRequestURI());
 }
 @Override
 public void startElement (String nsUri, String localname, String qname, Attributes atts) throws SAXException {
  /* copy the element attributes */
  AttributesImpl linkAtts = new AttributesImpl(atts);
  /* Only interested in EL_NAME elements */
  if(EL_NAME.equalsIgnoreCase(localname)){

   /* iterate through the attributes of the element and act only on ATT_NAME attributes */
   for (int i=0; i < linkAtts.getLength(); i++) {
    if (ATT_NAME.equalsIgnoreCase(linkAtts.getLocalName(i))) {
     String path_in_link = linkAtts.getValue(i);

     /* use the resource resolver of the http request to reverse-resolve the path  */
     String mappedPath = httpRequest.getResourceResolver().map(httpRequest, path_in_link);

     log.info("Tranformed {} to {}.", path_in_link,mappedPath);

     /* update the attribute value */
     linkAtts.setValue(i,mappedPath);
    }
   }

  }
        /* return updated attributes to super and continue with the transformer chain */
 super.startElement(nsUri, localname, qname, linkAtts);
 }
}

将转换器添加到重写器管道 adding-the-transformer-to-a-rewriter-pipeline

创建一个 JCR 节点,该节点定义使用您的转换器的管道。以下节点定义创建一个处理 text/html 文件的管道。使用 HTML 的默认 AEM 生成器和解析器。

NOTE
如果您将 Transformer 属性 pipeline.mode 设置为 global,则无需配置管道。global 模式将转换器插入所有管道中。

重写器配置节点 - XML 表示形式 rewriter-configuration-node-xml-representation

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="https://www.jcp.org/jcr/1.0" xmlns:nt="https://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured"
    contentTypes="[text/html]"
    enabled="{Boolean}true"
    generatorType="htmlparser"
    order="5"
    serializerType="htmlwriter"
    transformerTypes="[mytransformer]">
</jcr:root>

下图显示了节点的 CRXDE Lite 表示形式:

recommendation-more-help
ce382601-480f-4a99-8be7-73178d4b6ef5