2024年3月13日水曜日

動的アクションでファイルをアップロードする

Oracle APEXではファイルをアップロードするには、ページを送信する(ページに対してPOSTリクエストを発行する)必要があります。具体的にはアクションページの送信であるボタンのクリックか、または、JavaScript APIのapex.page.submitの呼び出しです。

この場合、ページとともにファイルが送信された後にページ全体が再ロードされます。ページ全体の再ロードを行わずにファイルをアップロードするために、ブラウザ側でファイルをアップロードする処理をJavaScriptで記述し、かつ、アップロードされたファイルを受け付ける処理をORDSのRESTサービスとして作成します。

作成したアプリケーションは以下のように動作します。ボタン作成変更の適用をクリックしたときは、Oracle APEX標準のページの送信によるファイルのアップロードが行われます。ボタンREPLACEをクリックすると、動的アクションによるファイルのアップロードを行います。動的アクションによるファイルのアップロードではページの送信を行っていないため、ドロワーが閉じません。


以下よりアプリケーションの作成方法について紹介します。

クイックSQLの以下のモデルより、アップロードするファイルを保存する表FUD_DOCUMENTSを作成します。
# prefix: fud
documents
    file_name vc80
    mime_type vc80
    content  blob
レビューおよび実行をクリックし、最終的に表FUD_DOCUMENTSが作成されるまで画面操作を行います。


作成された表FUD_DOCUMENTSを元に、アプリケーションの作成を行います。


アプリケーション作成ウィザードが起動します。

名前Sample File Upload by DAとし、アプリケーションの作成を実行します。


アプリケーションが作成されたら、ページ・デザイナでページ番号のフォーム画面を開きます。

ページ・アイテムP3_CONTENTストレージMIMEタイプ列MIME_TYPEファイル名列FILE_NAMEを設定します。


以上でページの送信によるファイルのアップロードについては、最低限の実装ができました。

アップロードされたファイルを受け付けて、表FUD_DOCUMENTSを更新するRESTfulサービスを作成します。

モジュール名FUD - File Upload Sampleとしています。モジュール・ベース・パス/fud/URIテンプレートuploadとしました。結果としてファイルのアップロード以下のURLを呼び出して実行します。

/ords/<ワークスペース名>/fud/upload

メソッドPUTソースとして以下を記述します。

begin
update fud_documents set content = :body, file_name = :NAME, mime_type = :TYPE where id = :ID;
htp.p('{ "success" : true })');
:status := 200;
end;

パラメータとしてnametypeidを追加します。バインド変数はそれぞれNAMETYPEIDです。ソース・タイプURIデータ型idINTEGER、それ以外はSTRINGとします。


作成したRESTfulサービスをAPEXのセッションによって保護するため(Apex-Sessionヘッダーによる保護)、権限を作成します。

名前タイトルFUD File UPload Sampleとし、ロールRESTful ServicesモジュールFUD - File Upload Sampleを選択します。


以上でファイルのアップロードを受け付けるRESTfulサービスは完成です。

ファイルのアップロードを行なうボタンREPLACEを作成します。

ページ・デザイナでページ番号を開きます。

ボタンREPLACEを作成し、動作アクションとして動的アクションで定義を選択します。


ボタンREPLACEに動的アクションを作成します。識別名前onClick REPLACEとします。


TRUEアクションとしてJavaScriptコードの実行を選択し、設定コードに以下を記述します。

/*
* ボタンを押したときに呼び出される。
*/
const content = document.getElementById("P3_CONTENT");
const file = content.files[0];
const filename = file.name;
const mimetype = file.type;
const reader = new FileReader();
const spinner = apex.widget.waitPopup(); // スピナー表示開始。
/*
* P3_CONTENTに設定されたファイルが読み込まれた。
*/
reader.onload = () => {
/*
* 読み込んだファイルをORDS REST APIを呼び出して送信する。
*/
const formData = new FormData();
formData.append("file", reader.result);
const request = new XMLHttpRequest();
/*
* 送信が完了した。
*/
request.onreadystatechange = () => {
if (request.readyState === 4) {
alert(request.response);
spinner.remove(); // スピナー表示終了。
}
};
/*
* ORDS REST APIを呼び出す。
* 送信が終了したらrequest.onreadystatechangeが呼び出される。
*/
request.open("PUT", "/ords/apexdev/fud/upload?id=" + apex.items.P3_ID.value + '&name=' + filename + '&type=' + mimetype);
request.setRequestHeader("Apex-Session", apex.env.APP_ID + "," + apex.env.APP_SESSION);
request.send(formData);
}
/*
* P3_CONTENTで選択されたファイルを読み込む。
* 読み込み完了で reader.onload が呼び出される。
*/
reader.readAsBinaryString(file);
view raw file-upload.js hosted with ❤ by GitHub

以上でアプリケーションは完成です。実行すると先頭のGIF動画のように動作します。

作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-file-upload-by-da.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。