ラベル ファイル管理 の投稿を表示しています。 すべての投稿を表示
ラベル ファイル管理 の投稿を表示しています。 すべての投稿を表示

2022年12月9日金曜日

簡単なファイル管理アプリケーションの作成(7) - シークレットを使う

 暗号化キーの保存先をデータベースからOCIのボールトに変更してみました。暗号化キーは、ボールトのシークレットとして保存されます。

シークレットとしての操作は、以下の記事で作成したパッケージSFM_SECRET_UTILを使用します。

OCI PL/SQL SDKを使ってOCI Vaultのシークレットを操作する
http://apexugj.blogspot.com/2022/12/oci-secret-plsql-sdk.html

APEXアプリケーションとしての見た目や使い方に変更はありません。


表SFM_SECRETSの変更



暗号化キーを保存していた表SFM_SECRETSを作り直します。元の表はドロップし、以下の定義で表SFM_SECRETSを作成します。暗号化キーではなくシークレットのOCIDを保存します。
create table sfm_secrets (
    id                             number not null,
    version                        number not null,
    iv                             raw(16) not null,
    secret_ocid                  varchar2(400) not null,
    constraint sfm_secrets_pk primary key(id, version)
)
;


パッケージSFM_FILE_UTILの変更



変更したパッケージSFM_FILE_UTILのコードは以下になります。ファンクションの引数が増えているため、APEXアプリケーションの変更も必要です。


APEXアプリケーションの更新



シークレットを操作するPL/SQL SDKはコンパートメントマスター暗号化キーおよびボールトOCIDを引数に取ります。そのため、アプリケーション定義置換文字列としてG_COMPARTMENT_OCIDG_MASTER_KEY_OCIDG_VAULT_OCIDを追加します。

それぞれの値の取得方法は、パッケージSFM_SECRET_UTILに関する記事に記載があります。



パッケージSFM_FILE_UTILを呼び出しているプロセスに対して、パラメータの同期を実行します。

プロセス上でコンテキスト・メニューを表示させると、パラメータの同期が含まれています。


プロセスファイルのアップロードでは、パラメータとしてp_compartment_ocidp_master_key_ocidp_vault_ocidが追加されています。これらはそれぞれ置換文字列として追加したG_COMPARTMENT_OCIDG_MASTER_KEY_OCIDG_VAULT_OCIDを割り当てます。


プロセスファイルの削除では、パラメータとしてp_time_of_deletionが追加されています。こちらは、PL/SQL式として以下を記述します。

systimestamp + (interval '2' day)

削除したファイルに紐づくシークレットを、2日後に削除するようスケジュールします。


プロセスダウンロードでは、パラメータとしてp_vault_ocidが追加されています。これには置換文字列のG_VAULT_OCIDを割り当てます。


以上でアプリケーションの改変は完了です。

OCIのシークレットはこのような用途を想定しているのかどうかはわかりませんが、PL/SQL SDKのサンプルにはなっているでしょう。

また、APEX 22.2から使えるようになったプロセス・タイプAPIの呼び出しですが、本当に生産性が上がります。PL/SQLのコードをパッケージにまとめられるため、単体テストなども実施が容易です。

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

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

2022年12月8日木曜日

簡単なファイル管理アプリケーションの作成(6) - ファイルの暗号化

 オブジェクト・ストレージにファイルを保存するにあたってセキュリティが気になったので、ファイルをオブジェクト・ストレージにアップロードするときにAES256で暗号化、ダウンロードした後ブラウザに戻す際に復号するように実装してみました。

(追記: 引数opc_sse_customer_keyを指定することによりオブジェクト・ストレージに保存するファイルを暗号化できるので、そちらを使う方が正解でした。)

暗号キーと初期ベクターはデータベースに保存します。

ファイルをデータベースに保存していれば、オラクル・データベースが提供する各種のアクセス制御の機能(Database Vault、Virtual Private Database、Real Application Securityなど)が使えますが、ファイルを丸ごとデータベースのストレージに保存するのは高コストです。コストを下げるためにオブジェクト・ストレージにオフロードすると、セキュリティが心配になります。暗号化してファイルをオブジェクト・ストレージにオフロードすれば、それだけが盗まれても読めませんし、また、改ざんもできません。

