使用無頭 (headless) Oracle Content Management 建置 Flutter 最小型網站
簡介
Flutter 是 Google 提供的開放原始碼架構,可讓您從單一程式碼編寫建置美觀、原生編譯、多平台應用系統。Flutter 程式碼可以編譯至 ARM 或 Intel 機器碼以及 JavaScript,讓任何裝置都能得到更快速的效能。Flutter 可以是建立使用 Oracle Content Management 內容之應用系統的強大工具。隨著正確的內容模型,您可以快速建置組成一般部落格的 Flutter UI。
本教學課程將運用 Oracle Content Management 作為無頭 (headless) CMS,在 Flutter 中建置簡單的最小網站。此 Flutter 範例位於 GitHub。
教學課程包含三個步驟:
必要條件
繼續本教學課程之前,建議您先閱讀下列資訊:
若要遵循本教學課程,您需要:
- Oracle Content Management 訂閱
- 具有「內容管理員」角色的 Oracle Content Management 帳戶
- Windows 或 Mac 電腦 (節點版本 10 或更新版本)
我們正在打造什麼
只要使用 Flutter,您就可以輕鬆地從 Oracle Content Management 儲存區域擷取影像和其他內容。
若要瞭解我們正在打造的東西,以下是教學課程的終點狀態,亦即使用 Oracle Content Management 內容的基本 Flutter 最小網站。
這是首頁畫面在本教學課程結束時顯示的內容:

這是聯絡我們畫面的外觀:

若要繼續,您必須具有 Oracle Content Management 的有效訂閱,並且以「內容管理員」角色登入。
作業 1:準備 Oracle Content Management
如果您還沒有 Oracle Content Management 執行處理,請參閱快速入門,瞭解如何註冊 Oracle Cloud、佈建 Oracle Content Management 執行處理,以及將 Oracle Content Management 設為無頭 (headless) CMS。
在本教學課程中,您將需要建立內容模型。有可下載的資產套件可供您填入含內容類型與相關內容的空白儲存庫。
準備 Oracle Content Management:
建立通道和資產儲存區域
您必須先在 Oracle Content Management 中建立通道和資產儲存區域,才能發布內容。
在 Oracle Content Management 中建立通道與資產儲存區域:
以管理員身分登入 Oracle Content Management Web 介面。
在左側導覽功能表中選擇內容,然後從頁面標頭的選取清單中選擇發布通道。

在右上角,按一下建立以建立新管道。為此教學課程的目的命名通道 'OCEMinimalChannel「,並讓存取權保持公開。按一下儲存以建立管道。

在左側導覽功能表中選擇內容,然後從頁面標頭的選取清單中選擇儲存庫。

在右上角,按一下建立以建立新的資產儲存庫。為此教學課程命名資產儲存庫 'OCEMinimalRepository'。

在發佈通道欄位中,選取 OCEMinimalChannel 通道來向 Oracle Content Management 指示 OCEMinimalRepository 儲存區域中的內容可以發布到 OCEMinimalChannel 通道。完成時,按一下儲存。

匯入 Oracle Content Management Samples Asset Pack
您可以下載預先設定的 Oracle Content Management 範例資產套件,其中包含此教學課程的所有必要內容類型和資產。
您可以從 Oracle Content Management Samples Asset Pack 上傳本教學課程中所使用的內容複本。這可讓您實驗內容類型並修改內容。若要匯入 Oracle Content Management Samples Asset Pack,您可以下載資產套件封存 OCESamplesAssetPack.zip,並將其擷取至您選擇的目錄:
從 Oracle Content Management 下載頁面下載 Oracle Content Management Samples Asset Pack (OCESamplesAssetPack.zip)。將下載的壓縮檔解壓縮到電腦上的位置。擷取之後,此位置將會包含名為 OCEMinimal_data.zip 的檔案。
以管理員身分登入 Oracle Content Management Web 介面。
在左側導覽功能表中選擇內容,然後從頁面標頭的選取清單中選擇儲存庫。現在選取 OCEMinimalRepository,然後按一下頂端動作列中的匯入內容按鈕。

