0
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

【SAPUI5】UIからxsjsを経由してHANA DBに画像登録をする

HANA DBへの画像登録

はじめに

こんにちは。
HANAで作成したテーブルに対して,xsjsのREST APIを使用して画像アップロードする方法を調査しましたので共有します。
なお,今回の記事では画像ファイルをNCLOB型で作成したカラムに保存することを想定しています。

テーブル作成

SQL

xsjsでの扱いやすさの観点からデータ型はNCLOBで作成していきます。

CREATE COLUMN TABLE "STORE"."IMG_TEST"(
    "IMG_NAME" NVARCHAR(100),
    "IMG_VALUE" NCLOB ,
    PRIMARY KEY (
        "IMG_NAME"
    )
)

その他ファイルを扱えるデータ型

NCLOBの他にファイルを扱えるデータ型は以下です。

BLOB

BLOB データ型は、大量のバイナリデータを格納するために使用されます。BLOB 値は VARBINARY に変換できます。SAP HANA の BLOB データ型は SAP ASE の IMAGE データ型にマッピングされます。

CLOB

CLOB データ型は、大量の 7 ビット ASCII 文字データを格納するために使用されます。CLOB 値は VARCHAR に変換できます。SAP HANA の CLOB および BCLOB データ型は、SAP ASE の TEXT データ型にマッピングされます。

【参考資料】

UI側(保存処理)

fileUploaderの用意

ブラウザにファイルがアップロードができればなんでもいいですが,今回はsap.ui.unifiedのFileUploaderを使っていきます。
ここでchangeイベントを設定します change="onChangeImage"

<un:FileUploader id="fileUploader" buttonOnly="true" change="onChangeImage" width="100px" fileType="jpg,png,jpeg" tooltip="Upload your file"/>

プレビューの表示

選択した画像のプレビューをUIに表示します。

View側

viewでidを設定

<Image class="imagePreview" width="600px" id="image"></Image>

Controller側

changeイベントでブラウザにアップロードされたファイルを取得し,viewのidに対してsrcを設定します。
また,ここでファイルデータをURLに整形しreader.readAsDataURL(file);,必要な情報と合わせてモデルにセットしておきます。

onChangeImage: function (oEvent) {
    var _this = this;
    var oView = _this.getView();

    if (oEvent.getSource().oFileUpload.files.length > 0) {
        var file = oEvent.getSource().oFileUpload.files[0];
        var reader = new FileReader();

        //dataURL形式でファイルを読み込む
        reader.readAsDataURL(file);

        //ファイルの読込が終了した時の処理
        reader.onload = function () {
            // 送信用にモデルにファイル(URL化)を保持
            var imgData = reader.result;
            var fileType = file.type;
            var params = {
                imgData: imgData,
                fileType: fileType
            };
            var paramsJson = new JSONModel(params);
            oView.setModel(paramsJson, "params");
        };

        // Viewに画像をセット
        var path = URL.createObjectURL(file);
        this.getView().byId("image").setSrc(path);
    }
}

画面イメージ

参照ボタン押下

スクリーンショット 2021-05-28 12.06.14.jpg

アップロードする画像を選択

スクリーンショット 2021-05-28 12.08.06.jpg

プレビュー表示

スクリーンショット 2021-05-28 12.06.57.jpg

送信ボタン押下時処理

contentTypeにファイルのデータタイプを設定し,processDatafalseにしています。
dataで送信するimageDataをURLのパラメータに設定しないために上記設定を記載します。

pressUploadButton: function () {
    var _this = this;
    var oView = _this.getView();

    var oFileUploader = this.getView().byId("fileUploader");
    var oStorage = jQuery.sap.storage(jQuery.sap.storage.Type.session);
    var params = oView.getModel("params").oData;

    //ajax
    _this._setCSRFToken();
    $.ajax({
        type: "GET",
        url: "/xxx/xxx/app/api/imgUploadTest.xsjs?name=" + oFileUploader.getValue(),
        processData: false,
        contentType: params.fileType,
        method: "POST",
        async: false,
        data: params.imgData
    }).done(function (data) {
        console.log(data);
    });
},
_setCSRFToken: function () {
    var thisController = this;
    jQuery.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (settings && settings.hasOwnProperty("type") && settings.type !== "GET") {
                var token = thisController._getCSRFToken();
                xhr.setRequestHeader("X-CSRF-Token", token);
            }
        },
        complete: function (xhr, textStatus) {
            var loginPage = xhr.getResponseHeader("x-sap-login-page");
            if (loginPage) {
                location.href = loginPage + "?x-sap-origin-location=" + encodeURIComponent(window.location.pathname);
            }
        }
    });
},

_getCSRFToken: function () {
    var token = null;
    jQuery.ajax({
        url: "/xxx/xxx/app/api/csrf.xsjs",
        type: "GET",
        async: false,
        beforeSend: function (xhr) {
            xhr.setRequestHeader("X-CSRF-Token", "Fetch");
        },
        complete: function (xhr) {
            token = xhr.getResponseHeader("X-CSRF-Token");
        }
    });
    return token;
}

