何怡璇 熊棠 易修文
摘要:在Linux系统中,使用Ruby on Rails 5框架设计一个基于Web的数据导入工具。将Excel数据导入任意数据库中,并可定义导入策略。
关键词:数据导入;Ruby on Rails 5
中图分类号:TP311 文献标识码:A
文章编号:1009-3044(2020)17-0046-03
数据的批量导入是系统设计和使用中经常都会遇到的问题,特别是采用Excel工具收集和处理之后的数据,如何导入至业务系统数据库并能正确应用于系统,是系统设计人员必须考虑的。使用数据库管理工具进行数据导入对操作人員技能有较高要求,且存在数据安全风险。同时,部分数据还存在不同表之间的关联需求,使用数据库管理工具导入就需要对这样的数据进行预先处理,或者编写SQL语句实现。
这就提出一个需求,设计一个Web界面的数据导入工具,具有界面友好、可定制保存策略、可视化、支持关联表等功能,以满足一般用户的使用需求。
在Linux系统中,使用Ruby on Rails 5框架设计一个数据导入工具,使其具有上述功能特定。
1 系统环境
Ruby on Rails 5框架本身支持Windows、Linux、MacOS等系统环境,且使用对象关系映射(ORM)技术实现了数据库类型不可知[1],在代码编写时注意避免直接使用SQL语句,就能实现一套系统在不同数据库之间的自由转换[2]。测试环境为Ubuntu16.04操作系统,Rails 5.2.3,MySQL 5.7数据库。
2 过程分析
2.1 策略列表
用户应可看到之前已保存的策略列表,可选择根据已有策略导入或者新建策略。
2.2 上传文件
不论用户使用哪种方式,均需上传源数据文件。客户端、服务器端应对文件类型进行过滤,仅接受可识别的文件,如xlsx、csv等。
2.3 读取数据
文件上传之后,应读取出文件中的数据,并显示。如果文件有多个工作表,应显示出来,并支持人工选择。
2.4 定义策略
如使用已有策略,应将策略展示在页面上并支持修改;如为新建策略,应支持可视化定义策略并支持自动匹配。新建策略及修改策略应保持UI的一致性。
2.5 保存策略并导入数据
新建策略应可选择是否保存,使用已有策略且发生策略更改时,应更新并持久化。不论策略是否保存,均应按当前策略导入数据并持久化。
3 模型设计
策略需要持久化保存,创建Rule类用来保存策略。
3.1 Rule类的属性
Rule类用来存储策略并可再次使用。至少应包含两个字段。
3.1.1 title字段
title字段用于识别策略,便于再次使用。
3.1.2 pattern字段
pattern字段用于存储策略文本。策略为JSON格式的文本数据,利于在前端、应用层中保持一致性,且便于存储。
3.2 pattern格式
pattern是整个工具的核心,用来定义如何导入数据。
3.2.1 src
src键值对用来定义数据源,即上传文件中的第几个工作表,从0开始。
3.2.2 dest
dest键值对用来定义数据目的,即系统中对应的ActiveRecord对象。
3.2.3 f_r
部分文件第一行为表头。第一行是表头还是数据应交由用户判断,f_r键值对用来定义第一行是否为表头。
3.2.4 map
map键值对用来定义源数据中的字段与ActiveRecord对象各属性的映射关系。因存在多个字段,其值为一个数组。数组的每个元素均为多个键值对组成的JSON格式对象。
3.2.4.1 col
col键值对用来定义该位置字段对应的ActiveRecord对象属性名。
3.2.4.2 type
type键值对用来定义该位置字段对应的ActiveRecord对象属性的字段类型。不同的字段类型在导入时会做特定的处理。
3.2.4.3 not_unique
not_unique键值对用来定义该位置字段对应的值在数据库中是否要求唯一性。
3.2.4.4 to_rel
to_rel键值对用来定义该位置字段对应的值是否存在表关联。如此值为false,则以下几个键值对可以不做定义。
3.2.4.5 rel_table
rel_table键值对用来定义该位置字段关联表的ActiveRecord对象名。
3.2.4.6 rel_col
rel_col键值对用来定义该位置字段关联的ActiveRecord对象的对应属性。
3.2.4.7 rel_col_type
rel_col_type键值对用来定义该位置字段关联的ActiveRecord对象的对应属性的字段类型。不同的字段类型在导入时会做特定的处理。
3.2.4.8 rel_c_rol
rel_c_rol键值对用来定义建立表关联时返回的字段。
3.2.4.9 rel_c_rol_type
rel_c_rol_type键值对用来定义返回对应字段的字段类型。不同的字段类型在导入时会做特定的处理。
3.2.4.10 rel_not_unique
rel_not_unique键值对用来定义该位置字段关联的ActiveRecord对象的对应属性值在数据库中是否要求唯一性。
4 控制与视图
文件上传之后,控制器调用组件读取文件内容。
4.1 读取源数据
使用开源Gem Roo执行所有常见的电子表格类型的读访问权限,包括Excel、LibreOffice、OpenOffice、CSV、Google spreadsheets等格式[3]。
对于Excel 2013文件,使用Roo::Excelx.new((服务器端文件路径))可以读出文件中的数据内容赋值给实例@data_src,并可按工作表进行访问。@data_src.sheets以数组形式输出各工作表名; @data_src.sheet(i).parse()可将第i个工作表以数组形式输出,如该表没有数据,则输出nil。
4.2 编写策略
为了便于对策略进行可视化编写,首先需要把读取的源数据按工作表以Table样式输出在页面上。如果数据量较大,可部分输出。
通过ApplicationRecord类的descendants方法可以获得系统已有的ActiveRecord对象及属性列表。
通过以上准备工作即可建立控制面板,用于编写策略。
4.2.1 数据源及目的表
采用下拉菜单的方式选择源数据及目的表。源数据即文件中的第几个工作表,目的表即数据要以哪个ActiveRecord对象导入数据库。同时要有首行导入选项。
4.2.2 字段映射
当数据源、目的表选定之后,根据数据源数组的列数生成对应选项下拉菜单。当“第一行包含标题”复选框未选中时,按Excel习惯,按字母标识列;当前述复选框被选中时,应根据名称进行自动对应。默认状态下字段导入是允许重复的。
4.2.3 关联表
当对应字段的“关联表”选项被选中时,将出现更多选项。目标表即被关联的表,目标域即数据将要被导入的域。默认状态下字段导入是不允许重复的,返回的值为id;通过打开更多选项,能对上述两个设定进行修改。当选择返回域时,应根据原目标表目标域的类型进行限制,防止因用户操作失误造成数据类型不匹配。
4.2.4 数据类型
数据类型是根据ActiveRecord对象读取,不能被人为控制。
4.2.5 生成策略并提交
页面上有一个隐藏的表单元素pattern_text,值为pattern的JSON格式文本。
为了统一新建与编辑策略时的脚本,应在页面载入时使用JSON.parse方法将pattern_text的值序列化为JSON实例pattern;若pattern_text的值为空或不是JSON格式文本,将其赋值为“{}”后再执行前述操作。生成前述选项时,如果pattern相应的值为null或undefined,则按默认值生成;否则读入该值,并按值设置。
完成设置后,点击“导入”按钮,再次运行策略生成脚本,根据各控件的值对pattern相应的键值对赋值;然后使用JSON.stringify方法将pattern转化为字符串并赋值给pattern_text,然后提交后台保存。为了便于日后再次调用,此处应设置保存选项。
4.3 数据持久化
策略文本提交到后台,如要保存为模板,则按Rule类保存。
策略在被使用前,需要再次序列化为JSON对象。JSON的統一规则使前/后端保持了很好的统一性。
依然使用Roo得到的数组,并根据pattern[“src”]的值获得需要导入的数据数组@src。对@src进行遍历,每一个元素存为一条数据库中的记录。遍历时根据pattern[“f_r”]的值决定是否导入@src[0]。
4.3.1 构造参数散列式
构造一个空散列式_params = {}用来记录参数。
4.3.2 字段映射
遍历@src[i]的每一个元素,如@src[i][j],按以下步骤进行导入操作。
4.3.2.1 是否关联
读取pattern[“map”][j][“to_rel”],如非,则直接导入,否则按关联导入并返回值导入。
4.3.2.2 关联导入
根据pattern[“map”][j][“rel_table”]、pattern[“map”][j][“rel_col”]确定ActiveRecord对象及字段,如pattern[“map”][j][“rel_not_unique”]为否,则按字段、值搜索,如有结果,则返回对象实例@rel;否则按pattern[“map”][j][“rel_table”]新建ActiveRecord对象实例@rel,并赋值保存。最后返回 @rel.attributes[pattern[“map”][j][“rel_c_rol”]]的值_value。
4.3.2.3 字段赋值
不管是直接导入还是关联,都牵涉到字段赋值。目标字段根据pattern[“map”][j][“col”]、pattern[“map”][j][“rel_col”]确定,值需要根据pattern[“map”][j][“type”]、pattern[“map”][j][“rel_col_ type”]进行预先处理。如转换成字符串型、浮点型、日期型等。如为关联导入按前述执行得到值_value,否则将处理之后的值赋为_value。
4.3.2.4 更新参数散列式
使用merge方法将{ pattern[“map”][j][“col”].to_sym => _vlue}合并入_params,至此则完成了一个字段的处理。
4.3.3 构造对象实例并保存
根据pattern[“dest”]获取ActiveRecord对象,使用create方法和_params参数执行存储。至此一条完成的记录按策略完成了导入。
4.4 根据策略模板导入
前述策略如果保存为模板,可以再次使用,上传文件后读取模板中的策略,并按策略设置控制面板。系统应可检查提交后的模板策略是否应被更新并安最新策略执行导入。
5 结束语
该工具能够实现可视化定制、保存策略,并支持表关联,达到了设计要求。但还存在只能单字段关联,不支持多个字段确定表关联的问题,将在后续进行改进。
参考文献:
[1] Active Record 基础[EB/OL].[2019-12-20].https://ruby-china.github.io/rails-guides/active_record_basics.html.
[2] 对象关系映射-维基中文镜像,自由的百科全书[EB/OL]. [2019-12-20].https://zh.wikipedia.com/wiki/对象关系映射.
[3] Documentation for roo (2.8.3) [EB/OL]. [2019-12-20].https://www.rubydoc.info/gems/roo/2.8.3.
【通联编辑:谢媛媛】