Java™ API最佳作法

Adobe Experience Manager (AEM)是以豐富的開放原始碼軟體棧疊為基礎,在開發期間公開許多Java™ API以供使用。 本文會探索主要的API,以及何時應該使用這些API以及其使用原因。

AEM建置在四個主要的Java™ API集上。

  • Adobe Experience Manager (AEM)

    • 產品抽象概念,例如頁面、資產、工作流程等。
  • Apache Sling Web框架

    • REST和以資源為基礎的抽象,例如資源、值對應和HTTP要求。
  • JCR (Apache Jackrabbit Oak)

    • 資料和內容抽象概念,例如,節點、屬性和工作階段。
  • OSGi (Apache Felix)

    • OSGi應用程式容器抽象概念,例如服務和(OSGi)元件。

Java™ API偏好設定「經驗法則」

一般規則是依下列順序偏好API/抽象化:

  1. AEM
  2. Sling
  3. JCR
  4. osgi

如果API是由AEM提供,則偏好使用 Sling、 JCR和OSGi。 如果AEM不提供API,則偏好使用 Sling 超過JCR和OSGi。

此順序為一般規則,表示存在例外。 可以接受中斷此規則的原因是:

  • 眾所周知的例外,如下所述。

  • 較高層級的API中沒有必要功能。

  • 在現有程式碼(自訂或AEM產品程式碼)的上下文中操作,而現有程式碼本身使用較不偏好的API,且移至新API的成本不合理。

    • 一致使用低階API比建立混合更好。

AEM API

AEM API提供產品化使用案例專用的抽象概念與功能。

例如,AEM PageManager頁面 API提供以下專案的抽象概念: cq:Page AEM中代表網頁的節點。

雖然這些節點可以透過 Sling API作為資源,JCR API作為節點,AEM API提供常見使用案例的抽象概念。 使用AEM API可確保AEM產品與AEM的自訂和擴充功能之間的一致行為。

com.adobe.* vs com.day.* API

AEM API具有套件內偏好設定,依偏好設定的順序由下列Java™套件識別:

  1. com.adobe.cq
  2. com.adobe.granite
  3. com.day.cq

com.adobe.cq package支援產品使用案例,但 com.adobe.granite 支援跨產品平台使用案例,例如工作流程或工作(用於跨產品:AEM Assets、網站等)。

com.day.cq 套件包含「原始」API。 這些API處理在Adobe收購之前和/或之後存在的核心抽象概念與功能 Day CQ. 這些API受到支援,應避免使用,除非 com.adobe.cqcom.adobe.granite 套件不提供(較新的)替代方案。

新的抽象概念,例如 Content Fragments 和 Experience Fragments 內建於 com.adobe.cq 空格而非 com.day.cq 如下所述。

查詢API

AEM支援多種查詢語言。 三種主要語言為 JCR-SQL2、 XPath和 AEM查詢產生器.

最重要的考量是在程式碼庫中維持一致的查詢語言,以降低複雜度和理解成本。

所有查詢語言實際上都有相同的效能設定檔,如 Apache Oak 會將其轉儲至JCR-SQL2以供最終查詢執行,而且與JCR-SQL2的查詢時間本身相比,其轉換時間可忽略不計。

偏好使用的API為 AEM查詢產生器,這是最高級別的抽象,提供強大的API來建構、執行和擷取查詢的結果,並提供下列內容:

CAUTION
AEM QueryBuilder API洩漏ResourceResolver物件。 若要減少這種洩露,請遵循以下步驟 程式碼範例.

Sling API

Apache Sling 是支援AEM的RESTful Web架構。 Sling 提供HTTP請求路由、將JCR節點建模為資源、提供安全性上下文等。

Sling API擁有為擴充功能建置的額外優點,這表示通常更容易、更安全增強使用建置的應用程式行為 Sling API比可擴充性較低的JCR API還多。

的常見用法 Sling API

JCR API

JCR (Java™ Content Repository) 2.0 API 是JCR實施規格的一部分(在AEM的情況下, Apache Jackrabbit Oak)。 所有JCR實作都必須符合併實作這些API,因此,是與AEM內容互動的最低層級API。

