导出工程结构
导出工程结构
业务用途
本文详解 产出的 zip 解压后的目录布局,以及背后 backend/src/main/resources/templates/export/ 下的 FreeMarker 模板树。理解了模板树,就知道平台能导出什么、改哪里能定制产物。
导出分两大形态:
- 单体(single):
backend/+admin-ui/(+ 可选mobile/),一个 jar 跑后端、一个 Vite 工程跑前端。 - 多模块(multiModule):
<artifactId>-parent/下挂system+biz-<group>+bootstrap子模块 +admin-ui/。
涉及文件
| 角色 | 路径 |
|---|---|
| 模板根目录 | backend/src/main/resources/templates/export/ |
| 渲染编排 | backend/src/main/java/com/lowcode/export/AppExportService.java |
| 元数据模型 | backend/src/main/java/com/lowcode/export/EntityMeta.java |
| 业务分组定义 | backend/src/main/java/com/lowcode/seeder/foundation/FoundationSchema.java(businessGroup 字段) |
| ERP 分组定义 | backend/src/main/java/com/lowcode/seeder/erp/ErpSchema.java(purchase / warehouse 等 group) |
后端实现(关键代码)
模板目录总览
templates/export/ 下 5 个子目录,对应 5 套渲染目标:
templates/export/
├─ admin-ui/ # 后台前端:Vue3 + Vite + Element Plus,约 30 个 .ftl
├─ biz-module/ # 业务表 Java 源:Entity/Mapper/Service/ServiceImpl/Controller + schema-biz.sql
├─ multi-module/ # 多模块 Maven 工程专用:parent/biz/bootstrap/system 的 pom 与入口
├─ system-module/ # 系统层 Java 源:RBAC/JWT/字典/菜单等 + schema-system.sql + data-system.sql
└─ uni-app/ # 移动端:uni-app 工程,含 H5/小程序打包脚本system-module 模板树
system-module/ 是导出工程的「系统底座」,无论单体还是多模块都会用到。单体模式下由 renderSystemModule 渲染,多模块模式下由 renderSystemSources 渲染(跳过 _root 与 db,因为工程根级文件由 multi-module/ 模板单独生成)。
system-module/
├─ _resources/
│ ├─ _root/ # 工程根级文件(单体模式专用)
│ │ ├─ Application.java.ftl # -> src/main/java/<pkg>/<AppClassName>Application.java
│ │ ├─ application.yml.ftl # -> src/main/resources/application.yml
│ │ ├─ pom.xml.ftl # -> pom.xml
│ │ ├─ README.md.ftl
│ │ └─ dot-gitignore.ftl # -> .gitignore
│ ├─ db/
│ │ ├─ schema-system.sql # 系统表 DDL(非 ftl,原样拷贝)
│ │ └─ data-system.sql.ftl # 系统种子数据(admin/123456 等)
│ └─ mapper/system/
│ └─ SysMenuMapper.xml.ftl # 唯一的 XML Mapper
├─ common/ # 通用类
│ ├─ BaseEntity.java.ftl # 审计字段基类
│ ├─ Result.java.ftl # 统一响应
│ ├─ PageResult.java.ftl
│ ├─ QueryHelper.java.ftl # 反射拼 LIKE/等值查询条件
│ ├─ BusinessException.java.ftl
│ └─ GlobalExceptionHandler.java.ftl
├─ config/ # 配置类
│ ├─ MybatisPlusConfig.java.ftl
│ ├─ MyMetaObjectHandler.java.ftl # 自动填充 createTime/updateTime
│ ├─ SecurityConfig.java.ftl
│ ├─ SystemDataInitializer.java.ftl # 启动建表/种子
│ └─ WebMvcConfig.java.ftl
├─ security/ # 安全
│ ├─ JwtUtil.java.ftl
│ ├─ JwtAuthenticationFilter.java.ftl
│ └─ UserDetailsServiceImpl.java.ftl
└─ system/ # 系统管理模块(RBAC + 字典 + 文件等)
├─ controller/ AuthController, SysUserController, SysRoleController, SysMenuController,
│ SysDeptController, SysPostController, SysDictController, FileController,
│ FoundationController, FoundationAdminController, OpenMenuStatusController
├─ dto/ LoginRequest, LoginResponse
├─ entity/ SysUser, SysRole, SysMenu, SysRoleMenu, SysUserRole, SysUserPost,
│ SysDept, SysPost, SysDictType, SysDictData
├─ mapper/ 各实体 Mapper 接口
└─ service/ 接口 + impl(SysUser/SysRole/SysMenu/SysDept/SysPost/SysDict)路径映射规则
mapSystemModuleTarget 负责把模板相对路径映射到产物路径:_resources/_root/Application.java 特判为 <AppClassName>Application.java;_resources/mapper/ 与 _resources/db/ 映射到 resources/ 下;其余 .ftl 去后缀后落到 src/main/java/<basePackage>/ 对应位置。
biz-module 模板树
每个 EntityMeta 渲染 5~7 个 Java 文件(取决于 splitControllerLayer)+ 汇总 SQL:
biz-module/
├─ Entity.java.ftl # 实体类(@TableName + 字段 + imports)
├─ Mapper.java.ftl # BaseMapper 接口
├─ Service.java.ftl # IService 接口
├─ ServiceImpl.java.ftl # ServiceImpl 实现
├─ Controller.java.ftl # 单一 Controller(splitControllerLayer=false)
├─ ControllerAdmin.java.ftl # 后台 Controller(splitControllerLayer=true,带 @PreAuthorize)
├─ ControllerApp.java.ftl # 公开 Controller(splitControllerLayer=true,exposeOpenList=true 才生成)
└─ schema-biz.sql.ftl # 所有业务表 DDL 汇总单体模式产物路径:backend/src/main/java/<basePackage>/biz/<module>/{entity,mapper,service,service.impl,controller}/<ClassName>.java。
Entity.java.ftl 片段:
package ${basePackage}.biz.${entity.module}.entity;
<#list entity.imports as imp>
import ${imp};
</#list>
import com.baomidou.mybatisplus.annotation.TableName;
import ${basePackage}.common.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("${entity.tableName}")
public class ${entity.className} extends BaseEntity {
<#list entity.fields as f>
/** ${f.comment} */
@TableField("${f.tableField}")
private ${f.javaType} ${f.javaField};
</#list>
}Controller.java.ftl 挂在 ${entity.apiPath}(即 /api/biz/<module>),提供 open/list、open/{id}(公开)、list、{id}、POST、PUT/{id}、DELETE/{id}(后台带 @PreAuthorize('${entity.permsKey}:xxx'))。
admin-ui 模板树
标准 Vue3 + Vite + TypeScript + Element Plus 后台工程,约 30 个 .ftl:
admin-ui/
├─ package.json.ftl / vite.config.ts.ftl / tsconfig.json.ftl / index.html.ftl
├─ .gitignore.ftl
├─ public/logo-mark.png
└─ src/
├─ main.ts.ftl / App.vue.ftl / vite-env.d.ts
├─ api/ auth.ts, file.ts, generic.ts(generic 是动态 CRUD 请求封装)
├─ components/ DictTag, FilePreview, RichTextEditor, SearchField
├─ generated/ entities.ts.ftl # 由所有 EntityMeta 生成的前端实体声明
├─ layout/ index.vue, BreadcrumbBar, HeaderTools, TabsBar
├─ router/ index.ts.ftl # 由 entities 动态生成 CRUD 路由
├─ stores/ user.ts, moduleStatus.ts
├─ styles/ main.scss.ftl
├─ utils/ request.ts(axios 封装), theme.ts
└─ views/
├─ crud/GenericCrud.vue.ftl # 通用 CRUD 页(由 entities 驱动,一张表一个路由)
├─ dashboard/index.vue.ftl
├─ login/Login.vue.ftl
└─ site/StyleSwitcher.vue.ftlgenerated/entities.ts 是关键
admin-ui/src/generated/entities.ts.ftl 把所有 EntityMeta 序列化成前端 TS 声明,router/index.ts 与 GenericCrud.vue 据此动态生成菜单和 CRUD 页。这意味着导出的前端是「数据驱动」的,新增表后重新导出即可,不用手写页面。
uni-app 模板树
移动端工程,由 renderMobileUi 渲染,模板在 uni-app/ 下。详见 。
前端实现
导出工程的前端(admin-ui/)本身就是个 Vue3 工程,结构与平台 frontend/ 类似但更精简:用 generic.ts 封装统一的 /api/biz/<module>/list 请求,GenericCrud.vue 一页搞定增删改查。登录走 /api/auth/login,JWT 存 pinia store,axios 请求拦截器带 Authorization。
单体工程产物结构
exported-app-springboot.zip 解压后:
├─ README.md # 启动说明(writeRootReadme 生成)
├─ backend/
│ ├─ pom.xml
│ ├─ src/main/java/<basePackage>/
│ │ ├─ <AppClassName>Application.java
│ │ ├─ common/ config/ security/ system/ # system-module 渲染
│ │ └─ biz/<module>/ # biz-module 渲染(每个实体一套)
│ │ └─ <module>/{entity,mapper,service,service.impl,controller}/
│ └─ src/main/resources/
│ ├─ application.yml
│ ├─ mapper/system/SysMenuMapper.xml
│ └─ db/
│ ├─ schema-system.sql data-system.sql
│ └─ schema-biz.sql data-biz.sql
└─ admin-ui/ # Vue3 + Vite 工程
└─ (见上文 admin-ui 模板树)
多模块 Maven 工程产物结构
exported-app-springboot-multi.zip 解压后(<artifactId>=myapp 为例):
myapp-parent/
├─ pom.xml # packaging=pom,声明 modules + dependencyManagement
├─ README.md .gitignore
├─ myapp-system/ # 系统层(renderSystemSources,跳过 _root 与 db)
│ ├─ pom.xml # multi-module/system/pom.xml.ftl
│ └─ src/main/java/<basePackage>/{common,config,security,system}/
├─ myapp-biz-purchase/ # 每个 menuGroup 一个(biz 模块)
│ ├─ pom.xml # multi-module/biz/pom.xml.ftl,依赖 myapp-system
│ └─ src/main/java/<basePackage>/biz/purchase/{entity,mapper,service,...}/
├─ myapp-biz-warehouse/ # 另一个 group
│ └─ ...
└─ myapp-bootstrap/ # 启动模块(main + application.yml + 全量 SQL)
├─ pom.xml # 依赖 system + 所有 biz-<group>,含 spring-boot-maven-plugin
└─ src/main/
├─ java/<basePackage>/<AppClassName>Application.java
└─ resources/
├─ application.yml
└─ db/
├─ schema-system.sql data-system.sql
├─ schema-purchase.sql schema-warehouse.sql # 按 group 各一份
└─ data-biz.sql # 全量业务种子(集中)父 pom 模块声明
multi-module/_root/pom-parent.xml.ftl 用 bizGroups 循环生成 <modules>:
<modules>
<module>${artifactId}-system</module>
<#list bizGroups as g>
<module>${artifactId}-biz-${g.name}</module>
</#list>
<module>${artifactId}-bootstrap</module>
</modules>父 pom 继承 spring-boot-starter-parent:3.2.5,<packaging>pom</packaging>,dependencyManagement 锁定内部模块版本与第三方版本(mybatis-plus 3.5.7 / mysql-connector 8.3.0 / jjwt 0.12.6 / lombok 1.18.34),pluginManagement 配置 Lombok annotationProcessorPaths。
bootstrap pom 依赖
multi-module/bootstrap/pom.xml.ftl 依赖 system + 所有 biz-<group>,并声明 spring-boot-maven-plugin 的 mainClass:
<dependencies>
<dependency><groupId>${groupId}</groupId><artifactId>${artifactId}-system</artifactId></dependency>
<#list bizGroups as g>
<dependency><groupId>${groupId}</groupId><artifactId>${artifactId}-biz-${g.name}</artifactId></dependency>
</#list>
</dependencies>
<build><plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration><mainClass>${basePackage}.${appClassName}Application</mainClass></configuration>
</plugin>
</plugins></build>biz-<group> pom
multi-module/biz/pom.xml.ftl 只依赖 system,最轻量:
<artifactId>${artifactId}-biz-${group.name}</artifactId>
<description>业务模块:${group.title}</description>
<dependencies>
<dependency><groupId>${groupId}</groupId><artifactId>${artifactId}-system</artifactId></dependency>
</dependencies>操作步骤
- 按需选择导出模式:中小应用选
export-springboot(单体);业务域多、要按域拆模块的选export-springboot-multi(多模块)。详见 。 - 解压 zip,对照上文结构确认目录完整。
- 单体:
cd backend && mvn spring-boot:run;多模块:在*-parent执行mvn clean install -DskipTests后cd *-bootstrap && mvn spring-boot:run。 - 前端:
cd admin-ui && pnpm install && pnpm dev,访问http://localhost:3000。 - 想定制产物:改
templates/export/下对应.ftl,重启后端再导出。
常见问题
多模块下 system 模块为什么没有 application.yml / pom.xml?
多模式下,工程根级文件(pom / Application / application.yml / README / .gitignore)由 multi-module/{system,bootstrap}/ 模板单独生成。renderSystemSources 显式 continue 跳过 _resources/_root/ 与 _resources/db/,避免与 bootstrap 冲突。SQL 全部集中到 bootstrap 的 resources/db/。
多模块 biz 模块包名为什么是 group 名而不是表名?
copyWithModule(src, group) 把 entity.module 覆盖为 group(如 purchase),所以包路径是 biz/purchase/entity/PurchaseRequirement.java。这保证 Maven 模块名 myapp-biz-purchase 与包路径一致,便于按域裁剪团队。group code 来自 FoundationSchema.TableDef.businessGroup 或 ErpSchema 的定义。
groupTitle 中文映射在哪里
AppExportService.groupTitle(String) 静态方法硬编码了 group -> 中文名映射:purchase->采购管理、sale->销售管理、hr->人事管理、warehouse->仓库管理、finance->财务管理、content->内容管理、project->项目管理、disclosure->信息公开、recruit->招聘管理、leads->线索管理、config->站点配置、misc->其它业务。新增业务域需同步改这里。
想给导出工程加自定义 Java 类
放到 templates/export/system-module/ 对应包目录下(带 .ftl 后缀,即使不引用变量也要 .ftl 才会被渲染;纯静态文件可不带后缀,会被原样拷贝)。多模块下记得这些类会进 system 子模块,bootstrap 才是启动入口。
