5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-05-31

#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 データ型にマッピングされます。

#####【参考資料】
https://help.sap.com/viewer/cbed2190ee2d4486b0bbe0e75bf4b636/16.0.3.0/ja-JP/02b0331bcbaa414fb687dfccdbd64cbb.html

##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

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?