JCR本身是階層式/樹狀結構的NoSQL資料存放區,AEM會將其當作內容存放庫。 JCR具有大量受支援的API,範圍從內容CRUD到查詢內容。 雖然有如此強大的API,但很少會偏好使用較高層級的AEM和 Sling 抽象化。

與Apache Jackrabbit Oak API相比,總是偏好使用JCR API。 JCR API用於 互動 JCR存放庫,而Oak API則用於 實施 jcr存放庫。

JCR API的常見誤解

雖然JCR是AEM內容存放庫,但其API並非與內容互動的推薦方法。 相反地,他們偏好AEM API (Page、Assets、Tag等)或Sling Resource API,因為這些提供更好的抽象化。

CAUTION
在AEM應用程式中,廣泛使用JCR API的工作階段和節點介面會導致程式碼異味。 確定 Sling 應該改用API。

JCR API的常見用法

OSGi API

OSGi API與較高層級API (AEM, Sling和JCR),很少需要使用OSGi API,且需要高水準的AEM開發專業知識。

OSGi與Apache Felix API

OSGi會定義所有OSGi容器都必須實作並遵循的規格。 AEM OSGi實作Apache Felix也提供自己的數個API。

  • 偏好使用OSGi API (org.osgi)透過Apache Felix API (org.apache.felix)。

OSGi API的常見用法

規則的例外

以下是上述定義規則的常見例外。

OSGi API

處理低階OSGi抽象化時(例如在OSGi元件屬性中定義或讀取),以下專案提供的較新抽象化 org.osgi 優先於較高層級的Sling抽象概念。 競爭的Sling抽象概念尚未標籤為 @Deprecated 並提出建議 org.osgi 替代方案。

另請注意OSGi設定節點定義偏好設定 cfg.json 超過 sling:OsgiConfig 格式。

AEM資產API

  • 偏好 com.day.cq.dam.api 超過 com.adobe.granite.asset.api.

    • com.day.cq Assets API為AEM資產管理使用案例提供更免費的工具。
    • Granite Assets API支援低階資產管理使用案例(版本、關係)。

查詢API

  • AEM QueryBuilder不支援某些查詢函式,例如 建議、拼字檢查,以及索引提示等不常見函式。 若要使用這些函式進行查詢,建議使用JCR-SQL2。

Sling Servlet註冊 sling-servlet-registration

Sling 篩選器註冊 sling-filter-registration

有用的程式碼片段

以下是有用的Java™程式碼片段,說明使用已討論API的常見使用案例的最佳實務。 這些片段也說明如何從較不偏好的API移至較偏好的API。

JCR工作階段至 Sling ResourceResolver

自動關閉Sling ResourceResolver

自AEM 6.2起, Sling ResourceResolver AutoClosable試用資源 陳述式。 使用此語法,明確呼叫 resourceResolver .close() 不需要。

@Reference
ResourceResolverFactory rrf;
...
Map<String, Object> authInfo = new HashMap<String, Object>();
authInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, jcrSession);

try (ResourceResolver resourceResolver = rrf.getResourceResolver(authInfo)) {
    // Do work with the resourceResolver
} catch (LoginException e) { .. }

手動關閉Sling ResourceResolver

ResourceResolvers必須手動關閉 finally 如果無法使用上述自動關閉技術,則設為區塊。

@Reference
ResourceResolverFactory rrf;
...
Map<String, Object> authInfo = new HashMap<String, Object>();
authInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, jcrSession);

ResourceResolver resourceResolver = null;

try {
    resourceResolver = rrf.getResourceResolver(authInfo);
    // Do work with the resourceResolver
} catch (LoginException e) {
   ...
} finally {
    if (resourceResolver != null) { resourceResolver.close(); }
}

JCR路徑至 Sling Resource

Resource resource = ResourceResolver.getResource("/path/to/the/resource");

JCR節點至 Sling Resource

Resource resource = resourceResolver.getResource(node.getPath());

Sling Resource 至AEM資產

建議做法

