2024年7月25日木曜日

APEX 24.1で追加されたファイルのダウンロードを行なうプロセスと動的アクションを使ってみる

Oracle APEX 24.1では動的アクションタイプとしてダウンロードが追加されました。また、プロセスタイプとしてもダウンロードが追加されています。

データベースに保存されているBLOBおよびCLOBをダウンロードするために、WPG_DOCLOAD.DOWNLOAD_FILEAPEX_DATA_EXPORT.DOWNLOADを呼び出すコードを書く必要がなくなりました。また、動的アクションからファイルのダウンロードを呼び出すこともできるため、Ajaxコールバックを作成する必要も無くなりました。

BLOBやCLOBのダウンロードに関して、これからはコードを書く必要はありません。

実際に新しく追加された動的アクションのダウンロードとプロセスのダウンロードを使ったアプリケーションを作成してみます。

作成したアプリケーションは以下のように動作します。


最初にファイルをBLOBとして保存する表EBMJ_TEMP_FILESを作成します。以下のDDLを実行します。
create table ebmj_temp_files (
    id                  number generated by default on null as identity
                        constraint ebmj_temp_files_id_pk primary key,
    content             blob,
    content_filename    varchar2(255 char),
    content_mimetype    varchar2(255 char),
    content_charset     varchar2(255 char),
    content_lastupd     date
);

空のアプリケーションを作成します。名前新しいダウンロードとします。


アプリケーションが作成されます。すべての機能はホーム・ページに実装します。


最初にアップロードするファイルを複数選択するページ・アイテムを作成します。

識別名前P1_UPLOAD_FILESタイプファイルのアップロードラベルUpload Filesとします。ストレージタイプとして表APEX_APPLICATION_TEMP_FILESを選択します。

アップロードしたファイルは表EBMJ_TEMP_FILESに保存しますが、ストレージタイプアイテム・ソース属性で指定されたBLOB列を選択すると単一ファイルの選択に制限されるため、一旦、APEX_APPLICATION_TEMP_FILESにアップロードした後にEBMJ_TEMP_FILESに移し替えます。

ファイルをパージするタイミングリクエストの終わり複数ファイルの許可オンにします。

セッション・ステートストレージリクエストごと(メモリーのみ)を設定します。


選択したファイルをアップロードするボタンを作成します。

識別名前UPLOADラベルUploadとします。外観ホットオンテンプレート・オプションWidthStretchとします。

動作アクションはデフォルトのファイルの送信です。処理中を表示オンにします。この設定はOracle APEX 24.1で新規に追加されました。ページの処理中にページ全体をグレーアウトし、他の操作を抑止します。


アップロードされたファイルを表EBMJ_TEMP_FILESに入れ替えるプロセスを作成します。

識別名前Store Uploaded Filesタイプコードを実行です。ソースPL/SQLコードとして以下を記述します。
insert into ebmj_temp_files(content_filename, content_mimetype, content, content_lastupd)
select filename, mime_type, blob_content, created_on
from apex_application_temp_files
where name in (select column_value from apex_string.split(:P1_UPLOAD_FILES, ':'));
サーバー側の条件ボタン押下時UPLOADを指定します。


アップロードされたファイルを表示するリージョンを作成します。リージョンのタイプとしてContent Rowを選択し、列の複数選択を有効にします。そのため、選択した列の情報を保存するページ・アイテムを先に作成します。

識別名前P1_SELECTED_FILESタイプテキスト・フィールドとします。一般的な実装ではタイプ非表示にしますが、今回はサンプルなので値を確認しやすいように内容を画面に表示します。

セッション・ステートストレージリクエストごと(メモリーのみ)です。


アップロードされたファイルを一覧するリージョンを作成します。

識別名前FilesタイプContent Rowとします。表名としてEBMJ_TEMP_FILESを選択します。


選択された行は、主キーの値がページ・アイテムP1_SELECTED_FILESに設定されます。

IDソース主キーオンであることを確認します。


リージョンの属性を開き、表示のされ方を設定します。

外観表示複数(レポート)です。設定Titleとして&CONTENT_FILENAME.を設定し、ファイル名を表示させます。Display Avatarオンにします。

AvatorTypeImageを選択します。(そのため、アップロードされたファイルがExcelなどの画像でない場合はAvatorが表示されません。)Imageをクリックし、メディア属性ソースとしてBLOB列を選択し、表EBMJ_TEMP_FILESの列を指定します。SizeExtra Largeを選択します。

