移动附件_上传篇
一、概述:
为清楚讲解移动附件的相关功能,这里将分为:控件介绍篇、上传篇、V7.5下载篇、V7.5删除篇、V7.5控制篇等5个篇幅。
本篇将详细介绍如下内容:
1. 如何触发附件上传
2. 如何在插件中完成附件数据库或文件服务器的存储
3. 附件数据如何关联单据头、单据体
二、适用版本:
适用于V 6.X及以上
三、移动附件上传的开发介绍:
上传过程:选择附件=>上传到临时目录-》插件AfterMobileUpload 事件,关联单据,并上传正式的存储位置(数据库 OR 文件服务器)
本篇为了方便拿到单据数据,将在【出差申请】中演示附件上传功能,实际运用以具体情况来定。
3.1. 实施部分
3.1.1. 登录BOS IDE-》打开子系统-》新建移动单据
3.1.2. 设置来源单据【出差申请】
3.1.3. 根据情况在单据详情中拖入对应字段,重点是拖入本篇的主角”附件”控件(标识:F_PAEZ_FileUpdate),用来上传附件
3.1.4. 拖入底部菜单-》保存(标识:saveItem),用来保存附件及单据数据。
3.1.5. (可选)单据列表中拖入相应字段,移动列表如果需要新建单据,可在列表中增加一个新增按钮。
至此,实施的部分已完成
3.2 介绍通过插件实现上传的业务逻辑
涉及到的知识点包括:
3.2.1. 点击单据详情中的【保存】按钮时同时触发附件上传,将附件上传至临时目录
//触发附件上传
this.View.GetControl<FileUploadControl>("F_PAEZ_FileUpdate").UploadFieldBatch();
3.2.2. 上传到临时目录完成后,会触发表单插件AfterMobileUpload回调函数,并可以通过参数e.FileNameArray获取到附件名称列表,我们就可以在这个回调函数中将临时目录中的附件上传至数据库或文件服务器
/// <summary>
/// 附件上传到临时目录后的插件回调函数
/// </summary>
/// <param name="e"></param>
public override void AfterMobileUpload(MobileUploadEventArgs e)
{
foreach (FiledUploadEntity file in e.FileNameArray)
{
// TODO:将附件上传至数据库或文件服务器
}
}
3.2.3. 获取临时目录
// 文件存放的临时目录
var tempDirPath = HttpContext.Current.Request.PhysicalApplicationPath + KeyConst.TEMPFILEPATH;
3.2.4. 附件有多种存储方式,例如数据库、文件服务器、各种云服务器等,这个可以从FileStorage这个字段来进行识别
FileStorage 文件存储类型,0为数据库,1为文件服务,2为亚马逊云,3为金蝶云
3.2.5. 如果是上传到文件服务器,还需要判断是否启用了文件服务器
//检查是否启用了文件服务器
if (!Kingdee.BOS.ServiceHelper.FileServer.FileServerHelper.UsedFileServer(this.Context))
{
this.View.ShowMessage("未启用文件服务器,无法实现上传。");
return;
}
3.2.6. 判断当前附件的存储方式
// 获取当前服务器的数据存储类型
Var fileStorgae = Kingdee.BOS.ServiceHelper.FileServer.FileServerHelper.GetFileStorgaeType(this.Context);
if (fileStorgae != 0)
{
// 将数据上传至文件服务器,并返回上传结果
}
else{
// 数据库的方式是直接保存附件数据
}
3.2.7. 文件服务器上传的方式。目前采用分段上传,每次只上传一个文件片段,通过FileId来标识多个片段属于同一个文件。最后一个片段需要将Last属性置为true
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(buff))
{
TFileInfo tFile = new TFileInfo()
{
FileId = fileId,
FileName = fileName,
CTX = this.Context,
Last = len >= dataBuff.Length,//标记是否为文件的最后一个片段
Stream = ms
};
var result = service.UploadAttachment(tFile);
// 注意点:上传时fileId传入null为新文件开始,会返回一个文件的fileId,后续采用这个fileId标识均为同一文件的不同片段。
fileId = result.FileId;
if (!result.Success)
{
return result;
}
}
3.2.8. 附件与单据关联。附件的属性数据(如文件名、大小等)是保存在数据库中的,并且会关联FormId、InterId、EntryInterID 、EntryKey来识别这个附件是与那张单据、单据体or基础资料关联。
dyn["BillType"] = formId; //关联单据的formid
dyn["InterID"] = interId; //关联单据的主键ID
dyn["EntryKey"] = entryKey; //单据体标识,如果是关联单据头则为“ ”
dyn["EntryInterID"] = entryInterId; //单据体主键ID,如果是单据头则为 -1;
3.3. 完整代码,供大家参考:
using System;
using System.Linq;
using System.Collections.Generic;
using Kingdee.BOS.Mobile.Metadata.ControlDataEntity;
using Kingdee.BOS.Util;
using Kingdee.BOS.Mobile.PlugIn.Args;
using Kingdee.BOS.Mobile.PlugIn.ControlModel;
using System.Web;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.ServiceHelper;
using Kingdee.BOS.Core;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.FileServer.Core;
using Kingdee.BOS.FileServer.ProxyService;
using Kingdee.BOS.FileServer.Core.Object;
using Kingdee.BOS.Mobile.Metadata;
using Kingdee.BOS.Orm;
using Kingdee.BOS.Core.DynamicForm;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Mobile.PlugIn;
namespace BOS.Debug.MobilePlugIn
{
//
/// <summary>
/// 移动表单继承:AbstractMobilePlugin, 移动单据继承:AbstractMobileBillPlugin
/// </summary>
[System.ComponentModel.Description("移动单据表单插件--附件相关功能DEMO")]
public class MobileBillPlugIn_AttachDemo : AbstractMobileBillPlugin
{
public override void ButtonClick(ButtonClickEventArgs e)
{
if (e.Key == "saveItem")
{
this.View.GetControl<FileUploadControl>("F_PAEZ_FileUpdate").UploadFieldBatch();
}
}
/// <summary>
/// 附件上传到临时目录的回调事件
/// </summary>
/// <param name="e"></param>
public override void AfterMobileUpload(MobileUploadEventArgs e)
{
var billNo = Convert.ToString(this.View.BillModel.GetValue(this.View.BillBusinessInfo.GetBillNoField()));//单据编号
var formId = this.View.GetFormId(); //关联单据的formid
var interId = this.View.BillModel.GetPKValue();//关联单据的主键ID
var entryKey = " ";//关联的单据体标识,如果是关联单据头则为“ ”
var entryInterId = -1; //关联的单据体主键ID,如果是单据头则为 -1;
if (interId.IsNullOrEmptyOrWhiteSpace()){
return;
}
// 文件存放的临时目录
var tempDirPath = HttpContext.Current.Request.PhysicalApplicationPath + KeyConst.TEMPFILEPATH;
// 获取附件表的元数据类
var formMetadata = (FormMetadata)MetaDataServiceHelper.Load(this.Context, Kingdee.BOS.Core.FormIdConst.BOS_Attachment);
var dynObjType = formMetadata.BusinessInfo.GetDynamicObjectType();
// 获取当前服务器的数据存储类型
var fileStorgae = Kingdee.BOS.ServiceHelper.FileServer.FileServerHelper.GetFileStorgaeType(this.Context);
var dynList = new List<DynamicObject>();
string failedFiles = "";
#region 上传新附件
for (var i = 0; i < e.FileNameArray.Count; i++)
{
var item = e.FileNameArray[i];
var fileName = System.IO.Path.Combine(tempDirPath, item.FileName);
//在版本PT139774 [7.3.1351.3]及以上,增加了FileId,并且新上传的附件临时ID是一个小数,可以以此来判断是否新上传附件
if (item.FileId.IndexOf("0.") < 0){
continue;
}
// 检查文件是否成功上传到临时目录
if (!item.IsSuccess)
{
failedFiles += item.OldName + ",";
continue;
}
// 检查文件是否存在于临时目录
if (!System.IO.File.Exists(fileName))
{
failedFiles += item.OldName + ",";
continue;
}
/**
* 此处几个关键属性解读:
* 1. AttachmentSize 系统统一按照KB单位进行显示,所以需要除以1024
* 2. EntryInterID 关联的单据体ID,如果是附件关联单据头则为 -1;
* 3.EntryKey 关联的单据体标识,如果是附件关联单据头则为 " "
* 4. BillType 关联的模型的FormId
* 5. BillNo 关联的单据编号,用于确定此附件是属于哪张单据
* 6. InterID 关联的单据/基础资料ID,附件列表就是根据这个ID进行加载
* 7. FileStorage 文件存储类型,0为数据库,1为文件服务,2为亚马逊云,3为金蝶云;
*/
var dataBuff = System.IO.File.ReadAllBytes(fileName);
var dyn = new DynamicObject(dynObjType);
if (fileStorgae != 0)
{
// 将数据上传至文件服务器,并返回上传结果
var result = this.UploadAttachment(item.FileName, dataBuff);
if (!result.Success)
{
// 上传失败
failedFiles += item.OldName + ",";
continue;
}
// 通过这个FileId就可以从文件服务器下载到对应的附件
dyn["FileId"] = result.FileId;
}
else
{
// 数据库的方式是直接保存附件数据
dyn["Attachment"] = dataBuff;
}
dyn["BillType"] = formId; //关联单据的formid
dyn["BillNo"] = billNo;//单据编号
dyn["InterID"] = interId;//关联单据的主键ID
dyn["EntryKey"] = entryKey;//单据体标识,如果是关联单据头则为“ ”
dyn["EntryInterID"] = entryInterId; //单据体主键ID,如果是单据头则为 -1;
dyn["AttachmentName"] = item.OldName;
dyn["AttachmentSize"] = Math.Round(dataBuff.Length / 1024.0, 2);
dyn["CreateMen_Id"] = Convert.ToInt32(this.Context.UserId);
dyn["CreateMen"] = GetUser(this.Context.UserId.ToString());
dyn["CreateTime"] = TimeServiceHelper.GetSystemDateTime(this.Context);
dyn["ExtName"] = System.IO.Path.GetExtension(item.OldName);
dyn["FileStorage"] = fileStorgae.ToString();
dyn["IsAllowDownLoad"] = 0;//参考PC端,历史原因 0 允许下载,1 不允许下载
dynList.Add(dyn);
}
if (!dynList.IsEmpty())
{
// 所有数据加载完成后再一次性保存全部
BusinessDataServiceHelper.Save(this.Context, dynList.ToArray());
}
#endregion
if (failedFiles == ""){
//附件保存成功
}
else{
failedFiles = failedFiles.TrimEnd(',');
string message = string.Format("附件保存失败,请重新保存! 失败文件:{0}", failedFiles);
this.View.ShowMessage(message);
}
}
/// <summary>
/// 上传附件方法
/// </summary>
/// <param name="fileName"></param>
/// <param name="dataBuff"></param>
/// <returns></returns>
private FileUploadResult UploadAttachment(string fileName, byte[] dataBuff)
{
// 初始化上传下载服务,这个Service会根据Cloud配置自动上传到对应的文件服务器
var service = new UpDownloadService();
int len = 0, less = 0;
string fileId = null;
byte[] buff = null;
while (len < dataBuff.Length)
{
// 文件服务器采用分段上传,每次上传4096字节, 最后一次如果不够则上传剩余长度
less = (dataBuff.Length - len) >= 4096 ? 4096 : (dataBuff.Length - len);
buff = new byte[less];
Array.Copy(dataBuff, len, buff, 0, less);
len += less;
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(buff))
{
TFileInfo tFile = new TFileInfo()
{
FileId = fileId,
FileName = fileName,
CTX = this.Context,
Last = len >= dataBuff.Length,//标记是否为文件的最后一个片段
Stream = ms
};
var result = service.UploadAttachment(tFile);
// 注意点:上传时fileId传入null为新文件开始,会返回一个文件的fileId,后续采用这个fileId标识均为同一文件的不同片段。
fileId = result.FileId;
if (!result.Success)
{
return result;
}
}
}
return new FileUploadResult()
{
Success = true,
FileId = fileId
};
}
/// <summary>
/// 获取用户
/// </summary>
/// <param name="userID"></param>
/// <returns></returns>
private DynamicObject GetUser(string userID)
{
OQLFilter filter = OQLFilter.CreateHeadEntityFilter(string.Format("FUSERID={0}", userID));
return BusinessDataServiceHelper.Load(this.View.Context, Kingdee.BOS.Core.FormIdConst.SEC_User, null, filter).FirstOrDefault();
}
}
}
3.3. 最后在BOSIDE中将插件挂载上去
到这里,上传附件的功能就完成了。
移动附件_上传篇
本文2024-09-23 04:15:49发表“云星空知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-k3cloud-164182.html