java-ylsw-bw.md 13 KB


name: crud-by-controller-ylsw-bw

description: 基于仪陇表务(ylsw-bw / water-meter)ledger 模块风格生成 CRUD、台账查询与导出接口。参考 com.tofly.wm.ledger.meter 等既有实现,统一 ResultResponse、MPJ、PageHelper 与权限注解。用户提到表务、水表台账、ledger、出入库、生成接口时使用。

CRUD 生成 Skill(仪陇表务 ylsw-bw)

适用场景

当用户要求在 business/water-meter 或表务相关模块中新增/补全接口时,优先对齐 com.tofly.wm.ledger 下既有代码(首选参考 ledger/meter,台账类参考 ledger/purchaseledger/arriveledger/verify)。

公共 Skill 引用

代码落点与包结构(对齐 com.tofly.wm

模块根包 com.tofly.wm,按业务分层;新建代码必须落在与职责匹配的包下,禁止全部堆在 ledger 或单一层级。

包树与职责(参考 ledger / manage 存量)

com.tofly.wm
├── cons/                         # 模块常量(字典目录码、业务编码前缀等)
│   └── MeterConstant.java
├── ledger/                       # 台账、出入库、只读汇总(少写或不写主数据)
│   ├── meter/                    # 水表出入库 CRUD
│   │   ├── enums/                # 域内枚举(BoundTypeEnum、CompanyTypeEnum…)
│   │   └── app/                  # 子场景(App 入库、领用等),*Controller/*Service/*Vo
│   ├── purchase/                 # 采购台账(Vo + Query + Service,无独立 Entity 表)
│   ├── arrive/                   # 到货台账
│   └── verify/                   # 落地检台账
├── manage/                       # 管理端业务写操作、主数据维护
│   ├── puachase/                # 采购(存量包名 puachase,新建子包沿用勿改拼写)
│   │   ├── apply/                # 采购申请
│   │   │   └── list/             # 申请明细子表
│   │   ├── plan/                 # 采购计划
│   │   │   ├── arrive/           # 到货单
│   │   │   └── arriveList/       # 到货明细
│   │   └── claim/                # 领用
│   ├── brand/                    # 厂家
│   ├── verify/                   # 检定管理(含 giveback 等子包)
│   └── warehouse/
├── workorder/                    # 工单
└── api/                          # 对外/第三方接口(verify 等)

单包内文件组织(以 ledger/meter 为准)

类型 命名 位置
接口 {Domain}Controller 域包根目录
服务接口/实现 {Domain}Service / {Domain}ServiceImpl 域包根目录;台账可无接口,仅 {Domain}LedgerService
实体 {Domain} 域包根目录
查询 {Domain}Query / {Domain}LedgerQuery 域包根目录
展示 {Domain}Vo / {Domain}LedgerVo 域包根目录
Mapper {Domain}Mapper 域包根目录
枚举 *Enum {domain}/enums/
App/专项 App*Claim* {domain}/app/ 等子包
  • 同包平铺为主,不按 controller/service/entity 再分子包(与 ledger 一致)。
  • 子表/明细:独立子包 listarriveList 等,类名与主表关联清晰。
  • 常量:字典目录、流水号类型等放 com.tofly.wm.cons.MeterConstant,禁止魔法字符串。
  • 表名前缀 TF_WM_*,业务表多为 _Wmapper.xmlsrc/main/resources/mapper/

选型:ledger 还是 manage?

场景 推荐包
分页/列表/导出台账、跨表只读汇总 ledger.{domain}
主表 CRUD、流程、审批、写入业务表 manage.{业务域}
移动端/专项入口 ledger.{domain}.appmanage.*.app

ylsw-bw 专项约束

接口与返回

  • 返回体统一 ResultResponse<T>(带泛型,禁止裸类型)。
  • Controller:@RestController + @RequestMapping("/xxx") + @Api(tags = "...")
  • 依赖注入:@RequiredArgsConstructor + @FieldDefaults(level = PRIVATE, makeFinal = true)(Controller 常见);Service 可用 @AllArgsConstructor@Service 无接口实现类。

路由习惯(对齐 meter)

能力 方法 路径 说明
分页 GET /page /list 共用 {Domain}Query(含 pageNum/pageSize
列表 GET /list /page 同一 Query、同一 Service 条件;不分页,返回 List
详情 GET /{id}
新增 POST / @RequestBody 实体
修改 POST /update 本模块用 POST 而非 PUT
删除 DELETE /{id}
批量删除 DELETE /deleteByIds ids 请求参数,逗号分隔主键
导出 GET /export 返回 voidEasyPoiUtil.download(台账类)

工具类与空值判断

场景 用法 禁止/避免
字符串为空 StrUtil.isNotBlank(s) / StrUtil.isBlank(s) 手写 s != null && !s.isEmpty()
集合为空 CollUtil.isEmpty(list) / CollUtil.isNotEmpty(list) list == null
对象拷贝 BeanUtil.copyProperties(...) 大段手动 set(无业务差异时)
对象是否为 null Objects.nonNull(x) / Objects.isNull(x) 对象用 == null 写在条件首参外且无一致性时
枚举入库条件 Optional.ofNullable(enum).map(Enumerable::getKey).orElse(null) 直接 .eq(field, enum) 未取 key
范围时间 .between(Objects.nonNull(q.getStartDate()), ...) 未判空即 between
  • Hutool 包名:cn.hutool.core.*StrUtilCollUtilBeanUtil 等),与项目存量一致。
  • 字符串用 Hutool;引用类型对象(实体字段、枚举、Long、OrganizationEntry 等)用 Objects

分页与查询

  • 查询类继承 PageQuery,Swagger @ApiModel / @ApiModelProperty
  • Query 字段类型:筛选用 Long/String/枚举/LocalDate 等基础类型;OrganizationEntryUserNameEntryDictEntry 仅出现在 Entity/Vo,不出现在 Query(字典筛选可用字典 code 的 String)。
  • 单表条件:Wrappers.<Entity>lambdaQuery(),条件首参遵循上表;枚举用 Enumerable.getKey()
  • 列表:list(query) 与分页共用 buildWrapperpage(query) 内部 PageHelper.startPage(query, () -> list(query))
  • 批量删除:Service deleteByIds(String ids) 解析逗号分隔主键后 removeByIds,需 @Transactional
  • 多表台账只读:MPJWrappers.lambdaJoin() + selectJoinList(见 purchase/verify 台账),不强行拆 XML。
  • 关键条件行加简短行尾注释(见注释规范),如 //出厂编码//需求部门

Service / Mapper 基类

  • 实体 CRUD:MPJBaseService<Entity> / MPJBaseServiceImpl<Mapper, Entity>
  • Mapper:MPJBaseMapper<Entity>;简单查询不写 XML。
  • 复杂统计、窗口函数、批量状态更新:在 *Mapper.xml 编写,禁止 Mapper 注解 SQL。

实体与值对象(部门 / 用户 / 字典)

  • 继承 BaseEntity;主键 @TableId(value = "ID", type = IdType.ASSIGN_ID)(雪花)。
  • Lombok:@Data@Accessors(chain = true)@FieldDefaults(level = PRIVATE);字段 @TableField 大写列名

部门 / 公司(OrganizationEntry)

  • 仅持久层实体、Vo 使用 OrganizationEntry 存部门/公司(含 id、name 映射),禁止Long deptId + String deptName 双字段落库。
  • Query / *LedgerQuery 中禁止使用 OrganizationEntry:按部门/公司筛选时用 Long(如 demandCompanyapplyDeptId),按名称模糊筛选用 String(如 deptName,按需);与 PurchasePlanQuery.demandCompany 一致。
  • 新增/修改赋值(Entity)OrganizationEntry.of(部门或公司ID);会话上下文可用 ApplicationSession.getDepartmentId() / getCompanyId()
  • Service 条件拼装:Query 的 Long 与实体 OrganizationEntry 字段对接,例如
    .eq(Objects.nonNull(q.getDemandCompany()), Entity::getDemandCompany, q.getDemandCompany())(见 PurchasePlanServiceImpl)。

用户(UserNameEntry)

  • Entity、Vo 上申请人、入库人等:UserNameEntry禁止Long userId 落库。
  • Query 中不使用 UserNameEntry;按用户筛选用 Long userIdString 用户名(如 inboundUser)。
  • 赋值UserNameEntry.of(ApplicationSession.getUserId()) 或业务传入的用户 ID。

字典(DictEntry + @DictDirectory

  • 字典项字段类型 DictEntry;字段上必须标注字典目录:

    @DictDirectory(MeterConstant.DICT_METER_JJCD)  // 字典目录码,定义在 MeterConstant
    @TableField("PRIORITY")
    @ApiModelProperty("紧急程度")
    DictEntry priority;
    
  • 目录常量集中在 com.tofly.wm.cons.MeterConstant,例如:

    • DICT_METER_JJCD — 紧急程度
    • DICT_METER_TYPE — 水表类型
    • DICT_METER_DIAMETER — 口径
    • DICT_WORKER_ORDER — 工单类型
  • 新建字典目录时:先在 MeterConstant 增加常量 → 再在实体/Vo 上使用 @DictDirectory

  • 按字典编码写死业务分支时:DictEntry.of(MeterConstant.PURCHASE_APPLY) 等(见 PurchaseApplyServiceImpl)。

  • Query 中若仅按字典 code 筛选,可用 String + eq回显/入库仍用实体上的 DictEntry

业务枚举(非字典)

  • 状态、出入库类型等:实现 Enumerable<T>getKey() / getLabel(),放 {domain}/enums/

注释规范

层级 要求
JavaDoc:中文业务说明;@author@date(与 ledger 存量一致)
public 方法(Service) JavaDoc:@param@return;说明业务含义,非复述方法名
关键代码 仅对非显而易见逻辑:状态流转、双写出入库、补偿、Wrappers 中每组条件的业务含义(参考 MeterServiceImpl.list 行尾 //总公司/分公司
禁止 无信息注释(// 查询// 保存);大量注释掩盖坏命名

示例(Service 条件注释,摘自 meter):

.eq(Objects.nonNull(q.getCompanyType()), Meter::getCompanyType,
        Optional.ofNullable(q.getCompanyType()).map(CompanyTypeEnum::getKey).orElse(null))
//出厂编码
.like(StrUtil.isNotBlank(q.getFactoryCode()), Meter::getFactoryCode, q.getFactoryCode())

Swagger 与日志

  • @Api(tags);方法 @ApiOperation;路径参数 @ApiParam
  • 写操作按 java-tf-ylsw-backend@ToFlyAppLog(ledger/meter 存量未全覆盖时,新增写接口应补齐)。

生成步骤

  1. 识别域与参考类
    • 标准 CRUD → ledger/meterMeterController ~ MeterMapper)。
    • 只读台账 + 导出 → ledger/purchaseledger/verify
  2. 生成 Query / Vo(分页查询、导出列)。
  3. 生成 Entity + Enum(表结构对齐 TF_WM_*)。
  4. 生成 Mapper + Service(Impl)(单表 Wrappers,多表 MPJJoin)。
  5. 生成 ControllerResultResponse、权限、路由)。
  6. 按需生成 Mapper.xml(仅复杂 SQL)。
  7. 自检(见下)。

输出格式

## CRUD 结果(ylsw-bw)
- 域包:`com.tofly.wm.ledger.{domain}`
- 参考模板:`ledger/meter` | `ledger/purchase` | ...
- 新增/修改文件:`...`

## 接口清单
- `GET /{resource}/page`
- `GET /{resource}/list`
- `DELETE /{resource}/deleteByIds`
- ...

## 规范检查
- [x] ResultResponse 带泛型
- [x] 包路径符合 ledger/manage 职责划分
- [x] 字符串用 StrUtil,对象空值用 Objects.nonNull/isNull
- [x] Entity/Vo 使用 OrganizationEntry、UserNameEntry、DictEntry + @DictDirectory;Query 不用 Entry 对象
- [x] 字典目录常量来自 MeterConstant
- [x] 类/方法/关键逻辑注释符合规范
- [x] 分页使用 PageHelper + PageQuery
- [x] 简单查询用 Wrappers / MPJ,复杂 SQL 在 XML
- [x] Mapper 无注解 SQL

参考

  • 模板代码见 examples-ylsw-bw.md
  • 仓库实现:business/water-meter/src/main/java/com/tofly/wm/ledger/meter/