行選択タイプ複数選択とし、現在の選択のページ・アイテムとしてP1_SELECTED_FILESを指定します。


Imageメディア属性では、ソースとしてBLOB列を選択します。BLOB列CONTENTファイル名列CONTENT_FILENAMEMIMEタイプ列CONTENT_MIMETYPE最終更新列CONTENT_LASTUPDを指定します。


以上で表EBMJ_TEMP_FILESにファイルをアップロードできるようになりました。

アプリケーションを実行し、いくつかファイルをアップロードします。

Upload Filesをクリックし、いくつかファイルを選択した後にボタンUploadをクリックします。アップロードしたファイルが表示されたら、いくつか行を選択してみます。


これで、ファイルをダウンロードする機能を実装する準備ができました。

これから複数のボタンを作成します。それらのボタンを配置するリージョンを作成します。

リージョンを作成しページ・アイテムP1_SELECTED_FILESの下に配置します。

識別名前Buttonsタイプ静的コンテンツとします。外観テンプレートButtons Containerを選択します。


テストを容易にするため、選択したファイルを削除するボタンを作成します。ボタンを配置するリージョンButtonsです。

識別ボタン名DELETEラベルDelete動作アクションページの送信とします。

処理中を表示オン確認の要求オン確認メッセージ本当に削除しますか?として、スタイル危険を選択します。


実際にファイルを削除するプロセスを作成します。

識別名前Delete Filesタイプコードを実行です。

ソースPL/SQLコードとして以下を記述します。
delete from ebmj_temp_files where id in (select column_value from apex_string.split(:P1_SELECTED_FILES, ':'));
サーバー側の条件ボタン押下時DELETEを指定します。


これで簡単にダウンロードの対象とするファイルを入れ替えられるようになりました。

これからAPEX 24.1の新機能を使ったファイルのダウンロードを実装します。

複数のファイルをZIPにまとめてダウンロードするボタンを作成します。動的アクションにて実装します。

識別ボタン名DOWNLOAD_MULTIラベルDownload (Multi)とします。ボタンを横一列に並べるため、レイアウト新規行の開始オフにします。

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


ボタンDOWNLOAD_MULTI動的アクションを作成します。

識別名前onClick DOWNLOAD_MULTIとします。タイミングイベントはボタンのデフォルトであるクリックです。


TRUEアクションとしてAPEX 24.1で新設されたダウンロードを選択します。

このボタンのアクションでは、複数のファイルをひとつのZIPファイルとしてダウンロードします。

複数のファイルオンにします。ファイル名としてdownload_&SYSDATE_YYYYMMDD..zipを設定します。一般的にAutonomous Databaseの場合、 データベースのタイムゾーンはUTCとなっているため&SYSDATE_YYYYMMDD.はUTCで置き換わります。ファイル名に置換文字列を含める例としてAPEX標準のSYSDATE_YYYYMMDDを含めています。

ソースSQL問合せとして以下を記述します。検索されたBLOBがZIPファイルに含まれます。
select content, content_filename from ebmj_temp_files 
where id in (select column_value from apex_string.split(:P1_SELECTED_FILES, ':'))
送信するアイテムとしてP1_SELECTED_FILESを指定します。

これでデータベースにBLOBとして保存されているファイルを、ひとつのZIPファイルにまとめてダウンロードできるようになりました。


選択したファイルをブラウザに表示するボタンを作成します。動的アクションにて実装します。

識別ボタン名VIEW_SINGLEラベルView (Single)とします。ボタンの設定や動的アクションの作成手順は、ボタンDOWNLOAD_MULTIと同様です。動的アクション名前onClick VIEW_SINGLEとします。


TRUEアクションダウンロードを選び、設定複数のファイルオフファイルの表示形式インラインを選択します。

インラインを選ぶと、ファイルはブラウザに表示されます。ファイルの表示形式として添付を選ぶと、通常のファイルとしてのダウンロードになります。

ソースSQL問合せとして以下を記述します。検索結果が複数ある場合は、先頭行が表示/ダウンロードの対象となる仕様になっていますが、fetch句を付けて検索結果が1行になるように制限しています。
select content, content_filename from ebmj_temp_files 
where id in (select column_value from apex_string.split(:P1_SELECTED_FILES, ':'))
fetch first 1 rows only
送信するアイテムとしてP1_SELECTED_FILESを指定します。

これでデータベースにBLOBとして保存されているファイルを、ブラウザに表示できるようになりました。


