本文档记录个人在 Forge 项目中的编码习惯和偏好,所有代码编写(含 AI 辅助生成)必须遵循以下规范。
适用范围: forge-hotel 模块及后续所有业务模块 最后更新: 2026-08-14
@Autowired 字段注入,不使用 @RequiredArgsConstructor 构造器注入@Autowired 注解java
@RestController
@RequestMapping("/hotel/dish")
public class HotelDishController {
@Autowired
private HotelDishService hotelDishService;
}
@RequestParam@PathVariable(路径参数如 id)和确实无法用实体类表达的参数(如安全校验参数)才单独接收/{id}/status)属于操作类,可保持 @RequestParam// ❌ 错误 public RespInfo> dishPage(PageQuery pageQuery,
@RequestParam(required = false) Long categoryId,
@RequestParam(required = false) String status,
@RequestParam(required = false) String name) { ... }
- Service 接口和 Mapper 方法签名同步使用实体类参数
- Mapper XML 中用 `@Param("query")` 标注,引用时用 `#{query.fieldName}`
### 1.3 统一返回封装
- 所有接口统一使用 `RespInfo` 封装返回值
- 成功:`RespInfo.success(data)` 或 `RespInfo.success()`(无返回值时)
- 失败:`RespInfo.error(msg)` 或抛出 `BusinessException`
### 1.4 实体类规范
- 实体继承 `TenantEntity`(自带 tenantId + 审计字段)
- 主键使用 `@TableId(value = "id", type = IdType.ASSIGN_ID)`(雪花算法)
- 逻辑删除字段:`@TableLogic(value = "0", delval = "id")`,类型为 `Long`(bigint),删除时写入主键 ID
- 使用 Lombok:`@Data` + `@EqualsAndHashCode(callSuper = true)` + `@Serial`
- 每个字段必须有 Javadoc 注释
- 示例:
```java
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("hotel_business_hours")
public class HotelBusinessHours extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/** 主键ID(雪花算法) */
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/** 状态: ENABLED-启用, DISABLED-禁用 */
private String status;
/** 删除标记(0=未删除,删除时写入主键ID) */
@TableLogic(value = "0", delval = "id")
private Long delFlag;
}
LambdaQueryWrapper 构建查询selectById、insert、updateById、deleteById 等 MyBatis-Plus 内置方法允许DataScopeInterceptor 按 mapperMethod 精确匹配改写 SQLAND del_flag = 0@OperationLog 注解@OperationLog(module = "模块名", type = OperationType.XXX, desc = "操作描述")QUERY / ADD / UPDATE / DELETEcontroller/ # REST 控制器
domain/ # 数据库实体(Entity)
dto/ # 请求 DTO(新增/修改用)
vo/ # 响应 VO(查询返回用)
mapper/ # MyBatis Mapper 接口
service/ # 服务接口
└── impl/ # 服务实现
constant/ # 常量
@Transactional(rollbackFor = Exception.class)validateXxx(Xxx entity/dto)requireXxx(Long id)(不存在直接抛异常)AiCrudPage 组件(自动处理搜索栏、工具栏、表格、分页布局)height: 100%api-config 格式:
javascript
:api-config="{
list: 'get@/hotel/xxx/page',
detail: 'get@/hotel/xxx/:id',
add: 'post@/hotel/xxx',
update: 'put@/hotel/xxx',
delete: 'post@/hotel/xxx/remove/:id',
}"
:id,禁止花括号 {id}tableColumns 和 editSchema 必须定义为 computed(确保字典异步加载后响应式更新)h('a', { class: 'text-primary cursor-pointer hover:opacity-80', onClick: ... }) 模式crudRef.value?.refresh()(不是 reload)crudRef.value?.handleEdit(row)- 作为占位符100pxdiv 包裹 AuthImage 组件,设置 overflow: hidden 防止图片溢出NAvatar 的 src 属性NTag 组件,配合颜色映射
javascript
const statusColorMap = { ENABLED: 'success', DISABLED: 'default' }
render: row => h(NTag, { type: statusColorMap[row.status] || 'default', size: 'small' },
{ default: () => statusLabelMap[row.status] || row.status })
使用 UnoCSS 语义化颜色类区分操作类型:
| 类名 | 颜色 | 场景 |
|---|---|---|
text-primary |
蓝 | 编辑、查看、授权 |
text-warning |
黄 | 刷新缓存、重置、封禁 |
text-error |
红 | 删除、强制下线 |
text-success |
绿 | 启用、发布、通过 |
text-info |
灰蓝 | 详情、统计 |
DictSelect 组件或 useDict() composableDictTag 组件computed 包裹Teleport to="body")position: fixed + 半透明黑色背景max-width: 85vw + max-height: 80vhimport { request } from '@/utils'(不是 @/utils/request)getXxxPage / getXxxDetail / createXxx / updateXxx / deleteXxx// ==================== 模块名 ====================id, tenant_id, create_by, create_time, create_dept, update_by, update_timeutf8mb4,引擎 InnoDBbigint(雪花算法),不用自增bigint,单位分datetime(对应 Java LocalDateTime)varchar,值为大写英文(如 ENABLED / DISABLED、ON_SALE / OFF_SHELF)del_flag 字段类型 bigint NOT NULL DEFAULT 01)@TableLogic(value = "0", delval = "id")V<版本号>__<lower_snake_case_description>.sql1.0.0,单调递增CREATE TABLE IF NOT EXISTSINSERT ... SELECT ... WHERE NOT EXISTSinformation_schemaINSERT 必须显式写列名,禁止依赖表字段顺序tenant_id 必须为 1,禁止写 0parent_id(子查询),避免硬编码 IDsys_dict_type + sys_dict_data,dict_value 与后端枚举值保持一致hotel_ 前缀,系统级用 sys_ 前缀dict_value 必须与后端枚举/状态值严格一致dict_label 只负责展示文案list_class 负责标签样式(success/primary/warning/info/default)| 操作 | HTTP 方法 | 路径 | 说明 |
|---|---|---|---|
| 分页查询 | GET | /xxx/page |
筛选参数用实体类接收 |
| 查询全部 | GET | /xxx/all 或 /xxx/list |
不分页列表 |
| 查询详情 | GET | /xxx/:id |
路径参数 |
| 新增 | POST | /xxx |
RequestBody |
| 修改 | PUT | /xxx |
RequestBody |
| 删除 | POST | /xxx/remove/:id |
路径参数 |
| 状态切换 | POST | /xxx/:id/toggle 或 /:id/toggle-status |
路径参数 |
| 状态更新 | PUT | /xxx/:id/status |
@RequestParam String status |
| 批量操作 | POST | /xxx/batch |
RequestBody |
模块:资源:操作,如 hotel:dish:query、hotel:businessHours:addresource_type = 3tenant_id 必须设为 1(默认租户),禁止设 0tenantId 动态设置租户上下文TenantContextHolder.getTenantId() 获取当前租户 IDreturn tenantId == null ? 1L : tenantId;****)mvn compile -pl forge-business/forge-hotel -am -DskipTestspnpm lint:fix