データベースに暗号キーが保存されているので、それはアクセス制御をかけて保護する必要があります。ただし、ファイル丸ごとよりは容量を消費しません。

以下より実施した作業を説明します。


DBMS_CRYPTOの実行権限の付与


データベースでの暗号化および復号にはパッケージDBMS_CRYPTOを使用します。このパッケージを使用するため、APEXのワークスペース・スキーマにDBMS_CRYPTOの実行権限を与えます。

grant execute on dbms_crypto to <APEXのワークスペース・スキーマ>;

Autonomous Databaseでは、データベース・アクション開発SQLから実行します。APEXのワークスペース名がAPEXDEVである場合は、以下のgrant文を実行します。

grant execute on dbms_crypto to wksp_apexdev;


暗号キーを保存する表の作成


暗号キーと初期ベクターを保存する表SFM_SECRETSを作成します。

create table sfm_secrets (
    id                             number not null,
    version                        number not null,
    iv                             raw(16) not null,
    key                            raw(32) not null,
    constraint sfm_secrets_pk primary key(id, version)
)
;

SQLワークショップSQLコマンドから実行します。


パッケージSFM_FILE_UTILの置き換え


パッケージSFM_FILE_UTILを暗号化処理を組み込んだものに置き換えます。以下のコードを実行します。アップロードを行うプロシージャupload_fileではDBMS_CRYPTO.ENCRYPTを呼び出してファイルの内容を暗号化しています。download_fileではDBMS_CRYPTO.DECRYPTを呼び出し、ファイルを復号しています。それぞれ追加した行数は数行です。

APEXアプリケーションへの変更は不要です。

2022年12月7日水曜日

簡単なファイル管理アプリケーションの作成(5) - タグの抽出

 概要(列ABSTRACT)の内容から'#'で始まるタグを抽出し、ファイルの検索に利用します。

タグの抽出にはAPEX_STRING_UTIL.FIND_TAGSを使用します。

せっかくタグを抽出するので、それをマルチバリュー・ファセットとして使うファセット検索のページを作成します。

以下の動作をするページを作成します。


タグの抽出処理の追加


表SFM_CONTENTSに列TAGSを追加します。抽出したタグはJSON配列として保存します。Autonomous DatabaseのDB19cを想定しているため、format osonの指定を加えています。

alter table sfm_contents add (tags blob check (tags is json format oson));


ページ番号3のフォームのページに、新たにプロセスを追加します。

プロセスの識別名前タグの抽出とし、タイプコードの実行を選択します。実行するPL/SQLコードとして以下を記述します。
update sfm_contents set tags = 
    json_object(apex_string_util.find_tags(:P3_ABSTRACT))
where id = :P3_ID;
サーバー側の条件として、タイプリクエストは値に含まれるを選択し、としてCREATE SAVEを設定します。

ファイルの削除の下、ダイアログを閉じる - ファイル無しの上に配置します。



ファセット検索の追加



ファセット検索のページを作成します。

ページの作成を実行します。


ファセット検索を選択します。


ページ定義名前ファセット検索とします。データ・ソースソース・タイプSQL問合せを選択し、SQL SELECT文を入力に以下を記述します。


ナビゲーションデフォルトから変更しません。デフォルトの設定で、ブレッドクラムナビゲーション・メニューが作成されます。

へ進みます。


表示形式レポート、ファセットとして使用する列としてCONTENT_MIMETYPETAGSを選択します。

ページの作成を実行します。


ファセット検索のページが作成されます。

ファセットP5_TAGSは、JSON配列をデータとしたマルチバリュー・ファセットです。

自動的に認識されていないため、複数の値タイプJSON配列に変更します。フィルタの結合AND(論理積)を選択しています。


レポート検索結果の列IDVERSION識別タイプ非表示に変更します。


対話モード・レポートと同様に、タイトルをクリックしてファイルのダウンロードができるように、HTML式として以下を記述します。

