データベースに保存されているBLOBおよびCLOBをダウンロードするために、WPG_DOCLOAD.DOWNLOAD_FILEやAPEX_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とします。外観のホットをオン、テンプレート・オプションのWidthをStretchとします。
動作のアクションはデフォルトのファイルの送信です。処理中を表示をオンにします。この設定はOracle APEX 24.1で新規に追加されました。ページの処理中にページ全体をグレーアウトし、他の操作を抑止します。
識別の名前は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をオンにします。
AvatorのTypeにImageを選択します。(そのため、アップロードされたファイルがExcelなどの画像でない場合はAvatorが表示されません。)Imageをクリックし、メディア属性のソースとしてBLOB列を選択し、表EBMJ_TEMP_FILESの列を指定します。SizeはExtra Largeを選択します。
行選択のタイプを複数選択とし、現在の選択のページ・アイテムとしてP1_SELECTED_FILESを指定します。
Imageのメディア属性では、ソースとしてBLOB列を選択します。BLOB列にCONTENT、ファイル名列にCONTENT_FILENAME、MIMEタイプ列にCONTENT_MIMETYPE、最終更新列にCONTENT_LASTUPDを指定します。
以上で表EBMJ_TEMP_FILESにファイルをアップロードできるようになりました。
アプリケーションを実行し、いくつかファイルをアップロードします。
Upload Filesをクリックし、いくつかファイルを選択した後にボタンUploadをクリックします。アップロードしたファイルが表示されたら、いくつか行を選択してみます。
これで、ファイルをダウンロードする機能を実装する準備ができました。
これから複数のボタンを作成します。それらのボタンを配置するリージョンを作成します。
リージョンを作成しページ・アイテムP1_SELECTED_FILESの下に配置します。
識別の名前はButtons、タイプは静的コンテンツとします。外観のテンプレートにButtons Containerを選択します。
識別のボタン名は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_PROCESSのクリックにより実行されるブランチを作成します。
識別の名前はCall Download、動作のタイプはページまたはURL(リダイレクト)、ターゲットは前出の設定になります。
サーバー側の条件のボタン押下時にDOWNLOAD_PROCESSを指定します。
ターゲットの成功メッセージはオン、オフどちらでも成功メッセージは表示されません。
- そもそも、ブランチに先行して実行されるプロセスが無いため、表示する成功メッセージ自体がありません。
- このブランチはダウンロードのプロセスを呼び出します。ダウンロードのプロセスは、ダウンロードが完了した時点で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のアプリケーション作成の参考になれば幸いです。
完