將本機電腦的 OCEMinimal_data.zip 上傳至文件資料夾。

上傳之後,請選取 OCEMinimal_data.zip,然後按一下確定將內容匯入您的資產儲存庫。

成功匯入內容之後,請瀏覽至資產頁面並開啟 OCEMinimalRepository 儲存庫。您將會看到所有相關影像與內容項目現在已新增至資產儲存庫。

按一下左上方的全選,然後按一下發布,將所有匯入的資產新增至您先前建立的發布管道 OCEMinimalChannel。

發布之前,您需要驗證所有資產。請先將 OCEMinimalChannel 新增為選取的通道,然後按一下驗證按鈕。

驗證資產後,您可以按一下右上角的發布按鈕,將所有資產發布到選取的管道。

完成之後,您可以在資產頁面上看到所有資產都已發布。(您可以由資產名稱上方的圖示來告知。)

作業 2:在 Flutter 建置最小地點
若要在 Flutter 應用程式中使用 Oracle Content Management 內容,可以使用 Flutter 最小網站範例,作為 GitHub 上的開放原始碼儲存區域。
注意:請記住,使用 Flutter 範例是選擇性的,我們會在本教學課程中使用它來快速開始。您也可以建置自己的 Flutter 應用程式。
在 Flutter 建立最小站台包括以下步驟:
安裝 Flutter
要開始使用 Flutter 的第一件事就是設定您的環境。您可以在Flutter 網站中找到設定該功能的指示。請使用與您作業系統對應的選項。以下為安裝步驟的摘要:
- 取得 Flutter SDK。
- 更新您的路徑環境變數。
- 執行
flutter doctor。 - 請依照 Flutter 網站中的步驟來安裝您選擇的編輯器。
- 新增 Android Studio、IntelliJ、VS Code 或 Emacs 的編輯器 Plugin。指示指定如何在編輯器中安裝 Flutter 和 Dart Plugin。
- 修改 android.properties 檔案中的值,以參照適當的位置、sdk 和 kotlin 版本。您可能也需要修改適當版本之 android.gradle 檔案中的值。
複製範例儲存庫並安裝相依性
Flutter 最小網站範例可在 GitHub 上做為開放原始碼儲存庫。
您必須先將範例從 GitHub 複製到您的本機電腦,並將您的目錄變更到儲存庫根目錄:
git clone https://github.com/oracle-samples/oce-flutter-minimal-sample.git
cd oce-flutter-minimal-sample
從 Android Studio 或您選擇的任何其他編輯器開啟專案。若要取得專案中使用的所有套裝軟體,請按一下 [取得套裝軟體] 按鈕。
設定 Flutter 應用程式
在此 Flutter 最小樣本中,您需要設定一些資訊,讓您的 REST API 要求可以使用正確的通道權杖作為正確的執行處理 URL 和 API 版本。lib/config/oce.dart 中定義的這些值會由 lib/networking/content.dart 中定義的函數使用,以建立 REST API 的端點。
您可以在 lib/config/oce.dart 中看到下列資訊:
const Map<String, String> config = <String, String>{
'serverUrl': 'https://samples.mycontentdemo.com',
'apiVersion': 'v1.1',
'channelToken': 'ba0efff9c021422cb134c2fd5daf6015'
};
變更每個索引鍵 - 值組以反映您的執行處理 URL、要目標的 API 版本,以及與您的發布通道關聯的通道權杖。本教學課程的管道為 OCEMinimalChannel。
我們也必須設定要在整個應用程式中使用的影像。在同一個檔案中,您會看到以下內容:
const Map<String, String> appConfig = <String, String>{
'homePage': 'Banner1.jpg',
'contactUs' : 'Banner2.jpg',
'logo' : 'Logo.png',
'footerLogo' : 'Powered_by_OCE.png',
};
變更每個映像檔的名稱以反映執行處理中的值。
使用 Oracle Content Management REST API 擷取內容
內容傳遞的 REST API 提供存取 Oracle Content Management 中發布的資產。發布的資產包括內容項目與數位資產,以及其轉譯。現在,我們可以運用 Oracle Content Management REST API 擷取內容,以便在最低的 Flutter 應用程式中轉譯內容。
lib/networking/content.dart 檔案具有使用 REST API 連線至 oce.dart 檔案中所指定伺服器的方法,並傳回其回應。
//Utility method to build up the URL for published content.
String _getPublishedContentServerURL() {
final String? serverUrl = data['serverUrl'] as String?;
final String? apiVersion = data['apiVersion'] as String?;
return '$serverUrl/content/published/api/$apiVersion/';
}
// Adds the channel token to the URL
String _addChannelToURL(String currUrl) {
final String? channelToken = data['channelToken'] as String?;
return '$currUrl?channelToken=$channelToken';
}
//Make an http get call and return the response if successful
Future<dynamic> _get(String url) async {
dynamic responseJson;
try {
final Response response = await get(Uri.parse(url));
responseJson = _returnResponse(response);
} on SocketException {
throw FetchDataException(kConnectionError);
}
return responseJson;
}
//Return the json decoded response body if response status is successful
dynamic _returnResponse(Response response) {
switch (response.statusCode) {
case 200:
final Map<String, dynamic>? responseJson =
json.decode(response.body.toString()) as Map<String, dynamic>?;
return responseJson;
case 400:
throw BadRequestException(response.body.toString());
case 401:
case 403:
throw UnauthorizedException(response.body.toString());
case 500:
default:
throw FetchDataException('StatusCode : ${response.statusCode}');
}
}
為轉譯影像,content.dart 也提供輔助方法來擷取資產的各種轉譯。
String getMediumRenditionUrl(Map<String, String> args) {
final String itemId = args['id'];
if (itemId == null) return null;
String url = _getPublishedContentServerURL();
url = '${url}assets/$itemId/Medium';
// add the channel token to the URL
url = _addChannelToURL(url);
url = '$url&format=jpg&&type=responsiveimage';
return url;
}
String getRenditionURL(Map<String, String> args) {
final String itemId = args['id'];
if (itemId == null) return null;
String url = _getPublishedContentServerURL();
url = '${url}assets/$itemId/native';
// add the channel token to the URL
url = _addChannelToURL(url);
return url;
}
lib/networking/services.dart 檔案包含用於取得應用程式資料的所有程式碼。
正在擷取影像資料
開啟 lib/networking/services.dart 並尋找下列函數,可協助取得此應用程式的所有映像檔。
// Get all the images needed for the app
Future<AppImages> getAppImages() async {
final Content content = Content();
final String homepageImage = appConfig['homePage'];
final String contactUsImage = appConfig['contactUs'];
final String logoImage = appConfig['logo'];
final String footerImage = appConfig['footerLogo'];
AppImages images;
try {
final dynamic data = await content.queryItems(<String, String>{
'q':
'(name eq "$homepageImage" OR name eq "$contactUsImage" OR name eq "$logoImage" OR name eq "$footerImage")',
'fields': 'all',
'expand': 'all',
});
final List<dynamic> items = data['items'] as List<dynamic>;
String homePageImageGUID,
contactUsImageGUID,
headerLogoGUID,
footerLogoGUID;
for (int i = 0; i < items.length; i++) {
final String name = items[i]['name'] as String;
final String id = items[i]['id'] as String;
if (name == homepageImage) {
homePageImageGUID = id;
} else if (name == contactUsImage) {
contactUsImageGUID = id;
} else if (name == logoImage) {
headerLogoGUID = id;
} else if (name == footerImage) {
footerLogoGUID = id;
}
}
//If any of the image ids are null, let the user know but continue loading the app
if (homePageImageGUID == null ||
contactUsImageGUID == null ||
headerLogoGUID == null ||
footerLogoGUID == null) {
print(kFileNameError);
}
images = AppImages(
headerLogoUrl: content.getRenditionURL(<String, String>{'id': headerLogoGUID}),
footerLogoUrl: content.getRenditionURL(<String, String>{'id': footerLogoGUID}),
contactUsImageUrl:
content.getMediumRenditionUrl(<String, String>{'id': contactUsImageGUID}),
homePageImageUrl: content.getMediumRenditionUrl(<String, String>{'id': homePageImageGUID}),
);
} catch (exception) {
rethrow;
}
return images;
}
;
現在我們有資料查詢,可以在雜亂元件中轉譯回應。
Flutter 元件
最小應用程式會將每個頁面細分為數個較小的元件。
以下幾節提供 Flutter 在每個元件中如何轉譯應用程式的簡介:
LoadingScreen 元件
LoadingScreen 是由 LoadingScreen 元件 (位於 lib/screens/loading_screen.dart) 所轉譯的狀態小工具。
lib/screens/loading_screen.dart 檔案包含用以取得畫面資料的所有代碼,並呼叫 services.dart 中定義的函數。
Future<void> getData() async {
final Services services = Services();
try {
final AppImages images = await services.getAppImages();
if (images != null) {
Navigator.push<dynamic>(context,
MaterialPageRoute<dynamic>(builder: (BuildContext context) {
return HomePage(appImages: images);
}));
}
} catch (exception) {
setState(() {
this.exception = exception.toString();
});
print(exception.toString());
}
}
元件使用 getData 方法,使用 services.dart 檔案中定義的方法取得資料。
HomePage 元件
主畫面由位於 lib/screens/home_page.dart 的 HomePage 元件轉譯。
HomePage 元件是由將資料傳遞至它的 LoadingScreen 元件所啟動。它不會從伺服器取得任何其他資料。
它也會使用 lib/components/screen_layout.dart 檔案中定義的 ScreenLayout 元件,以及 lib/components/image_stack.dart 檔案中定義的 ImageStack 元件。
ContactUs 元件
「與我們聯絡」畫面是由 ContactUs 元件 (位於 lib/screens/contact_us.dart) 所轉譯。
ContactUs 元件由 lib/components/navdrawer.dart 檔案中定義的 NavDrawer 元件啟動,並將資料傳遞給它。它不會從伺服器取得任何其他資料。它也會使用 lib/components/image_stack.dart 檔案中定義的 ImageStack 元件。
作業 3:準備應用程式以進行部署
現在,我們建立了 Flutter 最小型網站,需要將它部署在模擬器或裝置上,以便在正式上線之前,我們可以對任何問題進行除錯並預覽應用程式。
請依照 Flutter 網站中的指示,讓編輯器執行應用程式。
- 如果您使用 Android Studio 作為編輯器,請尋找主要的 Android Studio 工具列。
- 在目標選取器中,選取要執行應用程式的 Android 裝置。如果沒有列出可用的話,請選取「工具 > Android > AVD 管理員」,然後在該處建立一個。如需詳細資訊,請參閱管理 AVD。
- 按一下工具列中的執行圖示,或者呼叫功能表項目「執行 (Run)」>「執行 (Run)」。
結論
在本教學課程中,我們使用 Flutter 建立一個最少的網站,此網站可在 GitHub 找到。此網站使用 Oracle Content Management 作為無頭 (headless) CMS。在設定 Oracle Content Management 並設定最少網站教學課程的已發布內容通道之後,我們就會安裝並執行 Flutter 網站來擷取必要內容並建立網站。
如需有關 Flutter 的詳細資訊,請前往 Flutter 網站。
瞭解文件中的重要 Oracle Content Management 概念。
您可以在 Oracle Help Center 的 Oracle Content Management Samples 頁面找到更多範例。
使用無頭 (headless) Oracle Content Management 建置 Flutter 最小型網站
F55455-01
2022 年 3 月
Copyright © 2021, 2022, Oracle and/or its affiliates.
主要作者:Oracle Corporation