<a href="&G_DOWNLOAD_URL.#ID#&session=&APP_SESSION.">#TITLE#</a>


検索ファセットのデフォルトはRow Searchになっています。Row Searchの代わりにOracle Textを使うこともできます。

ファセットP5_SEARCH設定検索タイプOracle Textに変更し、ソースデータベース列TITLEに限定します。列TITLEに作成した全文検索索引はユーザー・データストアを構成することにより、列TITLE、ABSTRACTそれとファイルの内容を元に作成されています。


以上でファセット検索のページは完成です。

ページを実行すると、先頭のGIF動画のように動作します。

今回作成したアプリケーションのエクスポートを以下に置きました。ファセット検索のページが追加されています。
https://github.com/ujnak/apexapps/blob/master/exports/simple-file-manager-tags.zip


APEX_STRING_UTIL.FIND_TAGSの問題



#で始まるタグが複数連続しているときに、1つの空白で分割されていると後続のタグが認識されません。空白が2つ以上あると複数のタグとして認識されます。

例えば、以下を実行すると結果は#日本だけになります。

select column_value from table(apex_string_util.find_tags('#日本 #北海道'));


空白が2つで分割されていると、#日本と#北海道になります。

select column_value from table(apex_string_util.find_tags('#日本  #北海道'));


空白の代わりにカンマで区切っても結果は同じです。

select column_value from table(apex_string_util.find_tags('#日本,#北海道'));

すでに開発元に報告済みの不具合のようです。

簡単なファイル管理アプリケーションの作成(4) - ファイルをオブジェクト・ストレージに保存する

 Always FreeのAutonomous Databaseのストレージは20GBなので、ちょっとファイルをアップロードすると容量が足りなくなります。ファイルを保存するために、高速なストレージを消費するのも勿体無い話ですし、それだけのために有料インスタンスにアップグレードするのも勿体無い気がします。

とういうことで、ファイルの実体をオブジェクト・ストレージに保存するようにAPEXアプリケーションを改変してみます。

アップロードされたファイルは、オブジェクト・ストレージに以下のように保存されます。


準備


今までの記事に従って、ファイル管理アプリケーションが作成済みであることを前提としています。今回はオブジェクト・ストレージを使うため、以下の記事の記載に従って準備します。

ユーザー、グループ、ポリシーなどの作成を行います。

APEXからOCIオブジェクト・ストレージを操作する(1) - APIユーザーの作成

バケットはapex_file_storageを使います。

PL/SQL SDKを使用するため、以下の記事にあるクリデンシャルの作成とワークスペース・スキーマへの権限の付与も実施します。

APEXからオブジェクト・ストレージをPL/SQL SDKで操作する(1) - 準備

作成されるクリデンシャルはMY_OCI_CREDになります。


表SFM_CONTENTSの変更



オブジェクト・ストレージにファイルを保存すると、全文検索索引の再作成ができなくなります。そのため、索引作成のソースとなる文字列を表SFM_CONTENTSに保存しておきます。

全文検索索引のソースを保存する列TEXT_INDEX_SOURCEを表SFM_CONTENTSに追加します。

alter table sfm_contents add (text_index_source blob);

また、変更回数を記録する列VERSIONも追加します。

alter table sfm_contents add (version number default 0 not null);

クイックSQLのモデルは以下のように変わります。
# prefix: sfm
# pk: guid
contents
    title vc80 /nn
    abstract vc800
    content file
    text_index_source blob
    version num /default 0 /nn

ファイルから全文検索索引のソースとなる文字列を抽出するプロシージャSFM_CONTENTS_DOCは以下に変更します。

ファイルがデータベースにアップロードされたときに、ファイルから文字列を抽出し列TEXT_INDEX_SOURCEに保存していることが前提です。索引を作成する際にファイルのデータを必要としないため、ファイルがオブジェクト・ストレージにあっても全文検索索引を作ることができます。

