附件字段持久化的实现过程详解原创
金蝶云社区-聚宝彭
聚宝彭
20人赞赏了该文章 3,811次浏览 未经作者许可,禁止转载编辑于2021年11月24日 16:53:07
summary-icon摘要由AI智能服务提供

本文详细阐述了金蝶云·苍穹平台内附件字段持久化的实现过程,包括文件上传至Redis缓存、保存附件信息至数据库、最终文件持久化到附件服务器及业务单据数据保存的全过程。分析了多个请求处理及后台服务方法调用,强调了涉及的数据存储和关键工具类。提供了注意事项和参考资料链接。


本文给各位看官详细讲解一下金蝶云·苍穹平台内附件字段持久化的实现过程,希望能给各位在开发过程中提供一点点帮助。


设计器界面

单据设计器界面.png


实现过程详解

1. 在前端页面上的附件字段上传文件之后,浏览器F12前端发送了三个请求:

http://localhost:8080/ierp/form/batchInvokeAction.do?appId=kdec_testapp&f=kdec_demobill&ac=beforeUpload

http://localhost:8080/ierp/attachment/uploadFile.do

http://localhost:8080/ierp/form/batchInvokeAction.do?appId=kdec_testapp&f=kdec_demobill&ac=updateValue

文件上传请求.png


首先,在第一个请求中,可以完成上传文件前的业务处理逻辑。这里我们没做任务处理,直接略过该请求。


然后,第二个请求实现了把附件暂存到redis缓存中。根据平台底层框架分析可知,后台针对该请求在 kd.bos.web.actions.AttachmentAction.uploadFile(HttpServletRequest, HttpServletResponse) 中进行响应。反编译源码之后分析可知,该方法中通过 kd.bos.cache.tempfile.RedisTempFileCache.saveAsUrl(String, InputStream, int) 把文件流暂存到redis中,并返回临时缓存地址(含附件服务器访问链接在内的绝对路径)。

1.AttachmentAction-uploadFile.png


在文件临时缓存成功之后,第三个请求实现了保存附件相关信息,即向表 t_bd_attachment (页面标识:bd_attachment)中插件一条数据记录。后台针对该请求在 kd.bos.web.actions.FormAction.batchInvokeAction(HttpServletRequest, HttpServletResponse)中进行响应,

FormAction-batchInvokeAction.png


反编译源码分析可知,后台先将请求转发至 kd.bos.mservice.form.FormService.batchInvokeAction(String, String) 。

FormServiceImpl-batchInvokeAction.png

1.FormServiceImpl-invokeAction.png


然后转发至 kd.bos.mvc.form.FormController.postData(List<Map<String, Object>>) 。

1.FormController-postData.png

1.FormController-postFieldState.png


最后再转发至附件字段控件编程模型的方法 kd.bos.form.field.AttachmentEdit.postBack(Object, int, int) 。其中,平台通过附件字段模型的方法 kd.bos.mvc.attachment.AttachmentFieldModel.saveAttachments(IDataModel, String, String, List<Map<String, Object>>) 来记录附件信息。

1.AttachmentEdit-postBack.png

1.AttachmentEdit-saveTempAttachments.png

1.AttachmentFieldModel-saveAttachments.png

各位看官请注意:在该方法中,平台底层是通过工具类 kd.bos.servicehelper.attachment.AttachmentFieldServiceHelper 中的 saveAttachments(String, String, List<Map<String, Object>>) 来实现该功能。

1.AttachmentFieldServiceHelper-saveAttachments.png


2. 在用户维护完前端界面数据之后点击“保存/提交”,此时在浏览器可看到只有一次请求:http://localhost:8080/ierp/form/batchInvokeAction.do?appId=kdec_testapp&f=kdec_demobill&ac=save

保存请求.png

通过分析可知,后台还是在 kd.bos.web.actions.FormAction.batchInvokeAction(HttpServletRequest, HttpServletResponse) 中进行响应。

FormAction-batchInvokeAction.png

2.FormServiceImpl.invokeAction.png

2.FormServiceImpl.invokeMethod.png


然后依次将请求转发至 kd.bos.form.control.Toolbar.itemClick(String, String) 

2.ToolBar.itemClick.png