APEX 24.1では動的アイテムのアクション以外に、プロセスタイプとしてもダウンロードが追加されています。ただし、プロセスによるダウンロードは用途が限定的です。直リンクによるアクセスによりファイルをダウンロードするような場合が、主な用途になると思います。

レンダリング前ヘッダーの前に、複数のファイルをまとめてZIPとしてダウンロードするプロセスを作成します。ダウンロードのプロセスはレンダリング前に作成する必要があります。

識別名前Download Filesタイプダウンロードとします。

設定複数のファイルオンファイル名download_&SYSDATE_YYYYMMDD..zipソースSQL問合せとして以下を記述します。
select content, content_filename from ebmj_temp_files 
where id in (select column_value from apex_string.split(:P1_SELECTED_FILES, ':'))
サーバー側の条件タイプとしてリクエスト = 値を選択し、DOWNLOADを指定します。


ファイルの選択時に参照しているページ・アイテムP1_SELECTED_FILESは、セッション・ステートに保存されている値か、ページ呼び出し時の引数として渡された値を参照します。

このプロセスを呼び出すボタンを作成します。

識別ボタン名DOWNLOAD_PROCESSラベルDownload (Process)とします。レイアウト新規行の開始オフです。動作アクションはデフォルトのページの送信とします。


レンダリング前に配置されているプロセスを呼び出すだけであれば、動作アクションとしてこのアプリケーションのページにリダイレクトを選択し、ターゲットとして以下を指定することにより、ダウンロードのプロセスを呼び出すことができます。

しかし、アイテムの設定で名前P1_SELECTED_FILESとして渡している\&P1_SELECTED_FILES.\(値は:(コロン)で分割されているためバックスラッシュによるエスケープは必須です)は、ページが最初に表示されたときの値で置き換えられるため、ページ表示後にユーザーが行った選択は反映されません。

そのため、このボタンでは一旦ページの送信を行い、ブランチからダウンロードのプロセスを呼び出すようにします。また、ページの送信処理が終了する前にブランチにより別のページに遷移するため、処理が終わっていないと見做されます。そのため、処理中を表示オフにします。

詳細リクエストとしてDOWNLOADを設定し、ダウンロードのプロセスの実行条件とします。


プロセスの後に、ボタンDOWNLOAD_PROCESSのクリックにより実行されるブランチを作成します。

識別名前Call Download動作タイプページまたはURL(リダイレクト)ターゲットは前出の設定になります。

サーバー側の条件ボタン押下時DOWNLOAD_PROCESSを指定します。


ターゲット成功メッセージオンオフどちらでも成功メッセージは表示されません。
  1. そもそも、ブランチに先行して実行されるプロセスが無いため、表示する成功メッセージ自体がありません。
  2. このブランチダウンロードのプロセスを呼び出します。ダウンロードのプロセスは、ダウンロードが完了した時点でAPEXのページ・プロセスを終了するため、ページのレンダリングは行われません。そのため、仮に成功メッセージがあっても、成功メッセージは表示されません。

以上で、ボタンDOWNLOAD_PROCESSのクリックからブランチが呼び出され、ファイルのダウンロードが行われるようになりました。

レンダリング前に、選択したファイルをインラインで表示するプロセスを作成します。ボタンVIEW_SINGLEの動的アクションの設定と、ほぼ同じです。

識別名前View Fileタイプダウンロード設定複数のファイルオフとし、ファイルの表示形式インラインを選択します。

ソースSQL問合せとして以下を記述します。
select content, content_filename from ebmj_temp_files 
where id in (select column_value from apex_string.split(:P1_SELECTED_FILES, ':'))
fetch first 1 rows only
サーバー側の条件タイプとしてリクエスト = 値を選択し、VIEWを指定します。


このプロセスを呼び出すボタンブランチを作成します。

ボタンDOWNLOAD_PROCESSとブランチCall Downloadとほぼ同じ設定になります。

作成するボタン識別ボタン名VIEW_PROCESSラベルView (Process)とします。その他はボタンDOWNLOAD_PROCESSと同じです。


作成するブランチ識別名前Call Viewサーバー側の条件ボタン押下時VIEW_PROCESSを指定します。


ターゲット詳細リクエストとしてVIEWを設定します。それ以外はブランチCall Downloadと同じ設定です。


以上で、ボタンVIEW_PROCESSのクリックからブランチが呼び出され、ファイルの表示が行われるようになりました。

今回の実装は以上で完了です。アプリケーションを実行すると、記事の先頭のGIF動画のように動作します。

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

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