1. 只有一个简单业务实体
假设有一个编辑简历的功能,页面元素很简单,只有:姓名、年龄。数据格式为:application/json。
1.1 初次提交
请求参数
{
"age": 29,
"name": "张三"
}
响应参数
{
"id": 386
}
1.2 编辑后提交
请求参数
前端需要传递id或uuid这类唯一标识到后端。如果不传递:
- 如果业务上规定,一个用户只能有一个简历,那就简单了。
- 如果业务上规定,一个用户可以有多个简历,例如面试政府部门的简历,面试互联网公司的简历等,那后端就无从下手,不知道该更新哪个了。
所以,再次编辑后提交,需要携带id。
{
"id": 386
"age": 30,
"name": "张三"
}
响应参数
{
"id": 386
}
2. 一个业务实体,并且同时1对多关联其他业务实体
在编辑简历的同时,也编辑教育信息。
2.1 初次提交
请求参数
{
"name": "张三",
"age": 29,
"eduList": [
{
"colleague": "高校1",
"major": "专业1"
},
{
"colleague": "高校2",
"major": "专业2"
},
{
"colleague": "高校3",
"major": "专业3"
}
]
}
响应参数
问题来了,如何表征多个教育信息在数据库表里的id值呢?这个id很重要,删除或更新教育信息时需要用到。
- 最简单的方式,重新加载整个页面信息,显然,加载后所有实体都有id。但是,比较浪费带宽。
- 可以考虑前端为每个教育信息生成一个临时唯一标识,响应时携带这个临时唯一标识,这样前端就可以对号入座,根据frontEndUuid的值,设置后端生成的真正的id值了,之后抛弃frontEndUuid。
改进后请求参数
{
"name": "张三",
"age": 29,
"eduList": [
{
"frontEndUuid": "xxxx",
"colleague": "高校1",
"major": "专业1"
},
{
"frontEndUuid": "xxxx",
"colleague": "高校2",
"major": "专业2"
},
{
"frontEndUuid": "xxxx",
"colleague": "高校3",
"major": "专业3"
}
]
}
改进后响应参数
{
"id": xxx,
"eduList": [
{
"frontEndUuid": "xxxx",
"id": xxx
},
{
"frontEndUuid": "xxxx",
"id": xxx
},
{
"frontEndUuid": "xxxx",
"id": xxx
}
]
}
2.2 查询并编辑后提交
查询的响应参数
{
"id": xxx,
"name": "张三",
"age": 29,
"eduList": [
{
"id": "xxxx",
"colleague": "高校1",
"major": "专业1"
},
{
"id": "xxxx",
"colleague": "高校2",
"major": "专业2"
},
{
"id": "xxxx",
"colleague": "高校3",
"major": "专业3"
}
]
}
问题来了,编辑后如何表征哪些教育信息是新增的,哪些是被修改的,哪些是被删除的?可以考虑:
【方法1】
- 新增的,为新增的教育信息新增一个变量:newEduList
- 修改的,为修改的(无变化的视为修改的)教育信息新增一个变量:modifiedEduList
- 删除的,为删除的教育信息新增一个变量:delEduList
【方法2】
不新增变量,只使用eduList这一个变量:
- 无论用户作何操作,全都把页面上呈现的教育信息封装到eduList,并传递到后端。
- 将传入eduList记为A,数据库中的eduList集合(例如select id from t_edu_info where userId = ?)记为B。
- 新增的教育信息:A中edu的id为空的。
- 无变化的及修改的教育信息:A与B的交集。
- 删除的:B-A。
【方法3】
不新增变量,只使用eduList这一个变量:
- 如果eduList为null,表示教育信息无变化,后端可以忽视之。
- 如果eduList的大小为0,则表示客户端已删除了所有实体,无新增和修改。以下内容仅针对eduList大小大于0的情况:
- 将传入eduList记为A,数据库中的eduList集合(例如select id from t_edu_info where userId = ?)记为B。
- 新增的教育信息:A中edu的id为空的。
- 无变化的及修改的教育信息:A与B的交集。
- 删除的:B-A。
方法1 | 方法2 | 方法3 | |
---|---|---|---|
优点 | 数据模型很清晰,后端代码整洁。 | 变量少,前端工作量少些。 | 对方法2的改进 |
缺点 | 变量较多,前端工作量大些。 | 后端对前端的操作不甚明了,计算新增的、修改的和删除的,一个也不能少,即使用户没有任何编辑行为。 |
方法1请求参数举例(方法2和方法3略)
{
"id": xxx,
"name": "张三",
"age": 30,
"newEduList": [
{
"frontEndUuid": "xxxx",
"colleague": "高校4",
"major": "专业4"
}
],
"modifiedEduList": [
{
"id": "xxxx",
"colleague": "高校2-更新", <====== 这是修改的
"major": "专业2-更新"
},
{
"id": "xxxx", <====== 这里并没有修改,但后端仍可以按此数据进行更新
"colleague": "高校3",
"major": "专业3"
}
],
"delEduList": [
{
"id": "xxxx"
},
{
"id": "xxxx"
}
]
}
2.3 粗暴的处理方法
无论新增还是编辑,对教育信息每次都先删除数据库中的数据,再按全新数据插入。弊端是无效的垃圾数据较多。
2.4 关于“多”的那个实体数据的删除问题
上例中,显然需要新增一个表来保存教育信息。编辑简历时,如果前端删除了某条教育信息,对应数据库里也删除就可以了。考虑这种场景:
- 新增“照片”业务实体,一个简历里可以关联1或多个照片。
- 为了节省存储空间,N张照片在数据库里最多保存N行记录(列名可能包括:照片名称、照片格式、照片二进制数据信息)。
- 某一张照片可能被多个简历关联了,但不能重复保存该照片信息。当然了,关联表可以有多条记录(列名可能包括:简历ID、照片ID)。
修改简历或删除简历时,不能像删除教育信息一样,删除照片数据,只能删除简历与照片的关联表数据。应该在照片管理功能里上传新照片或删除照片。删除照片时,如果照片被引用了,要提示用户:一旦删除照片,那些引用该照片的简历里,也将一并被删除。