开发规范、设计原则、数据库规范、平台规范、AI 规范
# 一、用户界面
# 1、设计原则
# 1)对齐
- 层次结构清晰,观察 1 像素,引导视觉流向,让用户更流畅地接收信息
- 如果页面的字段或段落较短、较散时,需要确定一个统一的视觉起点
# 2)多元化
- 根据不同的用户体验,可快速进行界面色调切换
- 点击侧边栏头像,扩大工作区域显示,可快速折叠侧边栏和顶部导航栏
- 根据用户喜好,可折叠侧边栏,默认折叠侧边栏,取消页签模式,表单弹窗模式
- 弹窗的表单,关闭表单后,自动刷新列表数据,保留列表查询条件
- 列表操作体验清晰,不太实用的操作进行折叠隐藏
- 列表查询区域隐藏,扩大列表显示区域
# 3)布局色彩
- 响应式样式,12 列栅格化布局,根据屏幕大小进行自适应布局,支持平板或手机操作
- 色彩源于『自然』的设计价值观,设计师通过对自然场景的抽象捕捉
# 4)导航设计
- 在广义上,任何告知用户他在哪里,他能去什么地方以及如何到达那里的方式,都可以称之为导航
- 支持侧边栏全部导航;或者顶部一级导航,二级以下导航在侧边栏
# 2、数据列表
# 1)列对齐方式
- 短小字符居中,比较长的字符居左,日期居中,货币或带小数点的数字居右
- 数值位数相等的字段,如:编码、编号:居中
- 字典类,如:分类、类型、类别、状态:居中
- 不规则长度,5个字符以上,名称、标题:居左
- 日期时间:居中
- 与货币相关的,金额、单价:居右
- 带小数点的数字,数量、百分数:居右
- 整数型数字,年龄,个数:居中
- 合计,与合计列对齐方式相同
# 2)列显示格式
- 与货币相关,金额或单价:保留两位小数,如无特殊要求,不加货币符号,不使用千分位符号,默认单位“元”,如果单位不是“元”,则必须在列标题或当前页标明单位,如:金额(万元)
- 长字符列,名称、标题、备注等:当列宽不足时,用 … 号表示无法显示的字符
- 日期:yyyy-MM-dd,日期时间:yyyy-MM-dd HH:mm,如业务无特别要求,不带秒,如需要时分秒,格式为: yyyy-MM-dd HH:mm:ss 采用24小时制
- 列宽要适中,根据内容调整列宽大小
# 3)其他要求
- 列表中存在与金额相关的列,或者与数量相关的列,根据业务要求,列表底部增加合计,如果列表是分页列表,合计默认为查询结果的合计,而不是当前页合计
- 合计校验:明细行合计值,与合计行值相同,不要出现明细与合计的数值不对的情况
- 汇总与明细校验:汇总值与钻取的明细合计值相同,同上
- 根据业务要求,比较大或比较耗时的页面,第一次打开时,如没有特殊要求,默认不执行查询显示数据,需要点击查询,执行显示数据,并提示“点击查询显示数据”信息
- 对于列与数字相关的,如:金额、数量、证件号码(如:身份证)或其它由长数字组成的字段,不能出现科学计数法格式
- 明细行中不能存在重复记录
# 4)查询条件
- 数据字典字段作为查询条件,无特殊要求,信息内容相对固定少于20行时,采用下拉选择方式,否则采用弹出对话框选择方式;有特别要求时,可以采用输入方式,进行模糊查询,除此之外,必须采用选择方式
- 查询条件为多行时,标签需要上下两端对齐,标签单行右对齐,注意美观
- 输入框或选择框,上下两端对齐,宽度适中
# 3、编辑表单
# 1)表单控件
- 必填信息,必须明确区分,标签前增加红色星号,醒目显示,必填信息在保存时必须增加必填验证
- 数值类型,必须增加数值验证
- 日期类型,必须增加日期格式验证
- 边界验证,录入信息的长度不得多于数据库字段长度,input标签必须包含增加maxlength属性
- 无特殊情况,如:电话、身份证、邮箱,能用正则表达式验证的字段必须启用验证
- 界面录入信息与列表显示信息保持一致,避免字段张冠李戴
- 界面显示信息与数字相关的,如:金额、数量、证件号码(如:身份证)或其它由长数字组成的字段,不能出现科学计数法格式
- 必须避免提交类型按钮多次执行,出现多条相同信息,在未成功之前,不能多次点击
# 2)其它要求
- 对整个项目进行跨浏览器的测试(必须兼容IE10+、360、Chrome、Firefox浏览器)
- 界面大小应该适合美学观点,感觉协调舒适,能在有效的范围内吸引用户的注意力,注意细节(观察1像素距离、列表文字对齐)
- 必须保证在最小分辨率1024x768的可视性(不允许错版),在高分辨率下页面要自适应,不能出现标题背景空白,错位情况
- 每一步操作,如保存、更新、审核,都要有提示,如:保存xx成功!
- 检查界面是否有文字错误,避免出现看不懂的文字
- 手机端或PC端图标及标题内容显示不全的,应尽量减少文字,不显示…,让文字显示全
# 3)Vue 分离版设计
- 共享 Ant Design of React (opens new window) 设计工具体系。
- 提炼自企业级中后台产品的交互语言和视觉风格。
# 4)AI 前端代码约束(分端约束,不通用)
Vue 和 Beetl 前端组件体系完全不同,约束不可混用。
AI 生成前端代码时:先确认目标端(Vue / Beetl),然后加载对应 Skill 读取对应文档:
- Vue 端 → 加载
frontend-vueSkill,读取/vue-crud-view/、/vue-basic-form/、/vue-basic-table/- Beetl 端 → 加载
frontend-beetlSkill,读取/views-beetl/、/datagrid/
Vue 分离端约束要点(详细规则见上述文档):
| 要素 | Vue 组件 | 说明 |
|---|---|---|
| 列表表格 | BasicTable 组件 | 列配置、分页、排序、选择行 |
| 编辑表单 | BasicForm 组件 | 表单配置、校验规则、字段联动 |
| 查询区域 | BasicForm(表单模式复用) | 字段标签右对齐、每行 3-4 列 |
| 权限控制 | v-auth 指令 | 按钮/菜单权限 |
Beetl 经典端约束要点(详细规则见上述文档):
| 要素 | Beetl 组件 | 说明 |
|---|---|---|
| 列表表格 | DataGrid 组件(jqGrid) | 列配置、分页、事件 |
| 编辑表单 | <#form:form class="form-horizontal"> 标签 | 表单组件、字段渲染 |
| 查询区域 | <#form:form class="form-inline"> 标签 | 手动布局 |
| 权限控制 | <% if (hasPermi('app:appComment:edit')){ %>元素<% } %> | Beetl 模板中权限判断 |
Vue & Beetl 共有的后端约束 → 后端验证注解 Hibernate Validator 查看文档 (opens new window)
# 二、数据库设计规范
# 1、命名规范
- 数据库对象,如:表、列、索引、视图、存储过程、自定义函数,的命名的原则是简、短,易懂好记,有意义的英文单词、常用缩写,多个单词组成的,当长度比较大时应使用缩写,特殊情况使用拼音或首字母
- 数据表命名:必须带有模块前缀,如财务总账:js_fin_
- 如果命名由多个词汇组成,词汇之间加 _ 下划线,如:js_sys_office_company
# 2、设计规范
- 通常情况下每张表必须有主键,对于非主键,具有唯一性质的,必须加,唯一索引
- 每张表,每个字段都必须有正确的中文描述说明,以便快速生成数据字典
- 业务数据表必要时冗余基础信息表的核心字段,如:部门编码、部门名称,需要成对出现在业务数据表中
- 对于字符类型(VERCHAR)字段,确定数据值仅是数字、字母并无其它特殊字符的情况下使用VERCHAR字段,其它必须使用NVARCHAR类型,避免使用VARCHAR类型
- 表字段的长度要统一,尤其基础数据在业务数据中的引用,如:部门编码、部门名称,在任何业务数据表中的长度务必保持一致
- 存储过程、自定义函数、视图,以及调度,必须要有详细的注释说明
- 统一入口,统一出口原则:相同意义的数据存储、提取,使用同一过程和方法
- 不要盲目的加入其他索引,根据需要统一加索引
- 必须使用内置通用字段组,不要自行定义相同含义的字段。详细字段定义参见:内置通用字段组
- 主键:必须使用
varchar(64)类型,字段名为id(来自BaseEntity)或者其它自定义的业务名称,使用_code结尾,如:office_code - 状态:必须使用
char(1)类型,字段名统一为status(来自DataEntity) - 创建者:必须使用
varchar(64)类型,字段名统一为create_by(来自DataEntity) - 更新者:必须使用
varchar(64)类型,字段名统一为update_by(来自DataEntity) - 创建时间 / 更新时间:必须使用
datetime类型(来自DataEntity) - 备注:必须使用
nvarchar(500)类型,字段名统一为remarks(来自DataEntity) - 树结构相关:父级编号
parent_codevarchar(64)、排序号tree_sortdecimal(10)、末级标识tree_leafchar(1)等(来自TreeEntity) - 多租户:租户代码
corp_codevarchar(64)、租户名称corp_namenvarchar(100)(来自DataEntity)
- 主键:必须使用
# 数据库字段类型 → Java 类型强制映射(AI 必须遵守)
| 数据库类型 | Java 类型 | 说明 |
|---|---|---|
| VARCHAR / NVARCHAR | String | 字符串,长度在 Entity 中用 @Size(min = 0, max = N) 注解 |
| CHAR | String | 定长字符串,同上 |
| INT / TINYINT | Integer | 整数,禁用 int 基本类型 |
| BIGINT | Long | 长整数,禁用 long 基本类型 |
| DECIMAL / NUMERIC | Double 或 java.math.BigDecimal | 金额、汇率等金融数据,严禁使用 Double/Float |
| FLOAT / DOUBLE | Double | 仅用于非金融的普通小数 |
| DATE(年月日) | java.util.Date | 不带时分秒,增加 @JsonFormat(pattern = "yyyy-MM-dd") 注解 |
| DATETIME | java.util.Date | 带时分秒,增加 @JsonFormat(pattern = "yyyy-MM-dd HH:mm") 注解 |
| TEXT / CLOB | String | 大文本,展示用 textarea |
| BLOB | byte[] | 禁止使用二进制数据用于数据表列存储,应该存储文件 |
# 3、使用规范
- 在指定用户下,只有项目经理具有数据表对象的设计权限,其他开发人员不得调整表结构
- 作业调度需要有详细的登记台账(也是项目管理要求的一部分)
- SQL书写采用:关键字大写,表名,列名小写
- 变更数据库必须同步 erm 模型
# 4、数据库设计
# 三、平台开发规范
AI 注意:生成代码前,必须先读取以下目录的模板文件,严格按其结构输出,不可凭记忆生成:
modules/core/src/main/resources/templates/modules/gen/config.xml(模板注册中心,入口)modules/core/src/main/resources/templates/modules/gen/crud/(实体/DAO/Service/Controller 模板)modules/core/src/main/resources/templates/modules/gen/crud_cloud/(微服务生成模板)modules/core/src/main/resources/templates/modules/gen/vue/(Vue 前端模板)modules/core/src/main/resources/templates/modules/gen/view/(Beetl 前端模板)modules/core/src/main/resources/templates/modules/gen/app/(手机端前端模板)- 禁止 AI 生成模块代码,应该通过:模块管理 - 新建模块 - 生成代码(包括 Java 后端模块、Vue 前端模块、微服务模块)
- 代码生成后对照 四.9 AI 修订清单 逐项检查
# 1、JeeSite 包的命名规范
设有公司统一包名如:com.jeesite 包(根据项目单位命名),不允许直接在此包下直接建立模块,要先创建一个 modules 包。
- 模块格式:com.jeesite.modules.模块名.分层.子模块名.功能类
- 分层为 entity、dao、service、web、utils、config
- 若模块下只有几个功能,没有子模块,就不需要再建立子模块了
- Spring Boot 自动配置文件格式:com.jeesite.autoconfigure.模块名.配置类
- 自动配置的类,在 /META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 里指定
- 通用封装包或工具类:com.jeesite.common.大类.小类.封装类
# 2、JeeSite 分层命名规范
# Controller
| 操作 | 命名 | 备注 |
|---|---|---|
| 类名 | 以Controller结尾,继承BaseController | UserController |
| 类上的映射路径 | ${adminPath} / 模块 / 子模块 / 功能 | ${adminPath}/sys/user |
| 自动注入属性 | 与注入名相同,不允许注入 Dao | 不允许使用 @Autowired,应该通过构造方法注入 Service |
| 方法上的映射路径 | 与方法名相同 | @RequestMapping、@GetMapping、@PostMapping |
| 方法上的权限字符串 | 模块名:子模块名:控制器名:功能名 | @RequiresPermissions |
| 每次请求都会执行的方法 | get | @ModelAttribute |
| 列表页面 | list | |
| 列表数据 | listData | |
| 新增或编辑表单 | form | |
| 新增或编辑提交地址 | save | |
| 删除 | delete | |
| 停用 | disable | |
| 启用 | enable | |
| 主键校验 | check开头 | |
| 导入 | import开头 | |
| 导出 | export开头 | |
| 树结构数据 | treeData |
四名保持命名联系: Controller类名、映射路径、方法名、视图文件名,举例如下:
| 类型 | 命名 | 说明 |
|---|---|---|
| 类名 | SysEmpUserController.java | Sys 为模块名,但系统模块可不加 Sys |
| 映射路径 | /sys/empUser/list | /模块[/子模块]/功能/操作 |
| 映射方法 | public list() {} | 功能名,如列表:list,列表数据:listData,表单:form |
| Beetl视图文件名 | empUserList.html | 不要直接命名为 list.html(写全方便查找) |
| Beetl视图文件路径 | /src/main/resources/views/modules/sys/empUser/ | 统一放 resources 资源目录下 |
| Vue视图命名 | /packages/sys/views/sys/empUser/list.vue | 与映射路径一致 |
遵循一定的命名规范,可快速根据映射路径找到对应的源代码。
# Service
| 操作 | 命名 | 备注 |
|---|---|---|
| 类名 | 以Service结尾 | 继承 CrudService,TreeService,QueryService |
| 查询一条数据 | get | 以 get 开头 |
| 插入数据 | insert | 以 insert 开头 |
| 更新数据 | update | 以 update 开头 |
| 新增或编辑 | save | 以 save 开头 |
| 删除 | delete | 以 delete 开头 |
| 查询多条数据 | findList | 以 find 开头,List 结尾 |
| 查询多条分页 | findPage | 以 find 开头,Page 结尾 |
以上方法,参数应该使用 Entity 类型,返回值应该使用 Entity 或 List<Entity> 类型,更新返回 void 类型。
# Dao
| 操作 | 命名 | 备注 |
|---|---|---|
| 类名 | 以Dao结尾 | 继承 CrudDao,TreeDao,QueryDao |
| 查询一条数据 | get | 以 get 开头 |
| 插入数据 | insert | 以 insert 开头 |
| 更新数据 | update | 以 update 开头 |
| 删除 | delete | 以 delete 开头 |
| 物理删除 | phyDelete | |
| 查询多条数据 | findList | 以 find 开头,List 结尾 |
以上方法,参数应该使用 Entity 类型,查询返回值应该使用 Entity 或 List<Entity> 类型,更新返回 long 类型。
# Entity
| 操作 | 命名 | 备注 |
|---|---|---|
| 类名 | 根据表名以驼峰命名法转换 | 继承 DataEntity,TreeEntity,BaseEntity |
| 主键 | @Column(isPk=true) | 指定主键的列会自动与 getId() setId() 绑定 |
| 验证方法 | Hibernate Validator | 例如:@Length,@NotNull,查看文档 (opens new window) |
| 注解位置 | 依据能写 get 方法上绝不写字段上原则 | |
| 父类中已有的属性 | 父类中已有的属性无需定义,特殊情况除外 | |
| 非表属性的字段 | 如查询字段,必须写清楚注释说明用途。 | |
| 查询条件 | 查询条件必须写清楚注释说明用途。 @Column(queryType=?) 仅作为默认查询条件,扩展查询条件应该使用 get 和 set 方法,使用 _gte、_lte、_like 等结尾命名 |
# 3、Beetl 视图文件规范
所有视图文件均放在:模块项目 /src/main/resources/views 目录下,尽量不放在web项目下,约束如下:
| 名称 | 说明 |
|---|---|
| include | 公共视图代码块 |
| layouts | 公共视图布局文件 |
| modules | 功能模块视图文件,格式:/modules/模块名[/子模块]/功能页面 |
| themes | 个性化主题视图文件存放路径,格式:/themes/modules/模块名[/子模块]/功能页面 |
# 4、Static 静态文件规范
所有静态文件均放在:模块项目/src/main/resources/static 目录下,尽量不放在web项目下,约束如下:
| 名称 | 说明 |
|---|---|
| common | 存放公共脚本,不建议项目使用过程中修改。 |
| modules | 项目相关的模块 js 和 css 文件存放位置,格式:/modules/模块名[/子模块]/静态文件 |
| themes | 个性化主题视图文件存放路径,格式:/themes/modules/模块名[/子模块]/静态文件 |
| 组件文件 | 格式:组件名/组件版本/组件文件,例如:/static/echarts/4.2/组件文件包 |
# 5、Vue 分离端规范
AI 注意:生成 Vue 前端代码前,加载
frontend-vueSkill 读取对应文档:/vue-crud-view/(CRUD视图)、/vue-basic-form/(BasicForm 组件)、/vue-basic-table/(BasicTable 组件)、/vue-auth/(前端权限)、/vue-comp/(通用组件)。
开发辅助工具:
| 工具 | 用途 |
|---|---|
| eslint | 校验代码格式规范 |
| stylelint | 校验 css/less 规范 |
| prettier | 代码格式化 |
| TypeScript | 类型约束(tsconfig.json) |
目录结构规范(详细:/vue-install-deploy/):
| 路径 | 说明 | 示例 |
|---|---|---|
packages/{模块}/api/{模块}/{功能}.ts | API 接口定义(axios 请求封装) | packages/cms/api/cms/article.ts |
packages/{模块}/views/{模块}/{功能}/list.vue | 列表页(查询 + 表格 + 分页) | packages/cms/views/cms/article/list.vue |
packages/{模块}/views/{模块}/{功能}/form.vue | 编辑表单页(新增/修改) | packages/cms/views/cms/article/form.vue |
packages/{模块}/views/{模块}/{功能}/index.vue | 入口页(通常为 list 的容器) | packages/cms/views/cms/article/index.vue |
packages/{模块}/index.ts | 模块导出入口 | packages/core/index.ts |
packages/{模块}/package.json | 模块依赖声明 | — |
核心组件体系(基于 Antdv Next 或 Ant Design Vue 4.x):
| 组件 | 用途 | 参考文档 |
|---|---|---|
BasicForm | 表单 CRUD(查询区域 + 编辑表单),声明式配置字段/校验/联动 | /vue-basic-form/ |
BasicTable | 数据表格(列配置、分页、排序、筛选、多选),声明式配置 | /vue-basic-table/ |
| 通用组件库 | 文件上传、人员选择、机构选择、图标、富文本等 | /vue-comp/ |
v-auth 指令 | 按钮/菜单级权限控制 | /vue-auth/ |
showType → Vue 控件和 gridRowCol → 布局的详细映射表见本文 六.4 节。
# 6、注解驱动 SQL 规范
JeeSite 采用 @Table + @Column 注解驱动 MyBatis 动态 SQL,不再为 CRUD 操作手写 XML 映射。XML 仅用于自定义复杂查询。
# @Table 注解约束
// 关键结构(完整代码参见 crud/entity.xml 模板)
@Table(name = "${_prefix}test_data", alias = "a", label = "测试数据", columns = {
@Column(includeEntity = BaseEntity.class), // 当包含 corp_code、corp_name 时,必须使用。
@Column(includeEntity = DataEntity.class), // 当包含 create_by、create_date、update_by、update_date、remarks、status 时,必须使用。
@Column(name = "id", attrName = "id", label = "编号", isPK = true),
// ...
},
joinTable = {
@JoinTable(type = Type.LEFT_JOIN, entity = Office.class, alias = "o",
on = "o.office_code = a.office_code",
columns = {@Column(includeEntity = Office.class)}),
},
orderBy = "a.update_date DESC"
)
2
3
4
5
6
7
8
9
10
11
12
13
14
规则:表名必须带 ${_prefix} 多租户前缀;主表别名固定 "a"。
# @Column 规范
name:数据库列名(下划线命名),必须与数据库表一致attrName:Java 属性名(驼峰命名),必须与 getter/setter 对应label:中文描述,用于数据字典和 Excel 标题isPK:是否为主键(isPK=true的列自动与getId()/setId()绑定)isQuery:是否作为查询条件(默认 true,可显式关闭无关字段的查询能力)queryType:查询运算符类型,可选:EQ,NE,GT,GTE,LT,LTE,BETWEEN,LIKE,LEFT_LIKE,RIGHT_LIKEisUpdateForce:更新时是否总是更新此字段(默认 false)isInsert/isUpdate:控制字段是否参与插入/更新
# @JoinTable 规范
- 关联 User:
@JoinTable(type = Type.LEFT_JOIN, entity = User.class, alias = "u", on = "u.user_code = a.user_code", columns = {@Column(includeEntity = User.class)}) - 关联 Office:同上模式,
on = "o.office_code = a.office_code" - 关联 Company:
on = "c.company_code = a.company_code" - 关联 Area:
on = "ar.area_code = a.area_code" - attrName 务必与属性名一致,否则关联查询结果无法赋值
# 范围查询字段规范
Entity 中定义 gte/lte 范围查询字段(非表字段,必须注释说明用途):
public void setCreateDate_gte(Date createDate){
createDate = DateUtils.getOfDayFirst(createDate);
sqlMap.getWhere().and("create_date", QueryType.GTE, createDate);
}
@Schema(description = "小于等于创建时间")
public Date getCreateDate_lte(){
return sqlMap.getWhere().getValue("create_date", QueryType.LTE);
}
2
3
4
5
6
7
8
关键点:getter 中通过 sqlMap.getWhere().getValue("数据库列名", QueryType.XXX) 实现范围查询,不赋值时就忽略该条件。
# MyBatis XML Mapper 规范
仅当注解无法满足时才编写 XML。标准格式(详细参见 crud/mapper.xml 模板):
| 元素 | 规则 |
|---|---|
| namespace | 必须与 DAO 完整类名一致 |
| 基础 CRUD | 不需要 XML(框架从 @Table 注解自动生成) |
| 动态列/表 | 使用 ${sqlMap.column.toSql()} / ${sqlMap.table.toSql()} |
| 动态条件 | 使用 ${sqlMap.where.toSql()} + <if test> 标签 |
| 参数绑定 | 用户输入参数必须用 #{} 预编译,禁止 ${} 拼接 |
| weight 属性 | 当需要覆写 Dao 默认实现的时候,select、update 元素增加权重属性 |
存放位置:/src/main/resources/mappings/modules/<模块名>/<Dao名>.xml
# 7、实体字段类型规范(基于代码生成模板)
根据代码生成模板 config.xml 中定义的字段类型,新增实体字段时必须遵循以下类型映射:
| 数据库类型 | Java 类型 | config.xml 类型标识 | 使用场景 |
|---|---|---|---|
| VARCHAR/NVARCHAR | String | String | 名称、标题、编码、备注等文本 |
| BIGINT | Long | Long | 长整型数字,关联外键 |
| INT | Integer | Integer | 整型数字,年龄、个数、状态码 |
| DECIMAL | java.math.BigDecimal | BigDecimal | 金额、单价等金融数据(禁用 Double) |
| FLOAT/DOUBLE | Double | Double | 普通小数,数量、百分数 |
| DATETIME | java.util.Date | Date | 日期时间 |
| 关联用户 | com.jeesite.modules.sys.entity.User | User | 用户编码 + 用户名称(attrName="userCode |
| 关联机构 | com.jeesite.modules.sys.entity.Office | Office | 机构编码 + 机构名称(attrName="officeCode |
| 关联公司 | com.jeesite.modules.sys.entity.Company | Company | 公司编码 + 公司名称(attrName="companyCode |
| 关联区域 | com.jeesite.modules.sys.entity.Area | Area | 区域编码 + 区域名称(attrName="areaCode |
| 父对象引用 | 实体自身类型 | Parent | 生成树结构父对象 |
注解位置约束:验证注解(@NotBlank, @Size 等)优先写在 get 方法上,不写在字段上。
# 8、Service 层两种模式约束
| 模式 | 适用场景 | 写法 |
|---|---|---|
| 模式一 | 普通单表 CRUD | @Service + extends CrudService<Dao, Entity>,构造器注入依赖 |
| 模式二 | 跨模块调用、暴露 API | interface XxxService extends CrudServiceApi<T> + class XxxServiceSupport extends CrudService<Dao, Entity> implements XxxService |
使用原则:
- 子表批量操作必须在
save()中处理(使用executeBatch()) - 写操作必须标注
@Transactional - 依赖注入统一使用构造器注入
# 9、文件路径与命名约束
# 后端 Java 文件
| 层 | 路径规则 | 命名规则 |
|---|---|---|
| Entity | .../entity/{EntityName}.java | 驼峰命名,与表名对应 |
| DAO | .../dao/{EntityName}Dao.java | Entity名 + Dao 后缀 |
| Mapper XML | .../mappings/modules/{模块名}/{EntityName}Dao.xml | 与 Dao 接口名一致 |
| Service | .../service/{EntityName}Service.java | Entity名 + Service 后缀 |
| Controller | .../web/{EntityName}Controller.java | Entity名 + Controller 后缀 |
# 前端视图文件
| 类型 | 路径规则 |
|---|---|
| Beetl 视图 | /views/modules/{模块}[{子模块}]/{功能名}/{操作}.html |
| Vue 页面 | /src/views/{模块}[{子模块}]/{功能名}/{操作}.vue |
| Vue API | /src/api/{模块}[{子模块}]/{功能名}.ts |
# 10、完整代码模板(AI 必须读取实际模板文件)
AI 生成各层代码时,必须先去读取以下实际模板文件,不要凭记忆生成。模板目录:
modules/core/src/main/resources/templates/modules/gen/
├── crud/entity.xml → Entity 模板
├── crud/mapper.xml → MyBatis Mapper XML 模板
├── crud/dao.xml → DAO 接口模板
├── crud/service.xml → Service 模板
├── crud/controller.xml → Controller 模板
├── config.xml → 模板分类注册中心(入口配置)
├── vue/ → Vue 前端模板(vueApi/vueList/vueForm/vueIndex/vueImport)
├── crud_cloud/ → 微服务架构模板
└── query/ → 仅查询功能模板
2
3
4
5
6
7
8
9
10
生成步骤:
- 先读
config.xml确认模板分类(crud/crud_vue/treeGrid/service/dao/query) - 按分类找到对应的
.xml模板文件并读入 - 严格按模板结构输出代码,替换其中的
${...}变量 - 生成后对照 四.9 AI 修订清单 逐项检查
关键约束摘要(详细格式见模板文件):
- Entity:
@Table注解声明表映射,columns中includeEntity引入父类字段,验证注解写在 get 方法上 - DAO:
@MyBatisDao+extends CrudDao<T>,不声明基础 CRUD 方法,只声明自定义查询 - Mapper XML:仅自定义查询需要,
namespace与 DAO 全类名一致,基础 CRUD 由@Table注解自动生成 - Service:
extends CrudService<Dao, Entity>,写操作加@Transactional,构造器注入依赖 - Controller:
extends BaseController,@RequestMapping("${adminPath}/模块/功能"),方法按get→list→listData→form→save→disable→enable→delete顺序
# 11、树结构实体规范
树结构实体继承 TreeEntity<T> 而非 DataEntity<T>。AI 生成时读取 treeGrid_* 模板文件。
关键差异(与普通 CRUD 对比):
columns中用@Column(includeEntity = TreeEntity.class)引入树形字段- 树名字段标记
isTreeName = true orderBy使用a.tree_sorts排序- 必须重写
getParent() / setParent()返回具体类型 - Service 继承
TreeService<Dao, Entity>而非CrudService - Controller 增加
treeData方法返回List<Map<String, Object>>供前端树组件使用
# 12、主子表(子表)处理规范
AI 生成时读取 config.xml 中模板的 <childTable> 节点,以及 vue/vueFormChildList.xml。
关键规则:
| 层级 | 规则 |
|---|---|
| 子表 Entity | 继承 DataEntity<T>,外键用 @Column(name="父表_id", attrName="父表Entity.id");构造函数 public XxxChild(XxxEntity parent){ this.parent = parent; } |
| 子表 DAO | @MyBatisDao + extends CrudDao<T>,可加 deleteByEntity(T t) 方法 |
| 主表 Entity | 声明 protected List<XxxChild> xxxChildList = ListUtils.newArrayList(); |
| 主表 Service.save() | super.save(entity) → childDao.executeBatch(dao -> { forEach: insert/update/delete }) |
| 主表 Service.get() | 查询主表后,查询子表 childDao.findList(child) 并设置到 xxxChildList |
executeBatch 批量处理模式(三条分支):
STATUS_DELETE → dao.delete(child) // 标记删除的行
isNewRecord() → dao.insert(child) // 新增行
其他 → dao.update(child) // 修改行
2
3
# 13、导入导出规范
Entity 导出字段声明(@ExcelFields + @ExcelField):
| 属性 | 说明 |
|---|---|
title | Excel 列标题 |
attrName | 属性名,支持嵌套如 "office.officeName" |
align | 对齐:Align.CENTER(居中)、Align.LEFT(居左)、Align.RIGHT(金额居右) |
sort | 排序,间隔 10 方便插入 |
dataFormat | 数字格式,金额用 "0.00" |
Controller 导出:new ExcelExport("标题", XxxEntity.class).setDataList(list).write(response, "文件名.xlsx") Controller 导入:xxxService.importData(file, updateSupport),实际逻辑在 Service 中实现。
# 14、代码注释规范
- 类级注释:必须包含功能描述、
@author、@version - 方法注释:公有方法必须写 JavaDoc(一句话描述即可),私有方法可不写
- 非表字段:必须用
// 查询:xxx注释说明用途 - 复杂逻辑:关键分支用
// 步骤1:xxx注释 - 禁止:无意义的
// add by xxx 2024-01-01注释 - TODO/FIXME:临时标记必须附带说明和日期
# 四、其它开发规范
# 1、主键规范
有意义的、有规则的数据必须采用手动编码方式,不允许使用 UUID 自动生成注解表示,方便运维,例如:组织机构编码,区域编码。
# 2、事务管理规范
- 写操作(insert / update / delete / save)必须标注
@Transactional - 只读操作不标注事务注解,由
CrudService基类默认管理 - 跨 Service 调用写入操作时,调用方必须标注事务,确保原子性
- 文件上传 + 数据库写操作必须在同一事务中处理,避免脏数据
# 3、异常处理规范
- Controller 层不抓取异常,统一由框架全局异常处理器拦截
- Service 层校验失败抛出
RuntimeException或框架定义的业务异常 - 禁止在 DAO 层抛出业务异常(只抛数据访问异常)
- JSON 接口返回统一使用
renderResult(Global.TRUE/FALSE, text("xxx成功!"))
# 4、依赖注入规范
- 禁止在 Controller 中注入 DAO(违反分层原则)
- 使用构造器注入(非 @Autowired 字段注入),提高可测试性
- 不引入非必要的第三方依赖,优先使用框架已有工具类
- 新增 Maven 依赖必须在父 POM 中统一管理版本号
# 5、权限控制规范
- 每个 Controller 方法必须标注
@RequiresPermissions("模块名:功能名:操作名") - 权限字符串格式:
sys:user:view/sys:user:edit(三段式:模块:功能:操作) - 数据权限过滤使用
addDataScopeFilter(entity, ctrlPermi)方法,Service 里实现该方法,Controller 里调用该方法 - 字段权限过滤使用
addFieldScopeFilter(entity)方法,Service 里实现该方法,Controller 里调用该方法
# 6、常量与枚举规范
- 模块级常量定义在实体类或专门的常量类中(如
User.USER_TYPE_EMPLOYEE) - 字典值不得硬编码在视图层,必须通过数据字典组件读取
- 状态值、类型值禁止使用魔数,必须定义为常量或枚举
# 7、禁止硬编码与安全规范
- 禁止在代码中硬编码密码、密钥、Token、数据库连接串
- SQL 查询参数必须使用
#{}占位符(预编译),严禁用${}拼接用户输入(SQL 注入风险) ${}仅用于sqlMap.xxx.toSql()动态 SQL 标签和_prefix表前缀
# 8、代码生成后的 AI 修订清单
AI 使用代码生成器模板生成代码后,必须逐项检查以下内容:
| 序号 | 检查项 | 说明 |
|---|---|---|
| 1 | Entity 主键 | 确认 isPK=true 的字段与数据库一致 |
| 2 | 字段长度 | @Size(max=N) 必须与数据库字段长度一致 |
| 3 | 查询字段 | 确认 isQuery=true/false,避免无关字段可查询 |
| 4 | 关联表 | 确认 @JoinTable 的 on 条件正确,attrName 与属性名对应 |
| 5 | 字典字段 | 列表页使用 dictType 属性或字典组件渲染 |
| 6 | 必填验证 | 必填字段有前端 required: true + 后端 @NotBlank |
| 7 | 日期格式 | 列表:yyyy-MM-dd,表单:date 或 datetime 控件 |
| 8 | 金额格式 | 列表右对齐、保留两位小数、不含千分位 |
| 9 | 操作权限 | 每个按钮/链接有对应的权限标签 |
| 10 | 排序字段 | orderBy 使用索引列,避免全表扫描 |
| 11 | Mapper XML | 仅自定义查询需要 XML,标准 CRUD 不需要 |
| 12 | 版权声明 | 所有文件头包含 Copyright 声明 |
# 五、AI 开发助手行为边界
# 允许操作清单
| 类别 | 允许内容 |
|---|---|
| 代码生成 | 基于 config.xml 模板分类(crud_vue, crud, treeGrid_vue, service, dao, query 等)生成标准 CRUD 代码 |
| Entity | 创建继承 DataEntity<T> / TreeEntity<T> 的实体类,使用 @Table + @Column 注解 |
| DAO | 创建继承 CrudDao<T> / TreeDao<T> 的 DAO 接口,标注 @MyBatisDao |
| Service | 创建继承 CrudService<D, T> 的 Service 或 CrudServiceApi<T> 接口 |
| Controller | 创建继承 BaseController 的控制器,遵循 四名保持命名联系 规则 |
| Mapper XML | 仅编写自定义复杂查询的 XML,使用 ${sqlMap.xxx.toSql()} 动态 SQL |
| 权限注解 | 添加 @RequiresPermissions 和数据/字段权限过滤 |
| 字段验证 | 使用 Hibernate Validator 注解(@NotBlank, @Size, @Pattern, @NotNull) |
| Excel 注解 | 使用 @ExcelFields / @ExcelField 定义导入导出 |
| Vue 页面 | 创建基于 config.xml Vue 模板格式的 list.vue, form.vue, api.ts |
| 工具类 | 使用框架已有的 com.jeesite.common.* 工具类 |
| 数据字典 | 使用框架数据字典组件,不从零实现 |
# 禁止操作清单
| 类别 | 禁止内容 | 原因 | 正确做法 |
|---|---|---|---|
| 修改框架基类 | 尽量不修改JeeSite原版源码,应使用Java的继承、重写、多态等特性重写实现 | 方便JeeSite平台版本升级 | 重写子类方法 |
| 跨层调用 | 禁止 Controller 直接注入 DAO;禁止 View 层直接调用 DAO | 违反分层架构原则 | Controller → Service → DAO |
| 绕过注解 | 禁止不使用 @Table 注解而手写完整 CRUD 的 XML | 破坏框架注解驱动 SQL 机制 | 优先用 @Table 注解 |
| 建表语句 | 禁止 AI 直接编写 DDL 建表语句 | 数据库变更必须通过 ER 模型同步,走正式变更流程 | 通过 ER 模型工具 |
| 修改 config.xml | 禁止修改代码生成模板配置文件 | 模板结构由项目负责人管理 | 使用 config-custom.xml |
| 新增依赖 | 禁止未经评审新增 Maven/Gradle 第三方依赖 | 依赖变更需评审 | 先沟通确认 |
| 包名越界 | 禁止在 com.jeesite 根包下直接建类,必须经由 modules 子包 | 遵循包命名规范 | com.jeesite.modules.xxx.entity |
| URL 映射 | 禁止自定义 ${adminPath} 以外的 URL 前缀 | 统一 URL 规范 | ${adminPath}/模块/功能 |
| SQL 注入 | 禁止用 ${} 拼接用户输入参数(必须用 #{}) | SQL 注入风险 | 必须用 #{} 预编译 |
| 魔数 | 禁止在代码中使用魔法数字、魔法字符串表示状态/类型 | 不可维护 | 定义常量或枚举 |
| 硬编码 | 禁止硬编码密码、密钥、Token、配置项 | 安全风险 | 配置文件/系统参数 |
| UUID 主键 | 禁止对业务表使用 UUID 自动生成主键 | 有意义的编码便于运维 | 手动编码 |
| 科学计数法 | 禁止金额、数量、证件号码等数字字段出现科学计数法显示 | 影响数据可读性 | 格式化显示 |
| 无验证 | 禁止表单不添加前端+后端双重验证 | 防止脏数据入库 | 双重验证 |
| 修改API签名 | 禁止修改已有方法的参数、返回值、权限注解(除非明确要求重构) | 防止连锁崩溃 | 新增方法替代 |
| DROP/TRUNCATE/无条件的DELETE | 禁止生成任何删除表结构或清空数据的 SQL | 不可逆操作 | 禁止 |
# AI 决策树:选择正确的方法
Q1:新建模块?
→ 是:先创建模块包结构(entity/dao/service/web),再生成代码
→ 否:进入 Q2
Q2:功能是什么类型?
→ 单表 CRUD + Vue 前端:使用 crud_vue 模板,生成 5 个后端 + 5 个前端文件
→ 单表 CRUD + Beetl 前端:使用 crud 模板,生成 5 个后端 + 3 个 Beetl 文件
→ 树结构 CRUD:使用 treeGrid_vue / treeGrid 模板,Entity 继承 TreeEntity
→ 仅后端持久层:使用 service(含 Service)/ dao(仅 DAO)模板
→ 仅查询(不含增删改):使用 query 模板
Q3:有子表(一对多)?
→ 主表按 Q2 选择模板
→ 子表 Entity 继承 DataEntity,外键用 attrName="父表Entity.id"
→ 主表 Service 用 executeBatch 处理子表批量操作
Q4:需要关联系统表(User/Office/Company/Area)?
→ Entity 中声明 private Office office; 属性
→ @JoinTable 中配置 LEFT_JOIN
→ @Column(name="office_code", attrName="office.officeCode")
Q5:需要导入导出?
→ Entity 加 @ExcelFields / @ExcelField 注解
→ Controller 加 exportData / importData 方法
→ Excel 导出用 new ExcelExport("标题", XxxEntity.class)
# 六、AI 代码生成模板约束
AI 在生成代码时,必须严格按照以下模板分类对应的文件清单输出,不允许生成模板之外的文件结构。每种模板分类对应固定的生成文件集合,File 数量不可多也不可少。
# 1、模板分类与生成文件对照表
| 模板分类 (config.xml) | 生成的后端文件 | 生成的前端文件 |
|---|---|---|
crud_vue | Entity + Mapper XML + DAO + Service + Controller | vueApi + vueList + vueForm + vueIndex + vueImport |
crud | Entity + Mapper XML + DAO + Service + Controller | Beetl viewList + viewForm + viewIndex |
treeGrid_vue | 同 crud_vue(Entity 继承 TreeEntity) | 同 crud_vue |
treeGrid | 同 crud(Entity 继承 TreeEntity) | 同 crud |
service | Entity + Mapper XML + DAO + Service | 无 |
dao | Entity + Mapper XML + DAO | 无 |
query | Entity + Mapper XML + DAO + Service + Controller | Beetl viewList + viewForm |
crud_java | Entity + Mapper XML + DAO + Service + Controller | 无 |
说明:
- 主子表时,子表额外生成:Entity + Mapper XML + DAO(子表不生成 Service 和 Controller)
- Cloud 模式的模板(
crud_cloud_vue等)不在此列,适用于微服务架构
# 2、各文件生成约束(AI 必须精确遵循)
# Entity 文件约束
- 必须继承:
DataEntity<T>(普通表)或TreeEntity<T>(树表) - 必须含:
@Table注解,columns中使用对应通用字段时,必须includeEntityBaseEntity/DataEntity/TreeEntity - 必须含:无参构造器
this(null)+ 带主键构造器super(id) - 字段声明:使用包装类型(
String,Long,Integer,BigDecimal,Double),禁用基本类型 - 验证注解:全部写在
get方法上(非字段上) - 关联对象:
private Office office;方式声明,@Column(name="office_code", attrName="office.officeCode")
# DAO 文件约束
- 必须标注
@MyBatisDao,继承CrudDao<T>/TreeDao<T> - 禁止添加
@Mapper注解(@MyBatisDao已足够) - 禁止写
get/insert/update/delete基础方法(父接口已提供) - 仅自定义查询方法需要声明(格式:
List<T> findXxxList(T entity)/Page<T> findXxxPage(T entity))
# Mapper XML 文件约束
- 生成时机:仅在 Entity 注解无法满足(如自定义复杂查询)时生成
- 存放位置:
/src/main/resources/mappings/modules/{模块名}/{DaoName}.xml - namespace:必须与 DAO 完整类名一致
- 基础 CRUD:不需要 XML(框架从
@Table注解自动生成 SQL) - 自定义查询:使用
#{}预编译参数,条件判断用<if test>标签
# Service 文件约束
- 简单 CRUD:直接
extends CrudService<Dao, Entity>,不加接口 - API 契约:
interface XxxService extends CrudServiceApi<T>+class XxxServiceSupport extends CrudService<D, T> implements XxxService - 构造器注入:
private final XxxDao xxxDao;+ 构造函数参数(非@Autowired字段) - 写操作:必须加
@Transactional - 子表操作:在
save()中用executeBatch()批量处理
# Controller 文件约束
- 必须继承
BaseController,使用@Controller(非@RestController) - URL 前缀:
@RequestMapping(value = "${adminPath}/模块/功能") - 注入:仅注入 Service(禁止注入 DAO),构造器注入
- 方法顺序:
get(ModelAttribute) →list→listData→form→save→disable→enable→delete→treeData(如需要) →exportData/importData(如需要) - 权限注解:每个方法必须加
@RequiresPermissions - JSON 返回:使用
renderResult(Global.TRUE/FALSE, text("提示信息"))
# 3、Controller 方法清单(标准 CRUD)
每个标准 CRUD Controller 方法按以下顺序排列(详细格式读取 crud/controller.xml 模板):
| 序号 | 方法名 | 注解 | 返回值 | 权限后缀 | 说明 |
|---|---|---|---|---|---|
| 1 | get | @ModelAttribute | XxxEntity | — | 每次请求前预加载数据 |
| 2 | list | @RequestMapping("list") | String(视图路径) | view | 列表页面 |
| 3 | listData | @RequestMapping @ResponseBody | Page<XxxEntity> | view | 列表 JSON 分页数据 |
| 4 | form | @RequestMapping | String(视图路径) | view | 编辑表单页面 |
| 5 | save | @PostMapping @ResponseBody | String | edit | 保存(@Validated 验证) |
| 6 | disable | @RequestMapping @ResponseBody | String | edit | 停用(STATUS_DISABLE) |
| 7 | enable | @RequestMapping @ResponseBody | String | edit | 启用(STATUS_NORMAL) |
| 8 | delete | @RequestMapping @ResponseBody | String | edit | 删除 |
| 9★ | treeData | @RequestMapping @ResponseBody | List<Map> | view | 树结构数据(仅 TreeEntity) |
| 10☆ | exportData | @RequestMapping | void | view | 导出 Excel(按需) |
| 10☆ | importData | @PostMapping @ResponseBody | String | edit | 导入 Excel(按需) |
★ = 树结构专属,☆ = 按需添加。JSON 返回统一用
renderResult(Global.TRUE/FALSE, text("xxx成功!"))。
# 4、Vue 分离端文件约束
Vue 分离端根据 config.xml 的 showType 和 gridRowCol 配置生成表单布局:
- 表单控件映射(基于 config.xml showType):
| showType | BasicForm component | 说明 |
|---|---|---|
input | Input | 单行文本。例外:若字段类型为 Integer 且 attrName == 'treeSort',映射为 InputNumber |
textarea | InputTextArea | 多行文本、备注 |
hidden | 不渲染到表单(值通过 record.value 传递) | 隐藏域(isPK 主键通常隐藏) |
select | Select(JeeSiteSelect) | 单选下拉,通过 dictType 配置数据字典 |
select_multiple | Select(JeeSiteSelect,mode: 'multiple') | 多选下拉 |
radio | RadioGroup(JeeSiteRadioGroup) | 单选按钮组 |
checkbox | CheckboxGroup(JeeSiteCheckboxGroup) | 复选框组 |
date | DatePicker(format: 'YYYY-MM-DD', showTime: false) | 日期选择 |
datetime | DatePicker(format: 'YYYY-MM-DD HH:mm', showTime: { format: 'HH:mm' }) | 日期时间选择 |
userselect | TreeSelect(API: officeTreeData, isLoadUser: true) | 关联用户 |
officeselect | TreeSelect(API: officeTreeData) | 关联机构 |
companyselect | TreeSelect(API: companyTreeData) | 关联公司 |
areaselect | TreeSelect(API: areaTreeData) | 关联区域 |
- 栅格布局映射(基于 config.xml gridRowCol):
| gridRowCol | 列数 | 布局 |
|---|---|---|
12/2/10 | 1 列 | 标签2格 + 输入框10格 |
12/2/8 | 1 列(小) | 标签2格 + 输入框8格 |
12/2/5 | 1 列(中) | 标签2格 + 输入框5格 |
6/4/8 | 2 列 | 标签4格 + 输入框8格 × 2 |
4/4/8 | 3 列 | 标签4格 + 输入框8格 × 3 |
3/4/8 | 4 列 | 标签4格 + 输入框8格 × 4 |
# 5、文件头与版权声明
所有 AI 生成的 Java/Vue 文件必须包含以下版权声明(遵循项目约定):
/**
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
*/
2
3
# 6、禁止生成的破坏性代码
- 禁止生成改变现有 API 签名的代码(除非明确要求重构)
- 禁止生成删除/清空数据表的 SQL 语句(如
TRUNCATE,DROP, 无条件的DELETE) - 禁止生成绕过 Shiro 权限验证的代码
- 禁止生成 JS 中直接操作 DOM 绕过 Vue 数据绑定的代码
- 禁止在异步线程 /
@Async方法 /CompletableFuture中通过UserUtils.getUser()或SecurityUtils.getSubject()获取当前登录用户信息(异步线程无登录上下文)
