文章目录
前言
这系列文章详细记录在Fiori应用中如何在前端和后端之间使用文件进行交互。
这篇的主要内容有:
- 后端RAP的开发(S4HANA On-Premise)
- 新建Action(保存base64)
- 前端(UI5)读取文件并保存到后端
- 传输文件流,并保存在ABAP数据库表
- 在前端下载已保存的文件
- 在前端显示已保存的图片
一、开发Action
1. 修改Table
- 新增3个字段 attachment ,filename,filetype
- 对应的CDS也添加三个字段
define table ymoon_t010 {
key client : abap.clnt not null;
key uuid : sysuuid_x16 not null;
name : abap.char(40);
age : abap.int1;
gender : abap.char(10);
city : abap.char(40);
attachment : abap.string(0);
filename : abap.char(100);
filetype : abap.char(100);
}
2. BDEF中新增Action
managed implementation in class zbp_moon_i_010 unique;
strict ( 2 );
define behavior for ymoon_i_010 alias Student
persistent table YMOON_T010
early numbering
lock master
authorization master ( instance )
//etag master <field_name>
{
create;
update;
delete;
//Add Action
static action upload_file parameter ymoon_s010;
//新增Action
static action upload_attachment parameter ymoon_s011;
}
3. 新建结构,用于接收uuid以及附件数据
@EndUserText.label : 'uuid & Attachment'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
define structure ymoon_s011 {
uuid : sysuuid_x16;
attachment : abap.string(0);
filename : abap.string(0);
}
4. 实现Method逻辑
这里把base64保存到string类型中
method upload_attachment.
"获取UI5传送的parameter
data(uuid) = keys[ 1 ]-%param-uuid.
data(attachment) = keys[ 1 ]-%param-attachment.
data(filename_full) = keys[ 1 ]-%param-filename.
"
split filename_full at `.` into data(lv_filename) data(lv_filetype).
"更新
update ymoon_t010
set filename = lv_filename
filetype = lv_filetype
attachment = attachment
where uuid = uuid.
endmethod.
二、UI5项目修改
1. 添加表格行
- 新增附件和文件名列, 并使用FileUploader和Link组成cell
<columns>
<Column>
<Text text="姓名" />
</Column>
<Column>
<Text text="年龄" />
</Column>
<Column>
<Text text="性别" />
</Column>
<Column>
<Text text="城市" />
</Column>
<Column>
<Text text="选择附件" />
</Column>
<Column>
<Text text="文件名" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Text text="{Name}" />
<Text text="{Age}" />
<Text text="{Gender}" />
<Text text="{City}" />
<u:FileUploader
id="Attachment"
name="Attachment"
tooltip="Upload your Attachment to the server"
buttonText="上传附件"
change="onUploadAttachment"
/>
<Link text="{= ${Filename} !== '' ? ${Filename} + '.' + ${Filetype} : ''}" />
</cells>
</ColumnListItem>
</items>
2. 事件处理函数
- 上传文件时,获取当前行的uuid并调用Action传输到后端
onUploadAttachment: function (e) {
// console.log(e)
var oModel = this.getView().getModel();
var file = e.getParameter("files")[0]
var filename = e.getSource().getProperty('value')
var uuid = e.getSource().getBindingContext().getProperty().Uuid
var reader = new FileReader();
reader.onload = function (evt) {
// 获取文件流
var vContent = evt.currentTarget.result;
oModel.callFunction("/upload_attachment",
{
method: "POST",
urlParameters: { //参数,首字母大写
"Uuid": uuid,
"Attachment": vContent,
"Filename": filename
},
success: function (odata, response) {
//Model Refresh
MessageBox.information("附件上传成功! " + filename);
oModel.refresh(true);
},
error: function (res) {
console.log(res)
}
})
}
reader.readAsDataURL(file);
}
3. 点击文件名时的事件
- 点击文件时,会下载对应的文件。 如果是图片类型,则直接显示在浏览器Dialog上
这里值得一提的是Image控件可以直接显示BASE64值的图片,不需要传入图片路径也可
onClickFilename: function (e) {
var oData = e.getSource().getBindingContext().getProperty()
var validFileTypes = ['gif', 'jpg', 'png', 'jpeg'];
var vContent = oData.Attachment
if (validFileTypes.includes(oData.Filetype)) {
// 创建图片控件
this.oImage = new Image({
src: oData.Attachment,
width: "100%"
});
// 创建对话框
this.oDialog = new Dialog({
title: "Image Dialog",
content: this.oImage,
beginButton: new Button({
text: "Close",
press: function () {
this.oDialog.close();
}.bind(this)
})
});
// 打开对话框
this.oDialog.open();
} else {
var sContent = vContent.split(";")
var Mimetype = sContent[0].split(":")
var Docum = sContent[1].split(",")
//下载需要把base64转为blob
var blob = this.base64toBlob(Docum[1], Mimetype[1]);
File.save(blob, oData.Filename, oData.Filetype, Mimetype[1]);
}
},
base64toBlob(base64Data, contentType) {
contentType = contentType || '';
var sliceSize = 512;
var byteCharacters = atob(base64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, { type: contentType });
return blob;
}