场景描述:
前端是可动态编辑的json schema 数据,编辑成功保存后,传递给服务端是一串json
数据格式类如下
{
"type": "object",
"labelWidth": 120,
"displayType": "row",
"properties": {
"test": {
"api": "gitlab_name",
"enum": [
"a",
"b",
"c"
],
"type": "string",
"props": {
"showSearch": true,
"filterOption": true,
"optionFilterProp": "label"
},
"title": "git仓库名",
"widget": "select",
"disabled": false,
"readOnly": false,
"required": false,
"enumNames": [
"早",
"中",
"晚"
]
},
"select_n6IurM": {
"api": "gitlab_addr",
"enum": [
"a",
"b",
"c"
],
"type": "string",
"props": {
"showSearch": true,
"filterOption": true,
"optionFilterProp": "label"
},
"title": "git地址",
"widget": "select",
"disabled": false,
"readOnly": false,
"required": false,
"enumNames": [
"早",
"中",
"晚"
]
},
"execution_host": {
"api": "hostname",
"enum": [
"A",
"B",
"C",
"D"
],
"type": "array",
"items": {
"type": "string"
},
"props": {
"showSearch": true,
"filterOption": true,
"optionFilterProp": "label"
},
"title": "目标机器",
"hidden": false,
"widget": "multiSelect",
"disabled": false,
"readOnly": false,
"required": false,
"enumNames": [
"杭州",
"武汉",
"湖州",
"贵阳"
],
"description": "下拉多选"
}
}
}
后端需要存储该字段数据,故使用了json.RawMessage,mysql中字段类型设置为json
model结构体:
type TempInfo struct {
ID int `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"`
CreatedAt time.Time `gorm:"column:create_time" json:"create_time" form:"create_time"`
UpdatedAt time.Time `gorm:"column:update_time" json:"update_time" form:"update_time"`
TempName string `gorm:"column:temp_name; type: varchar(128)" json:"temp_name" form:"temp_name" binding:"required"` // 模板名称
FormStructure datatypes.JSON `gorm:"column:form_structure; type: json" json:"form_structure" form:"form_structure" binding:"required"` // 表单结构
Creator string `gorm:"column:creator; type: varchar(128)" json:"creator" form:"creator"` // 创建者
Updater string `gorm:"column:updater; type:varchar(128)" json:"updater" form:"updater"` // 修改者
Remarks string `gorm:"column:remarks; type: longtext" json:"remarks" form:"remarks"` // 备注
}
可以看到使用了datatypes.json 其实和json.RawMesage是一个道理,只不过使用datatypes的好处在于,数据在使用时无需序列化与反序列化,不然直接使用json.RawMessage存储到数据库里面是bytes格式的
CREATE TABLE `temp_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
`temp_name` varchar(128) DEFAULT NULL,
`form_structure` longtext DEFAULT NULL COMMENT 'schema结构体',
`creator` varchar(128) DEFAULT NULL,
`remarks` longtext,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT="模版信息";
问题描述:
上面我们可以看到,模版的编辑,是支持拖拽的,也就是每一个表单的位置可随意切换。但前端切换成功后,点击保存,在渲染出来的时候,会发现没有修改成功。
前端提交数据顺序:
{
"type": "object",
"properties": {
"bbb": {
"title": "单选",
"type": "string",
"widget": "select",
"required": false,
"disabled": false,
"readOnly": false,
"props": {
"filterOption": true,
"showSearch": true,
"optionFilterProp": "label"
}
},
"a": {
"title": "多选",
"type": "array",
"widget": "checkboxes",
"description": "点击多选",
"required": false,
"disabled": false,
"readOnly": false,
"items": {
"type": "string"
}
}
},
"labelWidth": 120,
"displayType": "row"
}
后端保存到数据库中的顺序:
{
"type": "object",
"properties": {
"a": {
"title": "多选",
"type": "array",
"widget": "checkboxes",
"description": "点击多选",
"required": false,
"disabled": false,
"readOnly": false,
"items": {
"type": "string"
}
},
"bbb": {
"title": "单选",
"type": "string",
"widget": "select",
"required": false,
"disabled": false,
"readOnly": false,
"props": {
"filterOption": true,
"showSearch": true,
"optionFilterProp": "label"
}
}
},
"labelWidth": 120,
"displayType": "row"
}
最开始以为是前端的组件在传递数据的时候 中间对数据进行了转换导致,但在后端打印日志,以及在存储到mysql之前进行打印,顺序都是正常的,也就是,数据在落到mysql后,字段顺序发生了变化
查看了一下mysql的json字段,为了提高性能,mysql会针对json字段做排序处理,即按照1、2、3...进行排序,如果字段是英文,那么将按照字符长短进行排序
故最后将mysql中的字段改为text,问题解决。即数据库使用json字段对json中的字段排序,位置没有要求的可以使用,对顺序有要求的不建议使用