Modules and package structure
Module name equals table prefix; naming conventions at a glance; where the reference implementation is.
Package structure
cn.minimao
├── app/<module>/{controller,service,dto,vo,convert}
├── domain
│ ├── handler/<module> + handler/<module>/cmd
│ ├── enums / enums/base
│ └── exception
├── infra/<module>/{model,mapper,repository,query}
├── data # BaseRepository + query-condition framework
├── plugin # extension points (plugin chain)
├── common # context, threads, utilities, exceptions
└── config # response envelope, MyBatis, Sa-Token, JSON wiring
Naming conventions
| Layer | Suffix | Base class / contract | Location |
|---|---|---|---|
| infra | XxxDO | must extends BaseDO | infra/<module>/model |
| infra | XxxMapper | BaseMapper<XxxDO> + @Mapper | infra/<module>/mapper |
| infra | XxxRepository | extends BaseRepository<XxxMapper, XxxDO> | infra/<module>/repository |
| infra | XxxPageQuery | pagination carrier for custom SQL, extends PageCarrierQuery | infra/<module>/query |
| domain | XxxHandler | extends MiniMaoAbstractHandler | domain/handler/<module> |
| domain | XxxCmd | plain @Data | domain/handler/<module>/cmd |
| app | XxxService | @Service | app/<module>/service |
| app | XxxDTO / XxxVO | request / response | app/<module>/{dto,vo} |
| app | XxxConvert | @Mapper(componentModel = "spring") | app/<module>/convert |
- DO / VO / DTO / Cmd all use
@Data; those extending a base class also add@EqualsAndHashCode(callSuper = true). @TableName("table_name")is mandatory, and the module name is the table prefix.infra/<module>/modelholds table entities only; query carriers go inquery— mixing them forces every reader to inspect annotations one by one.
Reference implementation
To see what the "standard answer" looks like, read these three packages: app/users/**, domain/handler/users/**, infra/users/**.
Tip: do not copy directories by hand for a new module. Use the skeleton generator and spend the saved time on business logic.
Last updated 2026-10-09Edit this page →