全文検索索引のソースは文字データなので圧縮することで容量を節約していますが、表自体が圧縮されている場合は不要かもしれません。そうすると列TEXT_INDEX_SOURCEはCLOBで定義できますが、今回は手が込んでいる方がサンプルとして使い勝手が良いだろうと判断し、圧縮して保存するようにしています。

表SFM_CONTENTSに列が追加されたため、ページ番号のフォームSfm Contentページ・アイテムの同期化を実行すると、ページ・アイテムP3_TEXT_INDEX_SOURCEP3_VERSIONが追加されます。このページ・アイテムにユーザーがデータを入力することは無いため、ビルド・オプションコメント・アウトしておきます。




オブジェクト・ストレージのアクセス情報の設定



ファイルを保存するオブジェクト・ストレージに関する情報を、アプリケーション定義置換文字列として設定します。

G_REGION - リージョン(今回の例ではus-ashburn-1
G_NAMESPACE - オブジェクト・ストレージのネームスペース
G_BUCKET - バケット名(今回の例ではapex_file_storage
G_CREDENTIAL - クリデンシャル(今回の例ではMY_OCI_CRED

置換文字列の設定では前後の空白はトリムされないため、不要な空白が入っていないか注意が必要です。



プロシージャとパッケージの作成



TEXT_INDEX_SOURCEにデータを保存するプロシージャretrieve_text_index_sourceを作成します。このデータが全文検索索引の作成時に使用されます。

SQLワークショップSQLコマンドに貼り付けて実行します。


次に、オブジェクト・ストレージにファイルをアップロードするプロシージャupload_fileとダウンロードするプロシージャdownload_file、および削除するプロシージャdelete_fileを実装したパッケージsfm_file_utilを作成します。

コードは以下になります。

SQLワークショップSQLスクリプトとして実行します。


確認画面が開くので、即時実行をクリックします。


パッケージパッケージ本体が作成されたことを確認します。




アップロード処理の変更



ページ・デザイナにてページ番号のフォームのページを開きます。

プロシージャretrieve_text_index_sourceを呼び出すプロセスを作成します。

プロセスの作成を実行し、新規に作成されたプロセスをプロセス・フォームSfm Contentの下に配置します。

識別名前文字列の抽出とし、タイプAPIの呼び出しを選択します。設定タイプとしてPL/SQL Procedure or Function所有者Parsing Schemaとし、プロシージャまたはファンクションとしてRETRIEVE_TEXT_INDEX_SOURCEを選択します。

サーバー側の条件タイプとしてリクエスト値に含まれるを選択し、CREATE SAVEを入力します。ボタン作成および変更の適用を押したとき(ボタン削除では実行しない)に、プロセス文字列の抽出を実行します。


パラメータp_idには、ページ・アイテムP3_IDの値を渡します。


同様にパッケージ・プロシージャupload_fileを呼び出すプロセスを作成します。

識別名前ファイルのアップロード設定タイプPL/SQL PackageパッケージSFM_FILE_UTILプロシージャまたはファンクションとしてUPOAD_FILEを選択します。

このプロセスも、ボタン作成または変更の適用がクリックされたときに実行します。


パラメータp_idにはページ・アイテムP3_IDの値を渡します。それ以外は、置換文字列として設定したG_REGIONG_NAMESPACEG_BUCKETG_CREDENTIALの値を渡します。


アップロードするファイルが指定されていないときは、文字列の抽出ファイルのアップロードが実行されないよう、その前にダイアログを閉じます。

プロセスを作成し、プロセス・フォームSfm Contentの直下に配置します。

識別名前ダイアログを閉じる - ファイル無しタイプとしてダイアログを閉じるを選択します。サーバー側の条件タイプとしてアイテムはNULLを選択し、アイテムとしてP3_CONTENTを選びます。


以上でオブジェクト・ストレージへのファイルのアップロードが実装できました。

アプリケーションからファイルをアップロードしても、列Cotentには何も表示されません。列CONTENTが空になっているためです。




ファイルの削除



ファイルが削除されたときに、オブジェクト・ストレージ上のファイルも削除します。

プロセスを作成します。識別名前ファイルの削除とします。

プロセス・フォームSfm Contentの直下に配置します。パラメータの設定はファイルのアップロードと同じ設定になります。

設定プロシージャまたはファンクションとしてDELETE_FILEを選択し、サーバー側の条件ボタン押下時としてDELETEを選択します。



ダウンロード処理の変更



列CONTENTの内容の代わりに、オブジェクト・ストレージ上のファイルをダウンロードするように処理を変更します。

ページ番号downloadのページに作成したプロセスダウンロードを、パッケージSFM_FILE_UTILDOWNOAD_FILEを呼び出すように変更します。


パラメータp_idへはアイテムIDを渡します。それ以外はアップロードのプロセスと同じく、オブジェクト・ストレージに関する置換文字列を指定します。


ファイルをオブジェクト・ストレージに配置しても、対話モード・レポートの列Download Urlは変わらず有効です。このURLからファイルをダウンロードできます。



ダウンロード・リンクの調整



対話モード・レポートからファイルをダウンロードする方法を変更します。

列CONTENTはつねに空なので、ソースとなるSELECT文より除きます。



列TITLEをクリックしてファイルのダウンロードが開始するよう、列の書式HTML式として以下を記述します。

<a href="#DOWNLOAD_URL#&session=&APP_SESSION.">#TITLE#</a>


ページ番号のフォームに含まれるページ・アイテムP3_CONTENT設定ダウンロード・リンクの表示OFFに変更します。


以上でアプリケーションは完成です。

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

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

2022年12月6日火曜日

簡単なファイル管理アプリケーションの作成(3) - Oracle Textによる全文検索索引

 表SFM_CONTENTSのBLOB列CONTENTに、Oracle Textによる全文検索索引を作成します。Oracle APEXでOracle Textを利用する場合、ユーザー・データストアを構成するのが一般的です。

以下にユーザー・データストアを使った全文検索索引の実装手順を紹介します。


CTX_DDLの実行権限


作成済みのAutonomous Databaseのデータベース・アクションに、管理者ユーザーADMINで接続します。

SQLの実行画面を開き、Oracle APEXのワークスペース・スキーマにCTX_DDLパッケージの実行権限を与えます。

grant execute on ctx_ddl to <APEXワークスペース・スキーマ>;

Oracle APEX 22.1以降でAutonomous Database上にワークスペースを作成している場合は、ワークスペース・スキーマ名はワークスペース名にWKSP_が接頭辞として追加されます。

ワークスペース名がAPEXDEVであれば、以下のようになります。

grant execute on ctx_ddl to wksp_apexdev;


APEXのワークスペースからCTX_DDLパッケージの実行が可能になりました。


Oracle Text全文検索索引の作成



日本語なので、レクサーとしてJAPANESE_LEXERを使うためのプリファレンスをja_lexerとして作成します。
begin
  ctx_ddl.create_preference('ja_lexer', 'JAPANESE_LEXER');
end;
/
BLOBとして保存されたデータより、文字データを抽出するフィルタを設定します。

以下のSQLを実行し、auto_policyというポリシーを作成します。このポリシーを指定することにより、BLOBにAUTO_FILTER(AUTO_FILTERについての説明はこちら)を適用します。
begin
  ctx_ddl.create_preference('auto_filter', 'AUTO_FILTER');
  ctx_ddl.create_policy('auto_policy', 'auto_filter');
end
/
ユーザー・データストアに登録するプロシージャsfm_contents_docを作成します。

列TITLEとABSTRACT、それと列CONTENTからAUTO_FILTERを適用して抽出された文字データを連結してCLOB(文字データ)として返します。AUTO FILTERの適用に失敗した場合(CTX_DOC.POLICY_FILTERで例外が発生した場合)はどうしようもないので、無視して検索対象のデータから外しています。
create or replace procedure sfm_contents_doc(
    rid in rowid,
    tlob in out nocopy clob
)
is
    l_clob clob;
begin
    for c in (select title, abstract, content from sfm_contents where rowid = rid)
    loop
        if c.title is not null then
            dbms_lob.writeappend(tlob, length(c.title), c.title);
        end if;
        if c.abstract is not null then
            dbms_lob.writeappend(tlob, 1, ' ');
            dbms_lob.writeappend(tlob, length(c.abstract), c.abstract);
        end if;
        if dbms_lob.getlength(c.content) > 0 then
            begin
                dbms_lob.writeappend(tlob, 1, ' ');
                ctx_doc.policy_filter('auto_policy', c.content, l_clob, true);
                dbms_lob.copy(tlob, l_clob, length(l_clob), length(tlob)+1, 1);
            exception
            when others then
                null;
                -- record_sfm_filter_exception(rid, sqlcode, sqlerrm);
            end;
        end if;
    end loop;
end sfm_contents_doc;
ユーザー・データストアsfm_contents_docを作成します。

先ほど作成したプロシージャsfm_contents_docにより、索引を作成する元になる文字データがCLOB形式で返されます。OWNERの部分は、作成したプロシージャsfm_contents_docの所有者であるAPEXのワークスペース・スキーマ名になります。以下の例ではWKSP_APEXDEVを指定しています。
begin
    ctx_ddl.create_preference('sfm_contents_doc', 'user_datastore'); 
    ctx_ddl.set_attribute('sfm_contents_doc', 'procedure', 'WKSP_APEXDEV.sfm_contents_doc'); 
    ctx_ddl.set_attribute('sfm_contents_doc', 'output_type', 'CLOB');
end;
作成したユーザー・データストアを使って全文検索索引SFM_CONTENTS_SIDXを作成します。
CREATE INDEX "SFM_CONTENTS_SIDX" ON "SFM_CONTENTS" ("TITLE") 
INDEXTYPE IS "CTXSYS"."CONTEXT"  PARAMETERS ('filter ctxsys.null_filter lexer ja_lexer datastore sfm_contents_doc sync(on commit)');
以上で全文検索索引が作成されました。

上記のスクリプトをまとめます。


SQLワークショップSQLスクリプトを使って実行できます。


エラーが発生した場合などに、作成済みのポリシーやプリファレンスの削除を行なうスクリプトです。


ユーザー・データストアのソースとなる文字列の確認に使用できるスクリプトです。

SQLワークショップSQLコマンドより実行します。


検索対象の文字列がファイルに含まれているにもかかわらず、ヒットしないときはAUTO_FILTERの処理に失敗している場合があります。


レポートのOracle Text検索列の設定



対話モード・レポートを含むページをページ・デザイナで開き、対話モード・レポートのリージョンの属性を選択し、詳細のカテゴリに含まれるOracle Text索引列を、全文検索索引SFM_CONTENTS_SIDXを作成した列TITLEにします。


Oracle Text索引列としてTITLEを選択しています。しかし、ユーザー・データストアに使用しているプロシージャは、TITLE、ABSTRACT、CONTENTを合成した文字列を返しています。その上で全文検索索引を作成しているため、TITLE、ABSTRACT、CONTENTに含まれる文字列が全文検索の対象となります。

以上で簡単なファイル管理アプリケーションができました。

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

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

補足

AUTO_FILTERでの例外の捕捉には自律トランザクションが必要でしょう。以下のようなコードをnullの部分に挿入する必要がありそうです。文字列の抽出に失敗するデータを見つけられなかったので動作は検証できていません。

nullの部分に以下を記述します。

record_sfm_filter_exception(rid, sqlcode, sqlerrm);


簡単なファイル管理アプリケーションの作成(2) - 直リンクによるダウンロード

ファイルのIDをURLの引数に与え、指定したファイルを直接ダウンロードできるようにします。

直リンクの実装の詳細、特にページの保護に関する説明については記事「特定のページへの直リンクによるアクセス」を参照してください。ページ・プロパティのディープ・リンクやページ保護の設定の意味について説明をしています。

本記事では、主に実装の手順について紹介します。

以下のような機能を、本記事では実装します。ダウンロードURLを電子メールなどに含めることにより、ファイルを共有することができます。



アプリケーション・アイテムの作成



ダウンロードの対象とするファイルを、URLの引数IDによって特定できるようにします。IDには表SFM_CONTENTSの列IDの値(つまり主キーの値)を指定します。

共有コンポーネントアプリケーション・アイテムを開きます。


作成済みのアプリケーション・アイテムが一覧されます。

作成を実行します。


作成するアプリケーション・アイテムは名前IDとし、セッション・ステート保護制限なしに設定します。設定した後、アプリケーション・アイテムの作成を実行します。


直リンクとなるURLを、セッションの開始時にアプリケーション・アイテムとして設定します。アプリケーションがインストールされているワークスペース名やアプリケーション別名によってURLは変わります。

アプリケーション・アイテムの名前G_DOWNLOAD_URLとします。セキュリティセッション・ステート保護制限付き - ブラウザから設定不可を選択し(これがデフォルトです)、アプリケーションのユーザーによる値の設定を禁止します。


アプリケーション・アイテムIDおよびG_DOWNLOAD_URLが作成されます。


アプリケーション・アイテムG_DOWNLOAD_URLに値を設定します。

共有コンポーネントアプリケーションの計算を開きます。


作成済みのアプリケーションの計算が一覧されます。作成をクリックします。


計算アイテムとしてG_DOWNLOAD_URLを選択します。頻度計算ポイント新規インスタンス(新規セッション)開始時です。

計算計算タイプファンクション本体を選択し、計算として以下のPL/SQLコードを記述します。


計算の作成をクリックします。


アプリケーションの計算が作成されました。

セッションの開始時にアプリケーション・アイテムG_DOWNLOAD_URLに直接ダウンロードするためのURLが設定されます。


ダウンロード機能の実装



プログラムの中からファイルのダウンロードを呼び出すために、APEX_UTIL.GET_BLOB_FILE_SRCを使用します。このAPIの引数p_item_nameとして、ダウンロードするファイルが保存されているBLOB列が割り当てられているページ・アイテムを指定します。このようなページ・アイテムは通常、フォームに含まれています。

今回のアプリケーションでは表SFM_CONTENTSのフォームが、ページ番号Sfm Contentとして作成されています。フォームに含まれるページ・アイテムP3_CONTENTp_item_nameに与えることができます。

ページ・アイテムP3_CONTENTを使って、ダウンロード機能を実装します。アプリケーションにp_item_nameとして割り当て可能なページ・アイテムが含まれない場合は、フォームを実装したページを新たに作成する必要があります。

ダウンロード機能を実装するページを作成します。

ページの作成を実行します。


空白ページを選択します。


ページ定義名前downloadとします。ダウンロードURLのターゲットはこのページ名になります。ページ・モード標準ナビゲーションブレッドクラムの使用ナビゲーションの使用はともにOFFです。この空白のページがユーザーに表示されることはありません。

ページの作成を実行します。


ページが作成されます。

ページ・プロパティのセキュリティに含まれるディープ・リンク有効にします。また、ページ・アクセス保護制限なしにします。


レンダリング前ヘッダー前にプロセスを作成します。

識別名前ダウンロードタイプコードの実行を選択します。PL/SQLコードとして以下を記述します。


サーバー側の条件タイプアイテムはNULLではないを選択し、アイテムIDを指定します。URLの引数としてIDがなければプロセスは実行しません。


以上で実装は完了です。

直接ファイルをダウンロードするURLを確認します。

対話モード・レポートのソースに以下の列DOWNLOAD_URLを追加します。

:G_DOWNLOAD_URL || id download_url

ページ番号2の対話モード・レポートのソースSQL問合せを以下のSELECT文に置き換えます。



アプリケーションを実行し、対話モード・レポートに表示する列にDownload Urlを追加します。


表示されたURLを直接アクセスすると、ユーザー認証が要求されます。これはページdownload認証が必要なページとして設定されているためです。正しいユーザー名とパスワードでサインインを行うとファイルのダウンロードが開始します。ページのディープ・リンク有効でなければ、サインインの後は必ずホーム・ページが開くように制限されるため、ページdownloadが開くことはありません。また、ページ・アクセス保護制限なしであるため、引数idの指定が許されています。

続く