#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);
}
}
###画面イメージ
#####参照ボタン押下
#####アップロードする画像を選択
###送信ボタン押下時処理
contentType
にファイルのデータタイプを設定し,processData
はfalse
にしています。
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();
###テーブル確認
テーブルにデータが保存されていることを確認します。
##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);
##おわりに
今回は画像ファイル登録のみの紹介になりますが,同様の方法で.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