→ kd.bos.mvc.form.FormView.invokeOperation(String, OperateOption)

2.FormView.invokeOperation.png

2.FormView.invokeOperation-2.png


→ kd.bos.form.operate.FormOperate.execute()

2.FormOperate.execute.png


→ kd.bos.form.operate.EntityOperate.invokeOperation()

2.EntityOperate.invokeOperation.png


→ kd.bos.entity.operate.DefaultEntityOperate.callEntityOperate()

2.DefaultEntityOperate.callEntityOperate.png

2.DefaultEntityOperate.invokeBillOperation.png


→ kd.bos.entity.operate.Save.callBillOperationService()

2.Save.callBillOperationService.png


→ kd.bos.service.operation.OperationServiceImpl.localInvokeOperation(String, DynamicObject[], OperateOption)

2.OperationServiceImpl.localInvokeOperation.png


→ kd.bos.service.operation.EntityOperateService.excute(DynamicObject[])

2.EntityOperateService.excute.png

2.EntityOperateService.doExcete.png


→ kd.bos.service.operation.Save.callOperationTransaction(DynamicObject[])

2.Save.callOperationTransaction.png


→ kd.bos.service.operation.EntityOperateService.persistAttachments(DynamicObject[])

2.EntityOperateService.persistAttachments.png


在这里,我们可以看到平台底层通过 kd.bos.service.attachment.IAttachmentOperateService.persistAttachments(OperateOption, DynamicObject[]) 来实现附件面板 & 附件字段的持久化。在该方法中,通过调用接口 kd.bos.servicehelper.attachment.AttachmentFieldServiceHelper.saveTempAttachments(String) 来实现文件持久化到附件服务器,并更新附件信息(bd_attachment)。

2.AttachmentOperateServiceImpl.persistAttachments.png

2.AttachmentFieldServiceHelper-saveTempAttachments.png

2.AttachmentFieldServiceHelper-saveTempToFileService.png

备注

在 AttachmentFieldServiceHelper.saveTempAttachments(String) 方法中,先查询附件(bd_attachment)信息,然后根据查询到的附件信息调用接口 kd.bos.servicehelper.attachment.AttachmentFieldServiceHelper.saveTempToFileService(String, Object, String) 将 redis缓存中的文件流持久化到附件服务器上,并返回附件在服务器上的存储地址。最后,通过接口 kd.bos.servicehelper.operation.SaveServiceHelper.save(DynamicObject[])  更新附件信息(bd_attachment)。


附件持久化成功之后,最后一步就是保存单据数据。在 kd.bos.service.operation.Save.callOperationTransaction(DynamicObject[]) 接口中继续将请求转发至 kd.bos.service.operation.Draft.executeOperate(DynamicObject[]) 。

2.Save.callOperationTransaction-2.png

2.Draft.callOperationTransaction.png

2.EntityOperate.callOperationTransaction.png

2.EntityOperateService.callOperation.png

2.Draft.executeOperate.png

在这个方法中,通过 kd.bos.servicehelper.operation.SaveServiceHelper.save(DynamicObject[]) 实现了单据业务数据的保存。


至此,在前端界面的附件字段上传文件后,点击“保存/提交”将附件和业务单据数据持久化的过程就全部结束了。通过以上分析,我们可知,整个过程涉及 4 个部分数据的存储:附件文件持久化到附件服务器上、向表 t_bd_attachment 中插入一条附件信息数据、保存业务单据数据、向中间表(即:附件字段上配置的表名)插入一条数据记录业务单据和附件信息的关联信息


功能实现主要过程

附件字段实现逻辑-20111112修正.jpg


注意事项

1. 附件字段支持在单据体列中使用。

2. 附件字段的控件编程模型:kd.bos.form.field.AttachmentEdit,派生自多选基础资料控件编程模型MulBasedataEdit。

3. 附件字段操作工具类:kd.bos.servicehelper.attachment.AttachmentFieldServiceHelper。


参考资料

https://club.kdcloud.com/article/182623 

https://vip.kingdee.com/article/198561339718310912 

https://vip.kingdee.com/knowledge/specialDetail/218022218066869248?category=218035423933468928&id=221558278130386688 





赞 20