xsjs(保存)

パラメータ取得

UIからajaxで送信されたパラメータを取得します。

var name = $.request.parameters.get("name");
var imgData = $.request.body.asString();

クエリ作成

// ■ db接続
var conn = $.db.getConnection();
conn.setAutoCommit(false);

// クエリの組み立て
var query = "INSERT INTO STORE.IMG_TEST (IMG_NAME, IMG_VALUE) VALUES ( ?, ? ) ";
var cntmt = conn.prepareStatement(query);
cntmt.setString(1, name);
cntmt.setString(2, imgData);
cntmt.execute();

テーブル確認

テーブルにデータが保存されていることを確認します。
スクリーンショット 2021-05-28 13.33.42.jpg

UI(データ呼び出し)

今度は,保存された画像データをUIから呼び出して画面に表示します。

プレビュー用意

View側

こちらもidを指定します。

<Image class="imagePreview" width="600px" id="imageReturn"></Image>

画像呼び出し

Controller側

今回,URLパラメータ(name)はテーブルに登録されているIMG_NAMEを固定値でパラメータに設定します。

pressGetButton: function () {
    var _this = this;
    _this._setCSRFToken();

    var dataArr = {
        "name": "任意の画像名"
    };
    $.ajax({
        type: "GET",
        url: "/xxx/xxx/app/api/imgGetTest.xsjs",
        dataType: "json",
        method: "POST",
        async: false,
        data: dataArr
    }).done(function (data) {
        _this.getView().byId("imageReturn").setSrc(data[0].IMG_VALUE);
    });
},
_setCSRFToken: function () {
    var thisController = this;
    jQuery.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (settings && settings.hasOwnProperty("type") && settings.type !== "GET") {
                var token = thisController._getCSRFToken();
                xhr.setRequestHeader("X-CSRF-Token", token);
            }
        },
        complete: function (xhr, textStatus) {
            var loginPage = xhr.getResponseHeader("x-sap-login-page");
            if (loginPage) {
                location.href = loginPage + "?x-sap-origin-location=" + encodeURIComponent(window.location.pathname);
            }
        }
    });
},

_getCSRFToken: function () {
    var token = null;
    jQuery.ajax({
        url: "/xxx/xxx/app/api/csrf.xsjs",
        type: "GET",
        async: false,
        beforeSend: function (xhr) {
            xhr.setRequestHeader("X-CSRF-Token", "Fetch");
        },
        complete: function (xhr) {
            token = xhr.getResponseHeader("X-CSRF-Token");
        }
    });
    return token;
}

レスポンスで取得したデータは指定したidに対してsetSrc()でパスとして設定します。

xsjs(描画)

パラメータ取得

UIからajaxで送信されたパラメータを取得します。

// ■ データ取得 
var name = $.request.parameters.get("name");

クエリ作成

// ■ db接続
var conn = $.db.getConnection();
conn.setAutoCommit(false);

// クエリの組み立て
var query = "SELECT IMG_NAME, IMG_VALUE FROM STORE.IMG_TEST WHERE IMG_NAME = ? ";
var cntmt = conn.prepareStatement(query);
cntmt.setString(1, name);
var rs = cntmt.executeQuery();
var retarr = [];
while (rs.next()) {
    var record = {
        "IMG_NAME": rs.getString(1),
        "IMG_VALUE": rs.getString(2)
    };
    retarr.push(record);
}

if (cntmt) {
    cntmt.close();
}

UIへのレスポンス

var output = JSON.stringify(retarr);
$.response.setBody(output);

UI確認

画像取得ボタン押下

スクリーンショット 2021-05-28 14.29.50.jpg

プレビュー表示

スクリーンショット 2021-05-28 14.30.02.jpg

おわりに

今回は画像ファイル登録のみの紹介になりますが,同様の方法で.csvや.xslxデータも扱えるかと思います。
ただ,データの上限や総データ量が増加した際の処理,挙動については確認できていないので,扱いには注意が必要です。

また,今回紹介させていただいた方法の他に,UI側からファイルの保存・使用方法として,
データ用にサーバを用意してファイル自体はそちらに保存し,DBにはファイルパスのみ登録する方法もあります。

データの扱いの面でメリットデメリットあるかと思いますので,特性を理解して適材適所で使い分けする必要がありそうですね。
また,ファイル保存について何か進展があればここに追記していきます。

参照資料

https://blogs.sap.com/2016/09/01/upload-and-retrieve-image-using-sap-hana-xs-sap-ui5/
https://blogs.sap.com/2017/03/14/how-to-post-an-image-from-sapui5-and-store-in-hana-db-as-blob-using-xsjs/
https://help.sap.com/viewer/cbed2190ee2d4486b0bbe0e75bf4b636/16.0.3.0/ja-JP/02b0331bcbaa414fb687dfccdbd64cbb.html
https://javascript.keicode.com/newjs/arraybuffer.php#1

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
0
Help us understand the problem. What are the problem?