开发规范
关于表名称
表名使用下划线 业务模块统一使用biz_前辍,如biz_project(项目表),biz_subject_category(学科分类表)
关于表字段
以下是主表和树型主表必备字段
普通主表
| 列名 | 数据类型 | 备注 | 默认值 |
|---|---|---|---|
| id | bigint(20) | 主键 | 系统自动生成 |
| create_time | datetime(3) | 创建时间 | 系统自动生成 |
| create_user | bigint(20) | 创建用户 | 系统自动生成 |
| update_time | datetime(3) | 更新时间 | 系统自动生成 |
| update_user | bigint(20) | 更新用户 | 系统自动生成 |
| is_deleted | tinyint(1) | 是否删除(1:是,0:否) | 0 |
普通树型主表
| 列名 | 数据类型 | 备注 | 默认值 |
|---|---|---|---|
| id | bigint(20) | 主键 | 系统自动生成 |
| parent_id | bigint(20) | 父节点ID | 0 |
| name | varchar(64) | 名称 | 录入 |
| sort | bigint(20) | 排序 | 系统自动生成 |
| create_time | datetime(3) | 创建时间 | 系统自动生成 |
| create_user | bigint(20) | 创建用户 | 系统自动生成 |
| update_time | datetime(3) | 更新时间 | 系统自动生成 |
| update_user | bigint(20) | 更新用户 | 系统自动生成 |
| is_deleted | tinyint(1) | 是否删除(1:是,0:否) | 0 |
子表
子表命名要加上主表前辍,例: biz_project(项目主表) biz_project_opslog (项目操作日志表) biz_project_attachment(项目附件表)
中间表
多对多关系时一般都需要到中间表,可以使用两主表组合命名,例: biz_project(项目表) sys_user(系统用户表) 此时中间表可以为:biz_project_user(r_项目成员关系表) 注释要加上r_前辍
关于接口
前端与后端人员约定的一个数据交换的一种规范。
数据格式-JSON
{
"id": 1,
"userName": "admin",
"userType": 1
}
后端统一返回结构规范
{
"code": 0,
"msg": "登录成功",
"data": {}
}
| 名称 | 类型 | 描述 |
|---|---|---|
| code | int | 状态码,200为成功,其他为失败 |
| message | String | 消息描述 |
| data | Object | 业务数据 |
返回规范
提交类
{
"code": 0,
"msg": "登录成功",
"data": {}
}
单条记录
{
"code": 0,
"msg": "登录成功",
"data": {
"id": 1,
"userName": "admin",
"userType": 1
}
}
多条记录
{
"code": 0,
"msg": "登录成功",
"data": [
{
"id": 1,
"userName": "admin1",
"userType": 1
},
{
"id": 2,
"userName": "admin2",
"userType": 1
}
]
}
分页记录
{
"code": 0,
"msg": "成功",
"data": {
"recordCount": 4,
"totalPage": 1,
"pageSize": 10,
"pageNum": 1,
"rows": [
{
"id": "1686404946814533633",
"userName": "admin",
"realName": "蒙立东",
"nickName": null,
"avatar": null,
"password": "211a86bdebe70443aa2e567bfc1e4d6e",
"salt": "tyszoxth",
"mobilePhone": "18276163688",
"tel": null,
"email": null,
"adminType": 2,
"sex": 1,
"isLocked": 0,
"deptId": "1704792169135079426",
"postId": "1705025419610894338",
"remark": null,
"createTime": "2023-08-01 23:54:05",
"createUser": "1567738052492341249",
"updateTime": "2023-09-25 17:01:02",
"updateUser": "1567738052492341249",
"isDeleted": 0,
"deptName": null,
"postName": null,
"roleIds": "1735191814393401346,1705019929250172930"
},
{
"id": "1711659551216500738",
"userName": "u0010",
"realName": "黄红",
"nickName": "",
"avatar": null,
"password": "2f4896ecef0ce948d9340ab895f72159",
"salt": "vqylahu6",
"mobilePhone": "13800000020",
"tel": null,
"email": null,
"adminType": 2,
"sex": 2,
"isLocked": 0,
"deptId": "1711659720523776002",
"postId": "1712271151770308609",
"remark": null,
"createTime": "2023-10-10 16:26:52",
"createUser": "1567738052492341249",
"updateTime": "2023-10-12 08:59:31",
"updateUser": "1567738052492341249",
"isDeleted": 0,
"deptName": null,
"postName": null,
"roleIds": "1735191814393401346"
},
{
"id": "1711661958608584706",
"userName": "u0011",
"realName": "王强",
"nickName": null,
"avatar": null,
"password": "1166408769777440bc33d42583712929",
"salt": "heco3yr0",
"mobilePhone": "13602312301",
"tel": null,
"email": null,
"adminType": 2,
"sex": 1,
"isLocked": 0,
"deptId": "1704792169135079426",
"postId": "1712270597442670593",
"remark": null,
"createTime": "2023-10-10 16:36:26",
"createUser": "1567738052492341249",
"updateTime": "2024-04-07 23:52:03",
"updateUser": "1686404946814533633",
"isDeleted": 0,
"deptName": null,
"postName": null,
"roleIds": "1735191814393401346"
},
{
"id": "1714545752097366017",
"userName": "u0012",
"realName": "李青",
"nickName": null,
"avatar": null,
"password": "a2575ec4a1f33a8f8ad40d2acd9bb5cb",
"salt": "a56uxlm2",
"mobilePhone": "18264232652",
"tel": null,
"email": null,
"adminType": 2,
"sex": 2,
"isLocked": 0,
"deptId": "1711659720523776002",
"postId": "1705025419610894338",
"remark": null,
"createTime": "2023-10-18 15:35:36",
"createUser": "1567738052492341249",
"updateTime": "2023-10-18 15:35:44",
"updateUser": "1567738052492341249",
"isDeleted": 0,
"deptName": null,
"postName": null,
"roleIds": "1735191814393401346"
}
],
"rainbow": null,
"ext": null
}
}
| 名称 | 类型 | 描述 |
|---|---|---|
| recordCount | long | 总记录数 |
| totalPage | int | 总页数 |
| pageSize | int | 每页的条数 |
| pageNum | int | 当前页,默认值为1 |
全局 null 键剥离与 @KeepNullResponse 豁免(mldong-nestjs 栈)
mldong-nestjs 有一个全局 SmartNullStrippingInterceptor,对每个响应的 data 做两件事:
- null 键剥离:值为
null的字段整键不输出(键消失)。默认形状是「空值 ⇒ 键消失」, 与上面分页示例里的「键恒在、值可为 null」相反; - Date 格式化:
Date字段统一格式化为yyyy-MM-dd HH:mm:ss字符串(字段可用@DateFormat自定义格式)。
对要求「键恒在、值可为 null」跨栈契约形状的出口(典型:jeeflow 门面 /wf/** 的时间列—— 未完成任务的 finishTime 键必须在、值 null),用 @KeepNullResponse() 装饰器豁免:
- 类级:标注在控制器类上,对该类所有路由生效(
WfController采用类级——/wf/**是单一 通配路由,类级标注即覆盖整个门面); - 方法级:标注在单个
@Get/@Post方法上(方法级标注优先于类级); - 豁免范围:只豁免 null 键剥离,Date 格式化保留(豁免删键 ≠ 豁免格式化);
- 字段级
@KeepNull()(元数据keepNull:fields)不受影响,两者可叠加; - 零存量行为变更:未标注的接口行为与此前完全一致。
// mldong-nestjs
import { KeepNullResponse } from 'src/decorators/keep-null-response.decorator';
@KeepNullResponse() // 类级:/wf/** 保留 null 键,Date 仍格式化
export class WfController { ... }
契约背景:13 栈契约要求 approvalRecord 行恒含 9 列 taskName/displayName/taskType/performType/taskState/operator/finishTime/variable/ext (jeeflow spec 06-facade §4.6)。nestjs 曾因此全局剥离在未完成行缺 finishTime 键, L2-16 record_row_keys 红;2026-09-23 以 framework issue 23 修复(方案 A 最小豁免)。
提交的规范
id提交类
请求正文JSON
{
"id": 1
}
ids提交类
{
"ids": [1,2,3]
}
实体提交类
{
"id": 1,
"userName": "admin",
"userType": 1,
"password": "123456"
}
通用查询类
详见通用查询