DamUtil.resolveToAsset(..) 函式解析 dam:Asset 至資產物件,方法為視需要向上瀏覽樹狀結構。

Asset asset = DamUtil.resolveToAsset(resource);

替代方法

將資源調整為適合資產需要資源本身 dam:Asset 節點。

Asset asset = resource.adaptTo(Asset.class);

Sling AEM資源頁面

建議做法

pageManager.getContainingPage(..) 解析下的任何資源 cq:Page 視需要向上瀏覽樹狀結構來移至Page物件。

PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
Page page = pageManager.getContainingPage(resource);
Page page2 = pageManager.getContainingPage("/content/path/to/page/jcr:content/or/component");

替代方法 alternative-approach-1

將資源調整成頁面需要資源本身成為 cq:Page 節點。

Page page = resource.adaptTo(Page.class);

讀取AEM頁面屬性

使用Page物件的getter來取得已知屬性(getTitle()getDescription()、等等)和 page.getProperties() 若要取得 [cq:Page]/jcr:content 用於擷取其他屬性的ValueMap。

Page page = resource.adaptTo(Page.class);
String title = page.getTitle();
Calendar value = page.getProperties().get("cq:lastModified", Calendar.getInstance());

讀取AEM資產中繼資料屬性

Asset API提供便利的方法,讓您從 [dam:Asset]/jcr:content/metadata 節點。 這不是ValueMap,不支援第二個引數(預設值和自動型別轉換)。

Asset asset = resource.adaptTo(Asset.class);
String title = asset.getMetadataValue("dc:title");
Calendar lastModified = (Calendar) asset.getMetadata("cq:lastModified");

讀取 Sling Resource 屬性 read-sling-resource-properties

當屬性儲存在AEM API (頁面、資產)無法直接存取的位置(屬性或相對資源)時, Sling 資源和ValueMap可用來取得資料。

ValueMap properties = resource.getValueMap();
String value = properties.get("jcr:title", "Default title");
String relativeResourceValue = properties.get("relative/propertyName", "Default value");

在此情況下,可能必須將AEM物件轉換為 Sling Resource 以有效找到所需的屬性或子資源。

AEM頁面目標 Sling Resource

Resource resource = page.adaptTo(Resource.class);

AEM資產目標 Sling Resource

Resource resource = asset.adaptTo(Resource.class);

寫入屬性,使用 Sling的ModifiableValueMap

使用 Sling的 ModifiableValueMap 將屬性寫入節點。 這只能寫入至立即節點(不支援相對屬性路徑)。

記下對的呼叫 .adaptTo(ModifiableValueMap.class) 需要資源的寫入許可權,否則會傳回null。

ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class);

properties.put("newPropertyName", "new value");
properties.put("propertyNameToUpdate", "updated value");
properties.remove("propertyToRemove");

resource.getResourceResolver().commit();

建立AEM頁面

您必須一律使用PageManager建立頁面,就像使用「頁面範本」一樣,才能在AEM中正確定義和初始化「頁面」。

String templatePath = "/conf/my-app/settings/wcm/templates/content-page";
boolean autoSave = true;

PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
pageManager.create("/content/parent/path", "my-new-page", templatePath, "My New Page Title", autoSave);

if (!autoSave) { resourceResolver.commit(); }

建立 Sling 資源

ResourceResolver支援建立資源的基本作業。 建立較高層級的抽象概念(AEM Pages、Assets、Tags等等)時,請使用其各自管理員提供的方法。

resourceResolver.create(parentResource, "my-node-name", new ImmutableMap.Builder<String, Object>()
           .put("jcr:primaryType", "nt:unstructured")
           .put("jcr:title", "Hello world")
           .put("propertyName", "Other initial properties")
           .build());

resourceResolver.commit();

刪除 Sling 資源

ResourceResolver支援移除資源。 建立較高層級的抽象概念(AEM Pages、Assets、Tags等等)時,請使用其各自管理員提供的方法。

resourceResolver.delete(resource);

resourceResolver.commit();
recommendation-more-help
c92bdb17-1e49-4e76-bcdd-89e4f85f45e6