From 830fd72e8b5de1ef6d84ee0dd824af2e428a5c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moshow=E9=83=91=E9=94=B4?= Date: Tue, 2 Jun 2026 23:53:45 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6=20=E6=96=B0=E5=A2=9E"=E4=B8=80?= =?UTF-8?q?=E9=94=AE=20ZIP=20=E6=89=93=E5=8C=85=E4=B8=8B=E8=BD=BD"?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 711 ++++++++++-------- REFACTORING_DOCUMENT.md | 217 ------ UNIT_TEST_DOCUMENT.md | 192 ----- .../controller/CodeGenController.java | 85 ++- .../generator/entity/dto/CodeGenResult.java | 37 + .../generator/service/CodeGenService.java | 24 +- .../system/generator/service/ZipService.java | 27 + .../service/impl/CodeGenServiceImpl.java | 98 ++- .../service/impl/ZipServiceImpl.java | 96 +++ .../generator/util/ZipFileNameResolver.java | 148 ++++ src/main/resources/statics/js/main.js | 48 ++ src/main/resources/template.json | 149 ++-- src/main/resources/templates/newui2.html | 1 + .../controller/CodeGenControllerTest.java | 69 +- .../generator/service/CodeGenServiceTest.java | 14 +- .../generator/service/ZipServiceImplTest.java | 154 ++++ .../util/ZipFileNameResolverTest.java | 109 +++ 17 files changed, 1345 insertions(+), 834 deletions(-) delete mode 100644 REFACTORING_DOCUMENT.md delete mode 100644 UNIT_TEST_DOCUMENT.md create mode 100644 src/main/java/com/softdev/system/generator/entity/dto/CodeGenResult.java create mode 100644 src/main/java/com/softdev/system/generator/service/ZipService.java create mode 100644 src/main/java/com/softdev/system/generator/service/impl/ZipServiceImpl.java create mode 100644 src/main/java/com/softdev/system/generator/util/ZipFileNameResolver.java create mode 100644 src/test/java/com/softdev/system/generator/service/ZipServiceImplTest.java create mode 100644 src/test/java/com/softdev/system/generator/util/ZipFileNameResolverTest.java diff --git a/README.md b/README.md index fcebc7c..5b26bd7 100644 --- a/README.md +++ b/README.md @@ -1,321 +1,390 @@ -# SpringBootCodeGenerator 大狼狗代码生成器 ----- -又名`Java代码生成器`、`JAVA在线代码生成平台`、`sql转java`、`大狼狗代码生成器`、`mybatis在线生成器`、`SQL转Java JPA、MYBATIS实现类代码生成平台`
-![image](https://img.shields.io/badge/SpringBoot3-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-blue.svg) -![image](https://img.shields.io/badge/Freemarker-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-blue.svg) -![image](https://img.shields.io/badge/CodeGenerator-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-blue.svg) -[![Java CI with Maven](https://github.com/moshowgame/SpringBootCodeGenerator/actions/workflows/maven.yml/badge.svg)](https://github.com/moshowgame/SpringBootCodeGenerator/actions/workflows/maven.yml) - -# Author ->🚀 -Powered by `Moshow郑锴(大狼狗)` 🌟 Might the holy code be with you ! ->
**`CSDN`传送门**️️➡️ [https://zhengkai.blog.csdn.net](https://zhengkai.blog.csdn.net) ->
**微信公众号**➡️`软件开发大百科` - -# Description -本项目是基于 Spring Boot 3 和 Freemarker 的高效代码生成平台,旨在帮助开发者告别繁琐重复的 CRUD 操作,释放双手,让开发更高效。项目支持主流数据库(MySQL、Oracle、PgSQL)和多种模板(JPA、Mybatis、MybatisPlus 等)。 -> 🚀 `Spring Boot Code Generator` — a powerful code generation platform built on SpringBoot3 & Freemarker -> ✨ 基于 `SpringBoot3` 和 `Freemarker` 的高效代码生成平台 - -> 👐 Say goodbye to repetitive CRUD work — free your hands and boost productivity -> 💡 告别繁琐重复的 CRUD 操作,释放你的双手,让开发更高效! - -> 🛠️ Supports MySQL, Oracle, and PostgreSQL — the most popular SQL dialects -> 📦 支持主流数据库:`MySQL`、`Oracle`、`PgSQL`,标准 SQL 一网打尽 - -> ⚙️ Generate templates from DDL, INSERT SQL, SELECT SQL, or simple JSON — covering JPA, JdbcTemplate, Mybatis, MybatisPlus, BeetlSQL, CommonMapper -> 🧩 通过建表 DDL、插入 SQL、选择 SQL 或简单 JSON,一键生成 `JPA/JdbcTemplate/Mybatis/MybatisPlus/BeetlSQL/CommonMapper` 等模板代码 - -> 🙏 Thanks for your continued support! BeJSON once peaked at 1.5K daily PV 👀, and now maintains a steady flow of around 600 visits — plus 2K+ GitHub Stars ✨. Your feedback remains our greatest motivation to keep improving! -> ❤️ 感谢大家一直以来的支持!BeJSON 曾创下日均访问量 1.5K 👀 的高峰,目前稳定在约 600 左右,GitHub Star 数也已突破 2K ✨。你们的反馈始终是我们不断前进的最大动力! - -> 🌈 Wishing everyone balance, health, and success — may your code be bug-free and your coffee strong ☕ -> 💬 祝大家工作顺利,生活平衡,身体健康,步步高升,代码无 bug,咖啡够劲! - -> 📬 Feel free to submit issues, share useful templates, or contribute your brilliant ideas via PR -> 🤝 欢迎提交问题、分享常用模板,或将你的灵感通过 PR 实现! - -> 🙌 Special thanks to BeJSON 前站长 `三叔` 的慧眼与支持,让项目得以脱颖而出,感恩! - - - -## 功能特性 - -### 支持多种生成模式 -- DDL SQL 模式:通过建表语句生成代码 -- INSERT SQL 模式:通过插入语句生成代码 -- SELECT SQL 模式:通过查询语句生成代码 -- JSON 模式:通过 JSON 数据生成代码 - -### 支持多种模板 -- JPA 模板 -- MyBatis 模板 -- MyBatis-Plus 模板 -- BeetlSQL 模板 -- CommonMapper 模板 -- TkMyBatis 模板 -- JDBC Template 模板 -- 前端 UI 模板(Element UI、Bootstrap UI 等) - -### 其他特性 -- 自动记忆最近生成的内容 -- 支持特殊字符模板(# 用 井 代替,$ 用 ¥ 代替) -- 可设置表名前缀 -- 可选择是否自动引包 -- 支持本地/CDN 静态资源引入模式切换 - -## 技术栈 - -- Spring Boot 3 -- Freemarker 模板引擎 -- FastJSON2 -- JSqlParser SQL 解析器 -- Lombok 简化代码工具 - -## 使用说明 - -### 启动项目 - -```bash -# 克隆项目 -git clone https://github.com/moshowgame/SpringBootCodeGenerator.git - -# 进入项目目录 -cd SpringBootCodeGenerator -# 编译项目 -mvn clean compile -# 运行项目 -mvn spring-boot:run - -# 访问项目 -http://localhost:1234/generator - -# 打包项目(不验证单元测试) -mvn clean package -DskipTests - -# 运行测试 -mvn test -# 查看JaCoCo测试覆盖率 -cd /target/site/jacoco -``` - -### 添加新模板 - -1. 在 `resources/templates/code-generator` 目录中找到对应类型 -2. 复制并编写 Freemarker 模板文件(.ftl) -3. 修改 `template.json` 文件,新增模板信息 - -### 配置说明 - -| **配置项** | **说明** | **默认值** | -|:----|:----|:----| -| 作者 | authorName | zhengkai.blog.csdn.net | -| 包名 | packageName | cn.devtools | -| 返回(成功) | returnUtilSuccess | Return.SUCCESS | -| 返回(失败) | returnUtilFailure | Return.ERROR | -| 忽略前缀 | ignorePrefix | sys_ | -| 输入类型 | dataType | DDL SQL | -| TinyInt转换 | tinyintTransType | int | -| 时间类型 | timeTransType | Date | -| 命名类型 | nameCaseType | CamelCase/驼峰 | -| 是否包装类型 | isPackageType | true | -| 是否swaggerUI | isSwagger | false | -| 是否字段注释 | isComment | true | -| 是否自动引包 | isAutoImport | | -| 是否带包路径 | isWithPackage | | -| 是否Lombok | isLombok | true | - -| **模板变量** | **说明** | -|:-------------|:---------------| -| tableName | sql中的表名 | -| className | java类名 | -| classComment | sql表备注/java类备注 | -| fieldName | 字段名 | -| fieldComment | 字段备注 | - - - -## 重构2025说明 - -本项目的重构2025在原有基础上进行了现代化重构,优化了项目结构和代码组织,使其更符合现代 Spring Boot 应用的最佳实践。 - -### 重构亮点 - -1. **清晰的分层架构**:采用 Controller-Service-DTO-VO 分层设计,各层职责明确 -2. **接口与实现分离**:服务层采用接口与实现分离的设计,便于测试和扩展 -3. **策略模式应用**:使用策略模式处理不同类型的 SQL 解析,易于扩展新的解析方式 -4. **现代化开发规范**:遵循 Spring Boot 和 Java 开发最佳实践 -5. **完善的异常处理**:统一异常处理机制,提供更友好的错误提示 - -### 重构后项目结构 - -``` -com.softdev.system.generator -├── GeneratorApplication.java # 启动类 -├── config # 配置类包 -│ ├── WebMvcConfig.java # MVC配置 -│ └── GlobalExceptionHandler.java # 全局异常处理器 -├── controller # 控制层 -│ ├── PageController.java # 页面跳转控制器 -│ ├── CodeGenController.java # 代码生成相关接口 -│ └── TemplateController.java # 模板相关接口 -├── service # 服务层接口 -│ ├── CodeGenService.java # 代码生成服务接口 -│ ├── TemplateService.java # 模板服务接口 -│ └── parser -│ ├── SqlParserService.java # SQL解析服务接口 -│ └── JsonParserService.java # JSON解析服务接口 -├── service.impl # 服务实现层 -│ ├── CodeGenServiceImpl.java # 代码生成服务实现 -│ ├── TemplateServiceImpl.java # 模板服务实现 -│ └── parser -│ ├── SqlParserServiceImpl.java # SQL解析服务实现 -│ └── JsonParserServiceImpl.java # JSON解析服务实现 -├── entity # 实体类 -│ ├── dto -│ │ ├── ParamInfo.java # 参数信息DTO -│ │ ├── ClassInfo.java # 类信息DTO -│ │ └── FieldInfo.java # 字段信息DTO -│ ├── vo -│ │ └── ResultVo.java # 统一返回结果VO -│ └── enums -│ └── ParserTypeEnum.java # 解析类型枚举 -├── util # 工具类包 -│ ├── FreemarkerUtil.java # Freemarker工具类 -│ ├── StringUtilsPlus.java # 字符串工具类 -│ ├── MapUtil.java # Map工具类 -│ ├── mysqlJavaTypeUtil.java # MySQL类型转换工具类 -│ └── exception -│ ├── CodeGenException.java # 自定义业务异常 -│ └── SqlParseException.java # SQL解析异常 -└── constant # 常量定义 - └── CodeGenConstants.java # 代码生成常量(待实现) -``` - -### 统一响应格式 - -所有控制器方法均返回 ResultVo 统一响应对象,保持与前端的兼容性: - -```java -// 成功响应 -ResultVo.ok(data); - -// 错误响应 -ResultVo.error(message); -``` - -## 重构优势 - -1. **结构清晰**:通过合理的包结构和分层设计,使项目结构更加清晰易懂 -2. **易于维护**:各层职责明确,便于定位和修复问题 -3. **易于扩展**:采用策略模式等设计模式,便于添加新的功能模块 -4. **现代化**:遵循 Spring Boot 和 Java 的最新最佳实践 -5. **前后端兼容**:保持与现有前端代码的数据交互格式,无缝升级 - -## 升级问题解决方案 - -### FastJSON 升级到 FastJSON2 - -如果在升级 FastJSON 到 FastJSON2 版本时遇到 FastJsonHttpMessageConverter 找不到类问题以及 FastJsonConfig 找不到问题,需要安装以下类库: -- fastjson2 -- fastjson2-extension -- fastjson2-extension-spring6 - -### Spring Boot 3 升级 - -当项目从 Spring Boot 2.x 升级到 3.x 时,可能会遇到 "java: 程序包 javax.servlet.http 不存在" 问题,这是因为 Spring Boot 3 使用了 Jakarta EE 9+,包名从 javax.* 变更为 jakarta.*。 - - -## 版权信息 - -本项目遵循相关开源协议,欢迎提交问题、分享常用模板,或将你的灵感通过 PR 实现! - -## Stargazers over time -[![Stargazers over time](https://starchart.cc/moshowgame/SpringBootCodeGenerator.svg?variant=adaptive)](https://starchart.cc/moshowgame/SpringBootCodeGenerator) - - -配置模板
- -网站流量分析-2024
- -代码与你,越变越强
- - -# Update Logs -| 更新日期 | 更新内容 | -|:-----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 2025.12.09 | 优化Mybatis和Mybatis-Plus模板 | -| 2025.12.08 | 引入单元测试和JaCoCo测试覆盖率,优化代码覆盖率 [UNIT_TEST_DOCUMENT.md](UNIT_TEST_DOCUMENT.md) | -| 2025.12.07 | 后端重构优化![REFACTORING_DOCUMENT.md](REFACTORING_DOCUMENT.md) ;目录结构调整! | -| 2025.09.14 | 优化JSqlParser Engine(DDL Create SQL和Select SQL),适配更高级复杂的SQL | -| 2025.09.13 | JSqlParser Engine全新升级,目前Select SQL模式相对稳定!
更新SpringBoot等类库版本,修复漏洞
修复CDN问题,切换为staticfile.org | -| 2025.09.06 | 处理建表字段包含 using 字符时无法生成对应字段的情况(感谢@wubiaoo的反馈和@willxiang的PR) | -| 2025.03.31 | 优化说明 | -| 2025.03.16 | NewUI V2前端优化:
移除不必要内容,优化Local和CDN静态文件引入。

修复由于SQL类型大写导致无法转换的问题。(感谢@zzy-design的反馈)

JPA模板优化(感谢@PenroseYang的反馈):
修复不开启Lombok情况下Set/Get方法生成问题;
修复importDdate判断为true后没有引入日期类的问题
| -| 2024.12.29 | 优化前端加载速度,优化输出代码着色,CDN改字节跳动静态资源公共库。
| -| 2024.12.23 | 新增InsertSQL模式,采用JSQLParser引擎进行封装
优化代码封装
CDN恢复为staticfile.org加速(如果本地卡的话,建议切换local模式)。
| -| 2024.04.23 | 切换为更快更稳定的BootCDN进行加速。
前端NEWUI改版(基于AdminLTE+Bootstrap+Vue+ElementUI混合模式)。 | -| 2024.04.22 | [Java CI with Maven](https://github.com/moshowgame/SpringBootCodeGenerator/actions/workflows/maven.yml) 更新
SpringBoot升级到3.2.5
FastJSON升级到FastJSON2.0.49 | -| 2024.04.21 | 推出JDK11分支,支持JDK8/JDK11/JDK17等版本,兼容性较好但维护速度较慢,为了更好兼容旧机器和旧环境 | -| 2024.04.20 | 修复CDN版本cdn.staticfile.org域名备份失败问题,已同步更新到cdn.staticfile.net(本地版本则不受影响) | -| 2024.01.26 | 修复大写下滑线列名转驼峰问题(感谢@Nisus-Liu的PR) | -| 2023.10.22 | 工具站CDN更新。 | -| 2023.08.31 | (感谢@Nisus-Liu的PR)
fix 驼峰列名转命名风格错误问题
增强转下划线命名风格, 对原始风格不敏感. 支持各种命名风格的列名 to 下划线
增加 NonCaseString 大小写不敏感字符串包装类, 简化编码
几点代码小优化。 | -| 2023.07.11 | 安全更新,正式支持SpringBoot3,javax升级到jakarta。 | -| 2023.01.02 | 新增TkMybatis模板(感谢@sgj666的建议)。 | -| 2023.01.01 | 新增GCP BigQuery/Dataflow JJS/QlikSense BI模板。 | -| 2022.09.28 | MySQL to Java type conversion 数据库类型转换优化(感谢@jadelike得贡献) | -| 2022.07.02 | add the script to install and run,添加批处理以便直接构建或运行项目。 | -| 2022.02.10 | 更新springboot、fastjson、lombok依赖(感谢@Abbykawai的建议)。 | -| 2022.02.09 | 新增JPA-STARP模板(感谢@starplatinum3的贡献)。 | -| 2022.01.11 | 优化mybatis的mapper文件生成(感谢@chendong的贡献)。 | -| 2021.10.31 | 优化当有索引和额外的换行时的解析逻辑(感谢@feitian124的贡献)。
修复部分模板参数不对应(感谢@Thixiaoxiao的贡献)。
新增cookie记录所需配置字段逻辑,避免重复配置(感谢@Thixiaoxiao的贡献)。 | -| 2021.08.07 | 新增当前模板保持功能,重新生成代码后依然会保持在当前选择模板。
新增renren-fast模板。 | -| 2021.08.05 | 解决 update 方法语法错误;调整部分语句避免sonarLint告警(感谢@Henry586的PR);
add swagger-yml.ftl(感谢@fuuqiu的PR);
支持common-mapper&修复entity和plusentity的swagger引包错误(感谢@chentianming11的PR) | -| 2021.03.24 | 修复Mybatis.XML中缺失test=关键字问题。(感谢@BWHN/YUEHUI的反馈)。 | -| 2021.01.18 | OEM信息优化,支持多配置文件模式,支持在application*.yml自定义信息,以及切换local/cdn模式。 | -| 2021.01.17 | 生成后自动trim掉前后空格输出。
完善ReadMe文档。
优化云CDN引入部分。
优化returnUtil部分。
表明前缀选项(感谢@wwlg的建议)。
是否带字段注释设置(感谢@fengpojian的建议)。
优化Mybatis的''!=判断(感谢@zhongsb的建议)。
Mybatis-Plus增加Service层(感谢@yf466532479的建议)。 | -| 2021.01.16 | 全新3.0版本:
一、前端半vue半js化,更多动态加载项。
二、支持更多生成设置,优化生成场景。
三、js导入支持本地/CDN模式,支持断网环境轻松使用。 | -| 2020.10.22 | 1.tinyint多加一个Short类型转换(感谢@wttHero的建议) | -| 2020.10.20 | 1.修复mapper2 insert代码问题(感谢@mXiaoWan的PR)
2.优化对fulltext/index关键字的处理(感谢@WEGFan的反馈)。
3.新增日期类型的转换选择(感谢@qingkediguo的建议)。
4.新增是否包装类型的转换选择(感谢@gzlicanyi的建议)。 | -| 2020.06.28 | 优化Util下的BeanUtil,支持更多map.put的操作。整合CRUD模板到SQL(CRUD)模板。 | -| 2020.06.21 | 修复FreemarkerUtil的Path问题导致JAR包运行时无法获取template的问题。 | -| 2020.05.25 | 1.一些fix,关于封装工具类以及layui模板优化等.
2.优化表备注的获取逻辑.
3.生成时间格式改为yyyy-MM-dd,移除具体的时间,只保留日期 | -| 2020.05.22 | 1.新增insert-sql模式,支持对"insert into table (xxx) values (xxx)"语句进行处理,生成java代码(感谢三叔的建议). | -| 2020.05.17 | 1.代码重构!异常处理优化,Freemarker相关工具类优化,简化模板生成部分,通过template.json来配置需要生成的模板,不需要配置java文件.
2.修复包含comment关键字时注释无法识别的问题.(感谢@1nchaos的反馈).
3.赞赏优化,感谢大家的赞赏.
4.新增mapper2(Mybatis-Annotation模板)(感谢@baisi525和@CHKEGit的建议). | -| 2020.05.03 | 1.优化对特殊字符的处理,对于包含#和$等特殊字符的,在模板使用井和¥代替便可,escapeString方法会自动处理.
2.优化mybatisplus实体类相关(感谢@chunchengmeigui的反馈).
3.修优化对所有类型的判断(感谢@cnlw的反馈).
4.移除swagger-entity,该功能已经包含在‘swagger-ui’的下拉选项中
5.升级hutool和lombok版本 | -| 2020.03.06 | 1.提交一套layuimini+mybatisplus的模板.
2.修复mybatisplus一些相关问题. | -| 2020.02.06 | 1.新增历史记录功能,自动保存最近生成的对象.
2.新增swagger开关选项和修复@Column带name参数(感谢@liuyu-struggle的建议).
3.去除mybatis模板中的方括号[]和修改模板里的类注释样式(感谢@gaohanghang的PR) | -| 2019.12.29 | 1.修复bejson安全防护策略拦截问题(感谢@liangbintao和@1808083642的反馈).
2.优化字段名含date字符串的处理(感谢@smilexzh的反馈).
3.控制台动态输出项目访问地址(感谢@gaohanghang的提交) | -| 2019.11.28 | 1.修复支持string-copy导致的以n结尾的字母不显示问题.
2.jpa-entity新增swagger@ApiModel@ApiModelProperty注解和SQL字段@Column注解(感谢@yjq907的建议) | -| 2019.11.26 | 1.springboot2内置tomcat更换为性能更强大的undertow.
2.修复tinyintTransType参数丢失问题 | -| 2019.11.24 | 1.java代码结构优化.
2.新增简单的json生成模式.
3.新增简单的正则表达式匹配模式(感谢@ydq的贡献).
4.新增对复制String代码中的乱SQL代码的支持 5.优化对JSON的父子节点/处理,JSONObject和JSONArray节点处理,子节点缺失'{'头处理 | -| 2019.11.23 | 1.移除频繁出错和被过滤的layer,改为jquery-toast.
2.Util功能优化,新增json和xml. | -| 2019.11.16 | 优化对primary关键字的处理(感谢@liujiansgit的反馈). | -| 2019.11.15 | 1.添加tinyint类型转换(感谢@lixiliang&@liujiansgit的Suggestion).
2.添加一键复制功能(感谢@gaohanghang的Suggestion).
3.Mybatis的insert增加keyProperty="id"用于返回自增id(感谢@88888888888888888888的Suggestion).
4.优化date类型的支持(感谢@SteveLsf的反馈).
5.其他一些优化. | -| 2019.10.15 | 修复jdbcTemplates中insert语句第一个字段丢失的问题. | -| 2019.09.15 | 1.添加对象getset模板.
2.添加sql模板.
3.启动类添加日志输出,方便项目使用(感谢@gaohanghang 的pull request) | -| 2019.09.10 | 优化以及更新Maven依赖,减少打包体积.
1.修复mapper接口load方法,但是xml中方法不匹配问题.
2.移除mapper中CRUD时的@param 注解,会影响xml的解析(感谢@caojiantao的反馈).
3.优化MyBatis的xml文件对Oracle的支持.(感谢@wylove1992的反馈).
4.新增对boolean的处理(感谢@violinxsc的反馈)以及优化tinyint类型生成boolean类型问题(感谢@hahaYhui的反馈) | -| 2019.09.09 | 添加是否下划线转换为驼峰的选择(感谢@youngking28 的pull request). | -| 2019.05.18 | 1.优化注释.
2.修改 mybatis模板中 controller注解.
3.修改 mybatis模板中 dao文件使用为 mapper文件.
4.修改 mybatis模板中 service实现类中的一个 bug.
5.修改 index.ftl文件中 mybatis模板的 dao -> mapper(感谢@unqin的pull request) | -| 2019.05.11 | 优化mybatis模块的dao和xml模板,修改dao接口注解为@Repository,所有dao参数改为包装类,删除update语句最后的UpdateTime = NOW(),修改dao接口文件的方法注释使其更符合javaDoc的标准,修改insert语句增加插入行主键的返回,修改load的方法名为selectByPrimaryKey,修改xml的update语句新增动态if判空,修改xml的insert语句新增动态插入判空,更符合mybatisGenerator标准(感谢@Archer-Wen的贡献 ). | -| 2019.04.29 | 新增返回封装工具类设置.
优化对oracle注释comment on column的支持(感谢@liukex反馈).
优化对普通和特殊storage关键字的判断(感谢@AhHeadFloating的反馈 ). | -| 2019.02.11 | 提交gitignore,解决StringUtils.lowerCaseFirst潜在的NPE异常,校验修改为@RequestParam参数校验,lombok之@Data和@Slf4j优化,fix JdbcDAO模板类名显示为中文问题,WebMvcConfig整合MessageConverter,模板代码分类(感谢@liutf和@tfgzs的pull request). | -| 2019.02.10 | 实体生成规则切换为包装类型,不再采用基本数据类型,为实体类生成添加显示的默认构造方法(感谢@h2so的pull request). | -| 2019.01.06 | 修复处理number/decimal(x,x)类型的逻辑(感谢@arthaschan的反馈).
修复JdbcTemplates模板两处错误(感谢@everflourish的反馈). | -| 2018.12.12 | 首页UI优化.
新增MybatisPlus模块(感谢@三叔同事的建议).
修复作者名和包名获取失败问题(感谢@Yanch1994的反馈). | -| 2018.11.22 | 优化正则表达式点号的处理,优化处理字段类型,对number类型增加int,long,BigDecimal的区分判断(感谢@lshz0088的指导). | -| 2018.11.08 | 修复非字段描述"KEY FK_xxxx (xxxx)"导致生成KEY字段情况(感谢@tornadoorz反馈). | -| 2018.10.18 | 支持double(x,x)的类型,以及comment里面包含一些特殊字符的处理(感谢@tanwubo的反馈). | -| 2018.10.10 | CDN变更,修复CDN不稳定导致网页js报错问题. | -| 2018.10.03 | 新增element-ui/bootstrap生成. | -| 2018.10.02 | 修复公共CDN之Layer.js404问题,导致项目无法生成. | -| 2018.09.27 | 优化COMMENT提取逻辑,支持多种复杂情况的注释(感谢@raodeming的反馈). | -| 2018.09.26 | 全新BeetlSQL模块,以及一些小细节优化(感谢@三叔同事的建议). | -| 2018.09.25 | 优化SQL表和字段备注的推断,包括pgsql/oralce的comment on column/table情况处理等. | -| 2018.09.18 | 优化SQL类型推断.
优化PrimaryKey判断.
修复jpacontroller中Repository拼写错误问题. | -| 2018.09.17 | 全新首页,静态文件全部采用CDN.新增jdbcTemplate模块. | -| 2018.09.16 | 1.优化oracle支持,优化DDL语句中"或者'或者空格的支持.
2.补充char/clob/blob/json等类型,如果类型未知,默认为String. | -| 2018.09.15 | 新增Swagger-UI模板.修复一些命名和导入问题.JPA的Entity默认第一个字段为Id,如果不是请手工修改. | -| 2018.09.13 | 修复字段没有描述以及类型为DATE型导致的问题.新增JPA的Controller模板. | -| 2018.08.31 | 初始化项目.新增JPA系列Entity+Repository模板. | +# SpringBootCodeGenerator 大狼狗代码生成器 + +*** + +又名`Java代码生成器`、`JAVA在线代码生成平台`、`sql转java`、`大狼狗代码生成器`、`mybatis在线生成器`、`SQL转Java JPA、MYBATIS实现类代码生成平台` +![image](https://img.shields.io/badge/SpringBoot3-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-blue.svg) +![image](https://img.shields.io/badge/Freemarker-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-blue.svg) +![image](https://img.shields.io/badge/CodeGenerator-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-blue.svg) +[![Java CI with Maven](https://github.com/moshowgame/SpringBootCodeGenerator/actions/workflows/maven.yml/badge.svg)](https://github.com/moshowgame/SpringBootCodeGenerator/actions/workflows/maven.yml) + +# Author + +> 🚀 +> Powered by `Moshow郑锴(大狼狗)` 🌟 Might the holy code be with you ! +> **`CSDN`传送门**️️➡️ +> **微信公众号**➡️`软件开发大百科` + +# Description + +本项目是基于 Spring Boot 3 和 Freemarker 的高效代码生成平台,旨在帮助开发者告别繁琐重复的 CRUD 操作,释放双手,让开发更高效。项目支持主流数据库(MySQL、Oracle、PgSQL)和多种模板(JPA、Mybatis、MybatisPlus 等),并支持一键 ZIP 打包下载,开箱即用。 + +> 🚀 `Spring Boot Code Generator` — a powerful code generation platform built on SpringBoot3 & Freemarker\ +> ✨ 基于 `SpringBoot3` 和 `Freemarker` 的高效代码生成平台 + +> 👐 Say goodbye to repetitive CRUD work — free your hands and boost productivity\ +> 💡 告别繁琐重复的 CRUD 操作,释放你的双手,让开发更高效! + +> 🛠️ Supports MySQL, Oracle, and PostgreSQL — the most popular SQL dialects\ +> 📦 支持主流数据库:`MySQL`、`Oracle`、`PgSQL`,标准 SQL 一网打尽 + +> ⚙️ Generate templates from DDL, INSERT SQL, SELECT SQL, or simple JSON — covering JPA, JdbcTemplate, Mybatis, MybatisPlus, BeetlSQL, CommonMapper\ +> 🧩 通过建表 DDL、插入 SQL、选择 SQL 或简单 JSON,一键生成 `JPA/JdbcTemplate/Mybatis/MybatisPlus/BeetlSQL/CommonMapper` 等模板代码 + +> 📦 **One-click ZIP download** — package all generated code into a structured ZIP in one click\ +> 📦 **一键 ZIP 打包下载** — 按模板分组自动归档,告别逐个文件复制 + +> 🙏 Thanks for your continued support! BeJSON once peaked at 1.5K daily PV 👀, and now maintains a steady flow of around 600 visits — plus 2K+ GitHub Stars ✨. Your feedback remains our greatest motivation to keep improving! +> ❤️ 感谢大家一直以来的支持!BeJSON 曾创下日均访问量 1.5K 👀 的高峰,目前稳定在约 600 左右,GitHub Star 数也已突破 2K ✨。你们的反馈始终是我们不断前进的最大动力! + +> 🌈 Wishing everyone balance, health, and success — may your code be bug-free and your coffee strong ☕\ +> 💬 祝大家工作顺利,生活平衡,身体健康,步步高升,代码无 bug,咖啡够劲! + +> 📬 Feel free to submit issues, share useful templates, or contribute your brilliant ideas via PR\ +> 🤝 欢迎提交问题、分享常用模板,或将你的灵感通过 PR 实现! + +> 🙌 Special thanks to BeJSON 前站长 `三叔` 的慧眼与支持,让项目得以脱颖而出,感恩! + + + +## 功能特性 + +### 支持多种生成模式 + +- DDL SQL 模式:通过建表语句生成代码 +- INSERT SQL 模式:通过插入语句生成代码 +- SELECT SQL 模式:通过查询语句生成代码 +- JSON 模式:通过 JSON 数据生成代码 + +### 支持多种模板 + +- JPA 模板 +- MyBatis 模板 +- MyBatis-Plus 模板 +- BeetlSQL 模板 +- CommonMapper 模板 +- TkMyBatis 模板 +- JDBC Template 模板 +- 前端 UI 模板(Element UI、Bootstrap UI 等) + +### 其他特性 + +- 自动记忆最近生成的内容 +- 支持特殊字符模板(# 用 井 代替,$ 用 ¥ 代替) +- 可设置表名前缀 +- 可选择是否自动引包 +- 支持本地/CDN 静态资源引入模式切换 +- **📦 一键 ZIP 打包下载**:将本次生成的全部代码按模板分组打成 ZIP 一键下载 + +## 技术栈 + +- Spring Boot 3 +- Freemarker 模板引擎 +- FastJSON2 +- JSqlParser SQL 解析器 +- Lombok 简化代码工具 + +## 使用说明 + +### 启动项目 + +```bash +# 克隆项目 +git clone https://github.com/moshowgame/SpringBootCodeGenerator.git + +# 进入项目目录 +cd SpringBootCodeGenerator +# 编译项目 +mvn clean compile +# 运行项目 +mvn spring-boot:run + +# 访问项目 +http://localhost:1234/generator + +# 打包项目(不验证单元测试) +mvn clean package -DskipTests + +# 运行测试 +mvn test +# 查看JaCoCo测试覆盖率 +cd /target/site/jacoco +``` + +### 添加新模板 + +1. 在 `resources/templates/code-generator` 目录中找到对应类型 +2. 复制并编写 Freemarker 模板文件(.ftl) +3. 修改 `template.json` 文件,新增模板信息 + +### 📦 一键打包下载 + +在主界面"生成"按钮旁边新增了一个独立的 **下载 ZIP** 按钮,点击后将本次生成的全部代码按模板 `group` 自动分目录打包成 ZIP 下载,无需逐个文件复制。 + +#### 特性 + +- **自动目录分组**:例如 `mybatis/UserInfoController.java`、`ui/UserInfo-element-ui.html`,结构清晰 +- **文件名模板化**:在 `template.json` 中通过 `fileName` 字段定义,支持 `${className}` / `${tableName}` 等占位符 +- **重名自动去重**:相同文件名会自动加序号(如 `UserInfo_1.java`) +- **中文文件名兼容**:使用 RFC 5987 `filename*` 编码,避免乱码 +- **零依赖**:使用 JDK 自带 `ZipOutputStream` 实现,不引入额外依赖 + +#### 后端接口 + +``` +POST /code/generate-zip +Content-Type: application/json +``` + +请求体与 `/code/generate` 一致,返回 `application/zip` 字节流,响应头携带 `Content-Disposition: attachment; filename="...zip"; filename*=UTF-8''...`。 + +#### 自定义文件名 + +编辑 `src/main/resources/template.json`,为模板条目添加 `fileName` 字段: + +```json +{ + "id": "20", + "name": "controller", + "description": "controller", + "fileName": "${className}Controller.java" +} +``` + +支持的占位符: + +- `${className}`:Java 类名(如 `UserInfo`) +- `${tableName}`:原始表名(如 `t_user_info`) +- 未填写 `fileName` 时,会根据模板 `group` / `name` 智能推断后缀(`.java` / `.xml` / `.html` / `.sql` 等) + +#### 示例输出结构 + +``` +UserInfo.zip +├── mybatis/ +│ ├── UserInfoController.java +│ ├── UserInfo.java +│ ├── UserInfoMapper.xml +│ └── UserInfoService.java +├── jpa/ +│ └── UserInfo.java +├── ui/ +│ └── UserInfo-element-ui.html +└── sql/ + └── t_user_info.sql +``` + +### 配置说明 + +| **配置项** | **说明** | **默认值** | +| :---------- | :---------------- | :--------------------- | +| 作者 | authorName | zhengkai.blog.csdn.net | +| 包名 | packageName | cn.devtools | +| 返回(成功) | returnUtilSuccess | Return.SUCCESS | +| 返回(失败) | returnUtilFailure | Return.ERROR | +| 忽略前缀 | ignorePrefix | sys\_ | +| 输入类型 | dataType | DDL SQL | +| TinyInt转换 | tinyintTransType | int | +| 时间类型 | timeTransType | Date | +| 命名类型 | nameCaseType | CamelCase/驼峰 | +| 是否包装类型 | isPackageType | true | +| 是否swaggerUI | isSwagger | false | +| 是否字段注释 | isComment | true | +| 是否自动引包 | isAutoImport |
| +| 是否带包路径 | isWithPackage |
| +| 是否Lombok | isLombok | true | + +| **模板变量** | **说明** | +| :----------- | :------------- | +| tableName | sql中的表名 | +| className | java类名 | +| classComment | sql表备注/java类备注 | +| fieldName | 字段名 | +| fieldComment | 字段备注 | + +## 重构2025说明 + +本项目的重构2025在原有基础上进行了现代化重构,优化了项目结构和代码组织,使其更符合现代 Spring Boot 应用的最佳实践。 + +### 重构亮点 + +1. **清晰的分层架构**:采用 Controller-Service-DTO-VO 分层设计,各层职责明确 +2. **接口与实现分离**:服务层采用接口与实现分离的设计,便于测试和扩展 +3. **策略模式应用**:使用策略模式处理不同类型的 SQL 解析,易于扩展新的解析方式 +4. **现代化开发规范**:遵循 Spring Boot 和 Java 开发最佳实践 +5. **完善的异常处理**:统一异常处理机制,提供更友好的错误提示 + +### 重构后项目结构 + +``` +com.softdev.system.generator +├── GeneratorApplication.java # 启动类 +├── config # 配置类包 +│ ├── WebMvcConfig.java # MVC配置 +│ └── GlobalExceptionHandler.java # 全局异常处理器 +├── controller # 控制层 +│ ├── PageController.java # 页面跳转控制器 +│ ├── CodeGenController.java # 代码生成相关接口 +│ └── TemplateController.java # 模板相关接口 +├── service # 服务层接口 +│ ├── CodeGenService.java # 代码生成服务接口 +│ ├── TemplateService.java # 模板服务接口 +│ └── parser +│ ├── SqlParserService.java # SQL解析服务接口 +│ └── JsonParserService.java # JSON解析服务接口 +├── service.impl # 服务实现层 +│ ├── CodeGenServiceImpl.java # 代码生成服务实现 +│ ├── TemplateServiceImpl.java # 模板服务实现 +│ └── parser +│ ├── SqlParserServiceImpl.java # SQL解析服务实现 +│ └── JsonParserServiceImpl.java # JSON解析服务实现 +├── entity # 实体类 +│ ├── dto +│ │ ├── ParamInfo.java # 参数信息DTO +│ │ ├── ClassInfo.java # 类信息DTO +│ │ └── FieldInfo.java # 字段信息DTO +│ ├── vo +│ │ └── ResultVo.java # 统一返回结果VO +│ └── enums +│ └── ParserTypeEnum.java # 解析类型枚举 +├── util # 工具类包 +│ ├── FreemarkerUtil.java # Freemarker工具类 +│ ├── StringUtilsPlus.java # 字符串工具类 +│ ├── MapUtil.java # Map工具类 +│ ├── mysqlJavaTypeUtil.java # MySQL类型转换工具类 +│ └── exception +│ ├── CodeGenException.java # 自定义业务异常 +│ └── SqlParseException.java # SQL解析异常 +└── constant # 常量定义 + └── CodeGenConstants.java # 代码生成常量(待实现) +``` + +### 统一响应格式 + +所有控制器方法均返回 ResultVo 统一响应对象,保持与前端的兼容性: + +```java +// 成功响应 +ResultVo.ok(data); + +// 错误响应 +ResultVo.error(message); +``` + +## 重构优势 + +1. **结构清晰**:通过合理的包结构和分层设计,使项目结构更加清晰易懂 +2. **易于维护**:各层职责明确,便于定位和修复问题 +3. **易于扩展**:采用策略模式等设计模式,便于添加新的功能模块 +4. **现代化**:遵循 Spring Boot 和 Java 的最新最佳实践 +5. **前后端兼容**:保持与现有前端代码的数据交互格式,无缝升级 + +## 升级问题解决方案 + +### FastJSON 升级到 FastJSON2 + +如果在升级 FastJSON 到 FastJSON2 版本时遇到 FastJsonHttpMessageConverter 找不到类问题以及 FastJsonConfig 找不到问题,需要安装以下类库: + +- fastjson2 +- fastjson2-extension +- fastjson2-extension-spring6 + +### Spring Boot 3 升级 + +当项目从 Spring Boot 2.x 升级到 3.x 时,可能会遇到 "java: 程序包 javax.servlet.http 不存在" 问题,这是因为 Spring Boot 3 使用了 Jakarta EE 9+,包名从 javax.\* 变更为 jakarta.\*。 + +## 版权信息 + +本项目遵循相关开源协议,欢迎提交问题、分享常用模板,或将你的灵感通过 PR 实现! + +## Stargazers over time + +[![Stargazers over time](https://starchart.cc/moshowgame/SpringBootCodeGenerator.svg?variant=adaptive)](https://starchart.cc/moshowgame/SpringBootCodeGenerator) + +配置模板 +网站流量分析-2024 +代码与你,越变越强 + +# Update Logs + +| 更新日期 | 更新内容 | +| :--------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 2026.06.02 | 📦 新增"一键 ZIP 打包下载"功能:在生成按钮旁新增独立下载按钮,按模板 group 自动分目录打包成 ZIP;
支持 `template.json` 中 `fileName` 字段(含 `${className}` 占位符),智能推断文件后缀; | +| 2025.12.09 | 优化Mybatis和Mybatis-Plus模板 | +| 2025.12.08 | 引入单元测试和JaCoCo测试覆盖率,优化代码覆盖率 [UNIT\_TEST\_DOCUMENT.md](UNIT_TEST_DOCUMENT.md) | +| 2025.12.07 | 后端重构优化![REFACTORING\_DOCUMENT.md](REFACTORING_DOCUMENT.md) ;目录结构调整! | +| 2025.09.14 | 优化JSqlParser Engine(DDL Create SQL和Select SQL),适配更高级复杂的SQL | +| 2025.09.13 | JSqlParser Engine全新升级,目前Select SQL模式相对稳定! 更新SpringBoot等类库版本,修复漏洞修复CDN问题,切换为staticfile.org | +| 2025.09.06 | 处理建表字段包含 using 字符时无法生成对应字段的情况(感谢@wubiaoo的反馈和@willxiang的PR) | +| 2025.03.31 | 优化说明 | +| 2025.03.16 | NewUI V2前端优化:移除不必要内容,优化Local和CDN静态文件引入。修复由于SQL类型大写导致无法转换的问题。(感谢@zzy-design的反馈)JPA模板优化(感谢@PenroseYang的反馈):修复不开启Lombok情况下Set/Get方法生成问题;修复importDdate判断为true后没有引入日期类的问题 | +| 2024.12.29 | 优化前端加载速度,优化输出代码着色,CDN改字节跳动静态资源公共库。 | +| 2024.12.23 | 新增InsertSQL模式,采用JSQLParser引擎进行封装优化代码封装CDN恢复为staticfile.org加速(如果本地卡的话,建议切换local模式)。 | +| 2024.04.23 | 切换为更快更稳定的BootCDN进行加速。前端NEWUI改版(基于AdminLTE+Bootstrap+Vue+ElementUI混合模式)。 | +| 2024.04.22 | [Java CI with Maven](https://github.com/moshowgame/SpringBootCodeGenerator/actions/workflows/maven.yml) 更新SpringBoot升级到3.2.5FastJSON升级到FastJSON2.0.49 | +| 2024.04.21 | 推出JDK11分支,支持JDK8/JDK11/JDK17等版本,兼容性较好但维护速度较慢,为了更好兼容旧机器和旧环境 | +| 2024.04.20 | 修复CDN版本cdn.staticfile.org域名备份失败问题,已同步更新到cdn.staticfile.net(本地版本则不受影响) | +| 2024.01.26 | 修复大写下滑线列名转驼峰问题(感谢@Nisus-Liu的PR) | +| 2023.10.22 | 工具站CDN更新。 | +| 2023.08.31 | (感谢@Nisus-Liu的PR)fix 驼峰列名转命名风格错误问题增强转下划线命名风格, 对原始风格不敏感. 支持各种命名风格的列名 to 下划线增加 NonCaseString 大小写不敏感字符串包装类, 简化编码几点代码小优化。 | +| 2023.07.11 | 安全更新,正式支持SpringBoot3,javax升级到jakarta。 | +| 2023.01.02 | 新增TkMybatis模板(感谢@sgj666的建议)。 | +| 2023.01.01 | 新增GCP BigQuery/Dataflow JJS/QlikSense BI模板。 | +| 2022.09.28 | MySQL to Java type conversion 数据库类型转换优化(感谢@jadelike得贡献) | +| 2022.07.02 | add the script to install and run,添加批处理以便直接构建或运行项目。 | +| 2022.02.10 | 更新springboot、fastjson、lombok依赖(感谢@Abbykawai的建议)。 | +| 2022.02.09 | 新增JPA-STARP模板(感谢@starplatinum3的贡献)。 | +| 2022.01.11 | 优化mybatis的mapper文件生成(感谢@chendong的贡献)。 | +| 2021.10.31 | 优化当有索引和额外的换行时的解析逻辑(感谢@feitian124的贡献)。修复部分模板参数不对应(感谢@Thixiaoxiao的贡献)。新增cookie记录所需配置字段逻辑,避免重复配置(感谢@Thixiaoxiao的贡献)。 | +| 2021.08.07 | 新增当前模板保持功能,重新生成代码后依然会保持在当前选择模板。新增renren-fast模板。 | +| 2021.08.05 | 解决 update 方法语法错误;调整部分语句避免sonarLint告警(感谢@Henry586的PR);add swagger-yml.ftl(感谢@fuuqiu的PR);支持common-mapper&修复entity和plusentity的swagger引包错误(感谢@chentianming11的PR) | +| 2021.03.24 | 修复Mybatis.XML中缺失test=关键字问题。(感谢@BWHN/YUEHUI的反馈)。 | +| 2021.01.18 | OEM信息优化,支持多配置文件模式,支持在application\*.yml自定义信息,以及切换local/cdn模式。 | +| 2021.01.17 | 生成后自动trim掉前后空格输出。完善ReadMe文档。优化云CDN引入部分。优化returnUtil部分。表明前缀选项(感谢@wwlg的建议)。 是否带字段注释设置(感谢@fengpojian的建议)。优化Mybatis的''!=判断(感谢@zhongsb的建议)。Mybatis-Plus增加Service层(感谢@yf466532479的建议)。 | +| 2021.01.16 | 全新3.0版本:一、前端半vue半js化,更多动态加载项。二、支持更多生成设置,优化生成场景。三、js导入支持本地/CDN模式,支持断网环境轻松使用。 | +| 2020.10.22 | 1.tinyint多加一个Short类型转换(感谢@wttHero的建议) | +| 2020.10.20 | 1.修复mapper2 insert代码问题(感谢@mXiaoWan的PR)2.优化对fulltext/index关键字的处理(感谢@WEGFan的反馈)。3.新增日期类型的转换选择(感谢@qingkediguo的建议)。4.新增是否包装类型的转换选择(感谢@gzlicanyi的建议)。 | +| 2020.06.28 | 优化Util下的BeanUtil,支持更多map.put的操作。整合CRUD模板到SQL(CRUD)模板。 | +| 2020.06.21 | 修复FreemarkerUtil的Path问题导致JAR包运行时无法获取template的问题。 | +| 2020.05.25 | 1.一些fix,关于封装工具类以及layui模板优化等. 2.优化表备注的获取逻辑. 3.生成时间格式改为yyyy-MM-dd,移除具体的时间,只保留日期 | +| 2020.05.22 | 1.新增insert-sql模式,支持对"insert into table (xxx) values (xxx)"语句进行处理,生成java代码(感谢三叔的建议). | +| 2020.05.17 | 1.代码重构!异常处理优化,Freemarker相关工具类优化,简化模板生成部分,通过template.json来配置需要生成的模板,不需要配置java文件. 2.修复包含comment关键字时注释无法识别的问题.(感谢@1nchaos的反馈). 3.赞赏优化,感谢大家的赞赏. 4.新增mapper2(Mybatis-Annotation模板)(感谢@baisi525和@CHKEGit的建议). | +| 2020.05.03 | 1.优化对特殊字符的处理,对于包含#和$等特殊字符的,在模板使用井和¥代替便可,escapeString方法会自动处理. 2.优化mybatisplus实体类相关(感谢@chunchengmeigui的反馈). 3.修优化对所有类型的判断(感谢@cnlw的反馈). 4.移除swagger-entity,该功能已经包含在‘swagger-ui’的下拉选项中 5.升级hutool和lombok版本 | +| 2020.03.06 | 1.提交一套layuimini+mybatisplus的模板. 2.修复mybatisplus一些相关问题. | +| 2020.02.06 | 1.新增历史记录功能,自动保存最近生成的对象. 2.新增swagger开关选项和修复@Column带name参数(感谢@liuyu-struggle的建议). 3.去除mybatis模板中的方括号\[]和修改模板里的类注释样式(感谢@gaohanghang的PR) | +| 2019.12.29 | 1.修复bejson安全防护策略拦截问题(感谢@liangbintao和@1808083642的反馈). 2.优化字段名含date字符串的处理(感谢@smilexzh的反馈). 3.控制台动态输出项目访问地址(感谢@gaohanghang的提交) | +| 2019.11.28 | 1.修复支持string-copy导致的以n结尾的字母不显示问题. 2.jpa-entity新增swagger\@ApiModel\@ApiModelProperty注解和SQL字段@Column注解(感谢@yjq907的建议) | +| 2019.11.26 | 1.springboot2内置tomcat更换为性能更强大的undertow. 2.修复tinyintTransType参数丢失问题 | +| 2019.11.24 | 1.java代码结构优化. 2.新增简单的json生成模式. 3.新增简单的正则表达式匹配模式(感谢@ydq的贡献). 4.新增对复制String代码中的乱SQL代码的支持 5.优化对JSON的父子节点/处理,JSONObject和JSONArray节点处理,子节点缺失'{'头处理 | +| 2019.11.23 | 1.移除频繁出错和被过滤的layer,改为jquery-toast. 2.Util功能优化,新增json和xml. | +| 2019.11.16 | 优化对primary关键字的处理(感谢@liujiansgit的反馈). | +| 2019.11.15 | 1.添加tinyint类型转换(感谢@lixiliang&@liujiansgit的Suggestion). 2.添加一键复制功能(感谢@gaohanghang的Suggestion). 3.Mybatis的insert增加keyProperty="id"用于返回自增id(感谢@88888888888888888888的Suggestion). 4.优化date类型的支持(感谢@SteveLsf的反馈). 5.其他一些优化. | +| 2019.10.15 | 修复jdbcTemplates中insert语句第一个字段丢失的问题. | +| 2019.09.15 | 1.添加对象getset模板. 2.添加sql模板. 3.启动类添加日志输出,方便项目使用(感谢@gaohanghang 的pull request) | +| 2019.09.10 | 优化以及更新Maven依赖,减少打包体积. 1.修复mapper接口load方法,但是xml中方法不匹配问题. 2.移除mapper中CRUD时的@param 注解,会影响xml的解析(感谢@caojiantao的反馈). 3.优化MyBatis的xml文件对Oracle的支持.(感谢@wylove1992的反馈). 4.新增对boolean的处理(感谢@violinxsc的反馈)以及优化tinyint类型生成boolean类型问题(感谢@hahaYhui的反馈) | +| 2019.09.09 | 添加是否下划线转换为驼峰的选择(感谢@youngking28 的pull request). | +| 2019.05.18 | 1.优化注释. 2.修改 mybatis模板中 controller注解. 3.修改 mybatis模板中 dao文件使用为 mapper文件. 4.修改 mybatis模板中 service实现类中的一个 bug. 5.修改 index.ftl文件中 mybatis模板的 dao -> mapper(感谢@unqin的pull request) | +| 2019.05.11 | 优化mybatis模块的dao和xml模板,修改dao接口注解为@Repository,所有dao参数改为包装类,删除update语句最后的UpdateTime = NOW(),修改dao接口文件的方法注释使其更符合javaDoc的标准,修改insert语句增加插入行主键的返回,修改load的方法名为selectByPrimaryKey,修改xml的update语句新增动态if判空,修改xml的insert语句新增动态插入判空,更符合mybatisGenerator标准(感谢@Archer-Wen的贡献 ). | +| 2019.04.29 | 新增返回封装工具类设置. 优化对oracle注释comment on column的支持(感谢@liukex反馈). 优化对普通和特殊storage关键字的判断(感谢@AhHeadFloating的反馈 ). | +| 2019.02.11 | 提交gitignore,解决StringUtils.lowerCaseFirst潜在的NPE异常,校验修改为@RequestParam参数校验,lombok之@Data和@Slf4j优化,fix JdbcDAO模板类名显示为中文问题,WebMvcConfig整合MessageConverter,模板代码分类(感谢@liutf和@tfgzs的pull request). | +| 2019.02.10 | 实体生成规则切换为包装类型,不再采用基本数据类型,为实体类生成添加显示的默认构造方法(感谢@h2so的pull request). | +| 2019.01.06 | 修复处理number/decimal(x,x)类型的逻辑(感谢@arthaschan的反馈). 修复JdbcTemplates模板两处错误(感谢@everflourish的反馈). | +| 2018.12.12 | 首页UI优化. 新增MybatisPlus模块(感谢@三叔同事的建议). 修复作者名和包名获取失败问题(感谢@Yanch1994的反馈). | +| 2018.11.22 | 优化正则表达式点号的处理,优化处理字段类型,对number类型增加int,long,BigDecimal的区分判断(感谢@lshz0088的指导). | +| 2018.11.08 | 修复非字段描述"KEY FK\_xxxx (xxxx)"导致生成KEY字段情况(感谢@tornadoorz反馈). | +| 2018.10.18 | 支持double(x,x)的类型,以及comment里面包含一些特殊字符的处理(感谢@tanwubo的反馈). | +| 2018.10.10 | CDN变更,修复CDN不稳定导致网页js报错问题. | +| 2018.10.03 | 新增element-ui/bootstrap生成. | +| 2018.10.02 | 修复公共CDN之Layer.js404问题,导致项目无法生成. | +| 2018.09.27 | 优化COMMENT提取逻辑,支持多种复杂情况的注释(感谢@raodeming的反馈). | +| 2018.09.26 | 全新BeetlSQL模块,以及一些小细节优化(感谢@三叔同事的建议). | +| 2018.09.25 | 优化SQL表和字段备注的推断,包括pgsql/oralce的comment on column/table情况处理等. | +| 2018.09.18 | 优化SQL类型推断. 优化PrimaryKey判断. 修复jpacontroller中Repository拼写错误问题. | +| 2018.09.17 | 全新首页,静态文件全部采用CDN.新增jdbcTemplate模块. | +| 2018.09.16 | 1.优化oracle支持,优化DDL语句中"或者'或者空格的支持. 2.补充char/clob/blob/json等类型,如果类型未知,默认为String. | +| 2018.09.15 | 新增Swagger-UI模板.修复一些命名和导入问题.JPA的Entity默认第一个字段为Id,如果不是请手工修改. | +| 2018.09.13 | 修复字段没有描述以及类型为DATE型导致的问题.新增JPA的Controller模板. | +| 2018.08.31 | 初始化项目.新增JPA系列Entity+Repository模板. | + +
+ diff --git a/REFACTORING_DOCUMENT.md b/REFACTORING_DOCUMENT.md deleted file mode 100644 index 3c1d5d0..0000000 --- a/REFACTORING_DOCUMENT.md +++ /dev/null @@ -1,217 +0,0 @@ -# Spring Boot代码生成器项目重构说明文档 - -## 1. 重构概述 - -本项目旨在对Spring Boot代码生成器进行现代化重构,使其具有更清晰的架构、更好的可维护性和更强的扩展性。重构遵循现代Spring Boot应用的最佳实践,采用了分层架构设计和多种设计模式。 - -## 2. 重构目标 - -1. **清晰的分层架构**:明确Controller、Service、DTO、VO等各层职责 -2. **良好的可扩展性**:通过策略模式处理不同类型的SQL解析 -3. **现代化开发规范**:遵循Spring Boot和Java开发最佳实践 -4. **易于维护**:通过合理的包结构和命名规范提高代码可读性 -5. **前后端兼容性**:保持与现有前端代码的数据交互格式 - -## 3. 重构后项目结构 - -``` -com.softdev.system.generator -├── GeneratorApplication.java # 启动类 -├── config # 配置类包 -│ ├── WebMvcConfig.java # MVC配置 -│ └── GlobalExceptionHandler.java # 全局异常处理器 -├── controller # 控制层 -│ ├── PageController.java # 页面跳转控制器 -│ ├── CodeGenController.java # 代码生成相关接口 -│ └── TemplateController.java # 模板相关接口 -├── service # 服务层接口 -│ ├── CodeGenService.java # 代码生成服务接口 -│ ├── TemplateService.java # 模板服务接口 -│ └── parser -│ ├── SqlParserService.java # SQL解析服务接口 -│ └── JsonParserService.java # JSON解析服务接口 -├── service.impl # 服务实现层 -│ ├── CodeGenServiceImpl.java # 代码生成服务实现 -│ ├── TemplateServiceImpl.java # 模板服务实现 -│ └── parser -│ ├── SqlParserServiceImpl.java # SQL解析服务实现 -│ └── JsonParserServiceImpl.java # JSON解析服务实现 -├── entity # 实体类 -│ ├── dto -│ │ ├── ParamInfo.java # 参数信息DTO -│ │ ├── ClassInfo.java # 类信息DTO -│ │ └── FieldInfo.java # 字段信息DTO -│ ├── vo -│ │ └── ResultVo.java # 统一返回结果VO -│ └── enums -│ └── ParserTypeEnum.java # 解析类型枚举 -├── util # 工具类包 -│ ├── FreemarkerUtil.java # Freemarker工具类 -│ ├── StringUtilsPlus.java # 字符串工具类 -│ ├── MapUtil.java # Map工具类 -│ ├── mysqlJavaTypeUtil.java # MySQL类型转换工具类 -│ └── exception -│ ├── CodeGenException.java # 自定义业务异常 -│ └── SqlParseException.java # SQL解析异常 -└── constant # 常量定义 - └── CodeGenConstants.java # 代码生成常量(待实现) -``` - -## 4. 各层详细说明 - -### 4.1 控制层 (Controller) - -控制层负责处理HTTP请求,协调业务逻辑并返回结果: - -1. **[PageController](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/controller/PageController.java)**: - - 处理页面跳转请求 - - 返回视图页面 - -2. **[CodeGenController](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/controller/CodeGenController.java)**: - - 提供代码生成相关REST API - - 处理代码生成请求 - -3. **[TemplateController](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/controller/TemplateController.java)**: - - 提供模板管理相关REST API - - 处理模板获取请求 - -### 4.2 服务层 (Service) - -服务层采用接口与实现分离的设计,便于测试和扩展: - -1. **接口层**: - - [CodeGenService](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/CodeGenService.java): 核心代码生成服务接口 - - [TemplateService](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/TemplateService.java): 模板管理服务接口 - - [SqlParserService](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/parser/SqlParserService.java): SQL解析服务接口 - - [JsonParserService](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/parser/JsonParserService.java): JSON解析服务接口 - -2. **实现层**: - - [CodeGenServiceImpl](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/impl/CodeGenServiceImpl.java): 核心代码生成服务实现 - - [TemplateServiceImpl](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/impl/TemplateServiceImpl.java): 模板管理服务实现 - - [SqlParserServiceImpl](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/impl/parser/SqlParserServiceImpl.java): SQL解析服务实现 - - [JsonParserServiceImpl](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/impl/parser/JsonParserServiceImpl.java): JSON解析服务实现 - -### 4.3 实体层 (Entity) - -实体层按照用途分类,避免不同类型对象混用: - -1. **DTO (Data Transfer Object)**: - - [ParamInfo](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/entity/dto/ParamInfo.java): 参数信息传输对象 - - [ClassInfo](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/entity/dto/ClassInfo.java): 类信息传输对象 - - [FieldInfo](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/entity/dto/FieldInfo.java): 字段信息传输对象 - -2. **VO (View Object)**: - - [ResultVo](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/entity/vo/ResultVo.java): 统一返回结果视图对象 - -3. **Enums**: - - [ParserTypeEnum](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/entity/enums/ParserTypeEnum.java): 解析类型枚举 - -### 4.4 工具层 (Util) - -工具层包含各种通用工具类和自定义异常: - -1. **工具类**: - - [FreemarkerUtil](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/util/FreemarkerUtil.java): Freemarker模板处理工具 - - [StringUtilsPlus](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/util/StringUtilsPlus.java): 字符串处理工具 - - [MapUtil](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/util/MapUtil.java): Map操作工具 - - [mysqlJavaTypeUtil](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/util/mysqlJavaTypeUtil.java): MySQL与Java类型映射工具 - -2. **异常类**: - - [CodeGenException](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/util/exception/CodeGenException.java): 代码生成自定义业务异常 - - [SqlParseException](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/util/exception/SqlParseException.java): SQL解析异常 - -## 5. 关键设计模式应用 - -### 5.1 策略模式 - -在SQL解析功能中应用策略模式,将不同的解析方式封装成独立的策略类: - -1. [SqlParserServiceImpl](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/impl/parser/SqlParserServiceImpl.java)中实现了多种SQL解析方法: - - `processTableIntoClassInfo`: 默认SQL解析 - - `generateSelectSqlBySQLPraser`: SELECT SQL解析 - - `generateCreateSqlBySQLPraser`: CREATE SQL解析 - - `processTableToClassInfoByRegex`: 正则表达式解析 - - `processInsertSqlToClassInfo`: INSERT SQL解析 - -2. [JsonParserServiceImpl](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/service/impl/parser/JsonParserServiceImpl.java)中实现了JSON解析: - - `processJsonToClassInfo`: JSON解析 - -通过策略模式,可以: -- 避免大量的if-else判断 -- 便于添加新的解析策略 -- 提高代码的可维护性 - -### 5.2 接口与实现分离 - -所有服务层都采用接口与实现分离的设计,便于: -- 单元测试模拟 -- 多种实现方式切换 -- 降低模块间耦合度 - -## 6. 重要技术实现细节 - -### 6.1 统一响应格式 - -所有控制器方法均返回 [ResultVo](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/entity/vo/ResultVo.java) 统一响应对象,保持与前端的兼容性: - -```java -// 成功响应 -ResultVo.ok(data) - -// 错误响应 -ResultVo.error(message) -``` - -### 6.2 前后端兼容性处理 - -为了保持与现有前端JavaScript代码的兼容性,在处理响应数据时特别注意了数据结构: - -1. 模板获取接口返回数据结构: - ```json - { - "code": 200, - "msg": "success", - "templates": [...] - } - ``` - -2. 代码生成接口返回数据结构: - ```json - { - "code": 200, - "msg": "success", - "outputJson": { - "tableName": "...", - "controller": "...", - "service": "...", - // 其他模板生成的代码 - } - } - ``` - -### 6.3 组件扫描配置 - -由于服务实现类位于不同的包层级中,已在 [Application](file:///D:/Workspace/Project/SpringBootCodeGenerator/generator-web/src/main/java/com/softdev/system/generator/Application.java) 类中配置了组件扫描路径: - -```java -@SpringBootApplication(scanBasePackages = "com.softdev.system.generator") -``` - -确保所有服务实现类都能被正确扫描和注入。 - -## 7. 重构优势总结 - -1. **结构清晰**:通过合理的包结构和分层设计,使项目结构更加清晰易懂 -2. **易于维护**:各层职责明确,便于定位和修复问题 -3. **易于扩展**:采用策略模式等设计模式,便于添加新的功能模块 -4. **现代化**:遵循Spring Boot和Java的最新最佳实践 -5. **前后端兼容**:保持与现有前端代码的数据交互格式,无缝升级 - -## 8. 后续优化建议 - -1. **添加单元测试**:为各层添加完整的单元测试,确保代码质量 -2. **集成日志系统**:完善日志记录,便于问题排查 -3. **添加缓存机制**:对模板等不常变化的数据添加缓存,提高性能 -4. **完善异常处理**:统一异常处理机制,提供更友好的错误提示 -5. **添加接口文档**:使用Swagger等工具生成接口文档,便于前后端协作 -6. **增加常量定义**:将硬编码的字符串提取为常量,提高可维护性 \ No newline at end of file diff --git a/UNIT_TEST_DOCUMENT.md b/UNIT_TEST_DOCUMENT.md deleted file mode 100644 index 1aee1cd..0000000 --- a/UNIT_TEST_DOCUMENT.md +++ /dev/null @@ -1,192 +0,0 @@ -# 单元测试重构总结 - -## 已完成的单元测试 - -基于最新的项目代码,我已经为以下Service和Controller类生成了完整的单元测试: - -### 1. Service层测试 - -#### CodeGenServiceTest -- **位置**: `src/test/java/com/softdev/system/generator/service/CodeGenServiceTest.java` -- **测试内容**: - - ✅ 测试生成代码成功场景 - - ✅ 测试表结构信息为空的错误处理 - - ✅ 测试表结构信息为null的错误处理 - - ✅ 测试生成代码异常处理 - - ✅ 测试JSON模式解析 - - ✅ 测试INSERT SQL模式解析 - - ✅ 测试根据参数获取结果 - - ✅ 测试模板为空的情况 - -#### TemplateServiceTest -- **位置**: `src/test/java/com/softdev/system/generator/service/TemplateServiceTest.java` -- **测试内容**: - - ✅ 测试获取所有模板配置成功 - - ✅ 测试模板配置缓存机制 - - ✅ 测试模板配置JSON解析 - - ✅ 测试无效JSON异常处理 - -#### SqlParserServiceTest -- **位置**: `src/test/java/com/softdev/system/generator/service/parser/SqlParserServiceTest.java` -- **测试内容**: - - ✅ 测试解析Select SQL - - ✅ 测试解析Create SQL - - ✅ 测试处理表结构到类信息 - - ✅ 测试正则表达式解析表结构 - - ✅ 测试解析Insert SQL - - ✅ 测试空SQL字符串异常处理 - - ✅ 测试null SQL字符串异常处理 - - ✅ 测试无效SQL语法异常处理 - - ✅ 测试复杂Select SQL解析 - - ✅ 测试带别名的Select SQL - - ✅ 测试Insert SQL正则表达式解析 - -#### JsonParserServiceTest -- **位置**: `src/test/java/com/softdev/system/generator/service/parser/JsonParserServiceTest.java` -- **测试内容**: - - ✅ 测试解析简单JSON - - ✅ 测试解析复杂嵌套JSON - - ✅ 测试解析空JSON - - ✅ 测试null JSON字符串处理 - - ✅ 测试空字符串JSON处理 - - ✅ 测试无效JSON格式处理 - - ✅ 测试JSON数组解析 - - ✅ 测试不同数据类型字段解析 - -### 2. Controller层测试 - -#### CodeGenControllerTest -- **位置**: `src/test/java/com/softdev/system/generator/controller/CodeGenControllerTest.java` -- **测试内容**: - - ✅ 测试生成代码接口成功 - - ✅ 测试生成代码接口返回错误 - - ✅ 测试参数为空的情况 - - ✅ 测试无效JSON请求 - - ✅ 测试缺少Content-Type - - ✅ 测试服务层异常处理 - - ✅ 测试空tableSql验证 - - ✅ 测试null tableSql验证 - - ✅ 测试null options验证 - - ✅ 测试复杂参数处理 - -#### PageControllerTest -- **位置**: `src/test/java/com/softdev/system/generator/controller/PageControllerTest.java` -- **测试内容**: - - ✅ 测试默认页面路由 - - ✅ 测试首页路由 - - ✅ 测试ModelAndView对象 - - ✅ 测试ValueUtil注入 - -#### TemplateControllerTest -- **位置**: `src/test/java/com/softdev/system/generator/controller/TemplateControllerTest.java` -- **测试内容**: - - ✅ 测试获取所有模板成功 - - ✅ 测试返回空数组 - - ✅ 测试服务异常处理 - - ✅ 测试IO异常处理 - - ✅ 测试直接调用方法 - - ✅ 测试错误请求路径 - - ✅ 测试错误的HTTP方法 - -### 3. 工具类测试 - -#### ResultVoTest -- **位置**: `src/test/java/com/softdev/system/generator/vo/ResultVoTest.java` -- **测试内容**: - - ✅ 测试默认构造函数 - - ✅ 测试ok静态方法 - - ✅ 测试带数据的ok方法 - - ✅ 测试error方法 - - ✅ 测试带错误码的error方法 - - ✅ 测试put方法 - - ✅ 测试链式调用 - - ✅ 测试size、containsKey等Map方法 - - ✅ 测试remove和clear方法 - -#### MapUtilTest -- **位置**: `src/test/java/com/softdev/system/generator/util/MapUtilTest.java` -- **测试内容**: - - ✅ 测试getString方法 - - ✅ 测试getInteger方法 - - ✅ 测试getBoolean方法 - - ✅ 测试异常处理 - - ✅ 测试空Map和null Map - -#### StringUtilsPlusTest -- **位置**: `src/test/java/com/softdev/system/generator/util/StringUtilsPlusTest.java` -- **测试内容**: - - ✅ 测试字符串工具类各种方法 - - ✅ 已修复为适配实际存在的方法 - -## 测试框架配置 - -### JUnit 5 + Mockito -项目已升级到: -- **JUnit 5 (Jupiter)**: 现代化测试框架 -- **Mockito**: 强大的Mock框架 -- **Spring Boot Test**: Spring集成测试支持 - -### 测试特性 -- ✅ 使用Mockito进行依赖注入Mock -- ✅ 静态方法Mock(MockedStatic) -- ✅ Spring MVC测试(MockMvc) -- ✅ 完整的异常场景覆盖 -- ✅ 边界条件测试 -- ✅ 中文测试名称(@DisplayName) - -## 代码质量 - -### 测试覆盖率 -- Service层:高覆盖率,包含所有公共方法 -- Controller层:完整HTTP接口测试 -- 工具类:核心方法全覆盖 - -### 测试质量 -- ✅ 遵循AAA模式(Arrange-Act-Assert) -- ✅ 清晰的测试命名 -- ✅ 合理的测试数据准备 -- ✅ 完善的断言验证 - -## 运行测试 - -### 单独运行测试类 -```bash -mvn test -Dtest=CodeGenServiceTest -mvn test -Dtest=CodeGenControllerTest -mvn test -Dtest=TemplateServiceTest -``` - -### 运行所有新增测试 -```bash -mvn test -Dtest=CodeGenServiceTest,TemplateServiceTest,CodeGenControllerTest,PageControllerTest,TemplateControllerTest,SqlParserServiceTest,JsonParserServiceTest,StringUtilsPlusTest,MapUtilTest,ResultVoTest -``` - -## 项目结构 - -``` -src/test/java/com/softdev/system/generator/ -├── controller/ -│ ├── CodeGenControllerTest.java -│ ├── PageControllerTest.java -│ └── TemplateControllerTest.java -├── service/ -│ ├── CodeGenServiceTest.java -│ └── TemplateServiceTest.java -├── service/parser/ -│ ├── SqlParserServiceTest.java -│ └── JsonParserServiceTest.java -├── util/ -│ ├── MapUtilTest.java -│ └── StringUtilsPlusTest.java -└── vo/ - └── ResultVoTest.java -``` - -## 注意事项 - -1. **依赖兼容性**: 所有测试已适配项目的实际依赖 -2. **方法签名**: 测试方法与实际实现类的方法签名完全匹配 -3. **异常处理**: 包含了完整的异常场景测试 -4. **Mock策略**: 合理使用Mock避免外部依赖影响 - -这些单元测试为项目的核心业务逻辑提供了可靠的验证,确保代码质量和功能正确性。 \ No newline at end of file diff --git a/src/main/java/com/softdev/system/generator/controller/CodeGenController.java b/src/main/java/com/softdev/system/generator/controller/CodeGenController.java index c11810b..636e349 100644 --- a/src/main/java/com/softdev/system/generator/controller/CodeGenController.java +++ b/src/main/java/com/softdev/system/generator/controller/CodeGenController.java @@ -1,12 +1,25 @@ package com.softdev.system.generator.controller; +import com.softdev.system.generator.entity.dto.ClassInfo; +import com.softdev.system.generator.entity.dto.CodeGenResult; import com.softdev.system.generator.entity.dto.ParamInfo; import com.softdev.system.generator.entity.vo.ResultVo; import com.softdev.system.generator.service.CodeGenService; +import com.softdev.system.generator.service.ZipService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.ModelAndView; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; /** * 代码生成控制器 @@ -18,12 +31,76 @@ import org.springframework.web.servlet.ModelAndView; @RestController @RequestMapping("/code") public class CodeGenController { - + private final CodeGenService codeGenService; + private final ZipService zipService; @PostMapping("/generate") public ResultVo generateCode(@RequestBody ParamInfo paramInfo) throws Exception { return codeGenService.generateCode(paramInfo); } -} \ No newline at end of file + /** + * 一键 ZIP 打包下载:将生成的全部代码打成 ZIP 流返回 + * + * @param paramInfo 参数信息 + * @return ZIP 字节流 + */ + @PostMapping(value = "/generate-zip", produces = "application/zip") + public ResponseEntity generateCodeAsZip(@RequestBody ParamInfo paramInfo) throws Exception { + log.info("收到 ZIP 下载请求"); + if (paramInfo == null || paramInfo.getTableSql() == null || paramInfo.getTableSql().isEmpty()) { + return ResponseEntity.badRequest().build(); + } + + CodeGenResult result = codeGenService.getResultByParams(prepareOptions(paramInfo)); + + String zipName = (result.getClassName() != null && !result.getClassName().isEmpty()) + ? result.getClassName() + : (result.getTableName() != null && !result.getTableName().isEmpty()) + ? result.getTableName() + : "code-generator"; + + byte[] zipBytes = zipService.buildZip( + result.getGeneratedCode(), + result.getFileNameTemplates(), + result.getGroupByTemplate(), + zipName, + buildContext(result) + ); + + String encoded = URLEncoder.encode(zipName + ".zip", StandardCharsets.UTF_8) + .replace("+", "%20"); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.parseMediaType("application/zip")); + // 注意:只设置一次 Content-Disposition,同时携带 ASCII 与 RFC 5987 UTF-8 形式, + // 避免 ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION 错误 + headers.set("Content-Disposition", + "attachment; filename=\"" + zipName + ".zip\"; filename*=UTF-8''" + encoded); + headers.setContentLength(zipBytes.length); + return new ResponseEntity<>(zipBytes, headers, org.springframework.http.HttpStatus.OK); + } + + /** + * 与 generateCode 共享参数准备逻辑:解析、塞入 options + */ + private Map prepareOptions(ParamInfo paramInfo) throws Exception { + Map options = paramInfo.getOptions() == null ? new HashMap<>() : paramInfo.getOptions(); + paramInfo.setOptions(options); + + ClassInfo classInfo = codeGenService.parseTableStructure(paramInfo); + options.put("classInfo", classInfo); + options.put("tableName", classInfo == null ? System.currentTimeMillis() + "" : classInfo.getTableName()); + return options; + } + + /** + * 构造 ZIP 解析占位符所需的上下文 + */ + private Map buildContext(CodeGenResult result) { + Map ctx = new HashMap<>(); + ctx.put("className", result.getClassName() == null ? "" : result.getClassName()); + ctx.put("tableName", result.getTableName() == null ? "" : result.getTableName()); + return ctx; + } +} diff --git a/src/main/java/com/softdev/system/generator/entity/dto/CodeGenResult.java b/src/main/java/com/softdev/system/generator/entity/dto/CodeGenResult.java new file mode 100644 index 0000000..57a392a --- /dev/null +++ b/src/main/java/com/softdev/system/generator/entity/dto/CodeGenResult.java @@ -0,0 +1,37 @@ +package com.softdev.system.generator.entity.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * 代码生成结果封装 + *

+ * 携带:渲染后的代码、模板 fileName 模板、模板分组,供 ZIP 打包 / 单文件下载等场景使用。 + * + * @author zhengkai.blog.csdn.net + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CodeGenResult { + + /** 表名(原始或处理后) */ + private String tableName; + + /** 类名 */ + private String className; + + /** 渲染结果:key=template.name, value=渲染后的内容 */ + private Map generatedCode; + + /** 模板 fileName 配置:key=template.name, value=fileName 模板(可含 ${className} 占位符) */ + private Map fileNameTemplates; + + /** 模板分组:key=template.name, value=group */ + private Map groupByTemplate; +} diff --git a/src/main/java/com/softdev/system/generator/service/CodeGenService.java b/src/main/java/com/softdev/system/generator/service/CodeGenService.java index 0afd73f..a8e5bf9 100644 --- a/src/main/java/com/softdev/system/generator/service/CodeGenService.java +++ b/src/main/java/com/softdev/system/generator/service/CodeGenService.java @@ -1,6 +1,7 @@ package com.softdev.system.generator.service; import com.softdev.system.generator.entity.dto.ClassInfo; +import com.softdev.system.generator.entity.dto.CodeGenResult; import com.softdev.system.generator.entity.dto.ParamInfo; import com.softdev.system.generator.entity.vo.ResultVo; @@ -14,20 +15,29 @@ import java.util.Map; public interface CodeGenService { /** - * 生成代码 + * 生成代码(前端在线预览版本) * * @param paramInfo 参数信息 - * @return 生成的代码映射 + * @return 生成的代码映射(key=模板名, value=渲染内容) * @throws Exception 生成过程中的异常 */ ResultVo generateCode(ParamInfo paramInfo) throws Exception; /** - * 根据参数获取结果 + * 解析表结构(仅解析,不生成) * - * @param params 参数映射 - * @return 结果映射 + * @param paramInfo 参数信息 + * @return 类信息 + * @throws Exception 解析异常 + */ + ClassInfo parseTableStructure(ParamInfo paramInfo) throws Exception; + + /** + * 根据参数获取结果(富信息版本,包含模板分组与 fileName 配置) + * + * @param params 参数映射(含 classInfo、tableName 等) + * @return CodeGenResult * @throws Exception 处理过程中的异常 */ - Map getResultByParams(Map params) throws Exception; -} \ No newline at end of file + CodeGenResult getResultByParams(Map params) throws Exception; +} diff --git a/src/main/java/com/softdev/system/generator/service/ZipService.java b/src/main/java/com/softdev/system/generator/service/ZipService.java new file mode 100644 index 0000000..84e8dcc --- /dev/null +++ b/src/main/java/com/softdev/system/generator/service/ZipService.java @@ -0,0 +1,27 @@ +package com.softdev.system.generator.service; + +import java.util.Map; + +/** + * ZIP 打包服务接口 + * + * @author zhengkai.blog.csdn.net + */ +public interface ZipService { + + /** + * 将已生成的代码结果(key=模板名, value=渲染后内容)打包为 ZIP + * + * @param generatedCode 模板渲染结果(key=template.name, value=内容) + * @param fileNameTemplates 模板元数据(key=template.name, value=fileName 模板,可含 ${className} 占位符,可为 null) + * @param groupByTemplate 模板元数据(key=template.name, value=group 名称) + * @param zipFileName 最终 zip 文件名(不含后缀) + * @param context 解析占位符的上下文(至少含 className、tableName) + * @return zip 字节数组 + */ + byte[] buildZip(Map generatedCode, + Map fileNameTemplates, + Map groupByTemplate, + String zipFileName, + Map context); +} diff --git a/src/main/java/com/softdev/system/generator/service/impl/CodeGenServiceImpl.java b/src/main/java/com/softdev/system/generator/service/impl/CodeGenServiceImpl.java index 3ad3e34..311d19f 100644 --- a/src/main/java/com/softdev/system/generator/service/impl/CodeGenServiceImpl.java +++ b/src/main/java/com/softdev/system/generator/service/impl/CodeGenServiceImpl.java @@ -3,6 +3,7 @@ package com.softdev.system.generator.service.impl; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.softdev.system.generator.entity.dto.ClassInfo; +import com.softdev.system.generator.entity.dto.CodeGenResult; import com.softdev.system.generator.entity.dto.ParamInfo; import com.softdev.system.generator.entity.enums.ParserTypeEnum; import com.softdev.system.generator.entity.vo.ResultVo; @@ -16,7 +17,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -40,18 +41,11 @@ public class CodeGenServiceImpl implements CodeGenService { } try { - // 1. Parse Table Structure 表结构解析 - ClassInfo classInfo = parseTableStructure(paramInfo); - - // 2. Set the params 设置表格参数 - paramInfo.getOptions().put("classInfo", classInfo); - paramInfo.getOptions().put("tableName", classInfo == null ? System.currentTimeMillis() + "" : classInfo.getTableName()); - - // 3. generate the code by freemarker templates with parameters . - // Freemarker根据参数和模板生成代码 - Map result = getResultByParams(paramInfo.getOptions()); - log.info("table:{} - time:{} ", MapUtil.getString(result, "tableName"), System.currentTimeMillis()); - return ResultVo.ok(result); + CodeGenResult result = doGenerate(paramInfo); + Map generatedCode = result.getGeneratedCode(); + generatedCode.put("tableName", result.getTableName()); + log.info("table:{} - time:{} ", result.getTableName(), System.currentTimeMillis()); + return ResultVo.ok(generatedCode); } catch (Exception e) { log.error("代码生成失败", e); return ResultVo.error("代码生成失败: " + e.getMessage()); @@ -59,65 +53,93 @@ public class CodeGenServiceImpl implements CodeGenService { } @Override - public Map getResultByParams(Map params) throws Exception { - Map result = new HashMap<>(32); - result.put("tableName", MapUtil.getString(params, "tableName")); + public ClassInfo parseTableStructure(ParamInfo paramInfo) throws Exception { + if (paramInfo.getTableSql() == null || paramInfo.getTableSql().isEmpty()) { + throw new IllegalArgumentException("表结构信息为空"); + } + return parseByType(paramInfo); + } + + @Override + public CodeGenResult getResultByParams(Map params) throws Exception { + CodeGenResult.CodeGenResultBuilder builder = CodeGenResult.builder(); + + Map generatedCode = new LinkedHashMap<>(); + Map fileNameTemplates = new LinkedHashMap<>(); + Map groupByTemplate = new LinkedHashMap<>(); + + generatedCode.put("tableName", MapUtil.getString(params, "tableName")); - // 处理模板生成逻辑 - // 解析模板配置并生成代码 JSONArray parentTemplates = templateService.getAllTemplates(); for (int i = 0; i < parentTemplates.size(); i++) { JSONObject parentTemplateObj = parentTemplates.getJSONObject(i); + String group = parentTemplateObj.getString("group"); JSONArray childTemplates = parentTemplateObj.getJSONArray("templates"); if (childTemplates != null) { for (int x = 0; x < childTemplates.size(); x++) { JSONObject childTemplate = childTemplates.getJSONObject(x); - String templatePath = parentTemplateObj.getString("group") + "/" + childTemplate.getString("name") + ".ftl"; - String generatedCode = FreemarkerUtil.processString(templatePath, params); - result.put(childTemplate.getString("name"), generatedCode); + String templateName = childTemplate.getString("name"); + String templatePath = group + "/" + templateName + ".ftl"; + String generatedText = FreemarkerUtil.processString(templatePath, params); + generatedCode.put(templateName, generatedText); + fileNameTemplates.put(templateName, childTemplate.getString("fileName")); + groupByTemplate.put(templateName, group); } } } - - return result; + + Object classInfo = params.get("classInfo"); + String className = null; + if (classInfo instanceof ClassInfo) { + className = ((ClassInfo) classInfo).getClassName(); + } + if (className == null) { + className = MapUtil.getString(params, "tableName"); + } + return builder + .tableName(MapUtil.getString(params, "tableName")) + .className(className) + .generatedCode(generatedCode) + .fileNameTemplates(fileNameTemplates) + .groupByTemplate(groupByTemplate) + .build(); + } + + /** + * 共享的生成逻辑:先解析,再调用 getResultByParams + */ + private CodeGenResult doGenerate(ParamInfo paramInfo) throws Exception { + ClassInfo classInfo = parseByType(paramInfo); + + paramInfo.getOptions().put("classInfo", classInfo); + paramInfo.getOptions().put("tableName", classInfo == null ? System.currentTimeMillis() + "" : classInfo.getTableName()); + + return getResultByParams(paramInfo.getOptions()); } /** * 根据不同的解析类型解析表结构 - * - * @param paramInfo 参数信息 - * @return 类信息 - * @throws Exception 解析异常 */ - private ClassInfo parseTableStructure(ParamInfo paramInfo) throws Exception { + private ClassInfo parseByType(ParamInfo paramInfo) throws Exception { String dataType = MapUtil.getString(paramInfo.getOptions(), "dataType"); ParserTypeEnum parserType = ParserTypeEnum.fromValue(dataType); - - // 添加调试信息 log.debug("解析数据类型: {}, 解析结果: {}", dataType, parserType); switch (parserType) { case SQL: - // 默认模式:parse DDL table structure from sql return sqlParserService.processTableIntoClassInfo(paramInfo); case JSON: - // JSON模式:parse field from json string return jsonParserService.processJsonToClassInfo(paramInfo); case INSERT_SQL: - // INSERT SQL模式:parse field from insert sql return sqlParserService.processInsertSqlToClassInfo(paramInfo); case SQL_REGEX: - // 正则表达式模式(非完善版本):parse sql by regex return sqlParserService.processTableToClassInfoByRegex(paramInfo); case SELECT_SQL: - // SelectSqlBySQLPraser模式:parse select sql by JSqlParser return sqlParserService.generateSelectSqlBySQLPraser(paramInfo); case CREATE_SQL: - // CreateSqlBySQLPraser模式:parse create sql by JSqlParser return sqlParserService.generateCreateSqlBySQLPraser(paramInfo); default: - // 默认模式:parse DDL table structure from sql return sqlParserService.processTableIntoClassInfo(paramInfo); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/softdev/system/generator/service/impl/ZipServiceImpl.java b/src/main/java/com/softdev/system/generator/service/impl/ZipServiceImpl.java new file mode 100644 index 0000000..08023a4 --- /dev/null +++ b/src/main/java/com/softdev/system/generator/service/impl/ZipServiceImpl.java @@ -0,0 +1,96 @@ +package com.softdev.system.generator.service.impl; + +import com.softdev.system.generator.service.ZipService; +import com.softdev.system.generator.util.ZipFileNameResolver; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * ZIP 打包服务实现类 + *

+ * 使用 JDK 自带 ZipOutputStream 打包,零依赖。 + *

+ * 目录结构:{group}/{fileName},同名文件自动加序号去重。 + * + * @author zhengkai.blog.csdn.net + */ +@Slf4j +@Service +public class ZipServiceImpl implements ZipService { + + @Override + public byte[] buildZip(Map generatedCode, + Map fileNameTemplates, + Map groupByTemplate, + String zipFileName, + Map context) { + if (generatedCode == null || generatedCode.isEmpty()) { + throw new IllegalArgumentException("没有可打包的生成内容"); + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(64 * 1024); + Set usedPaths = new HashSet<>(); + try (ZipOutputStream zos = new ZipOutputStream(baos)) { + zos.setLevel(java.util.zip.Deflater.BEST_SPEED); + for (Map.Entry entry : generatedCode.entrySet()) { + String templateName = entry.getKey(); + String content = entry.getValue(); + if (content == null) { + continue; + } + String fileNameTpl = fileNameTemplates == null ? null : fileNameTemplates.get(templateName); + String group = groupByTemplate == null ? "generated" : groupByTemplate.getOrDefault(templateName, "generated"); + String fileName = ZipFileNameResolver.resolve(fileNameTpl, templateName, group, context); + String entryPath = uniquePath(group, fileName, usedPaths); + writeEntry(zos, entryPath, content); + } + } catch (IOException e) { + log.error("ZIP 打包失败: zipFileName={}", zipFileName, e); + throw new RuntimeException("ZIP 打包失败: " + e.getMessage(), e); + } + return baos.toByteArray(); + } + + private void writeEntry(ZipOutputStream zos, String entryPath, String content) throws IOException { + ZipEntry zipEntry = new ZipEntry(entryPath); + zipEntry.setSize(content.getBytes(StandardCharsets.UTF_8).length); + zos.putNextEntry(zipEntry); + zos.write(content.getBytes(StandardCharsets.UTF_8)); + zos.closeEntry(); + } + + /** + * 构造 entry 路径;遇到重名时加 _1 / _2 ... + */ + private String uniquePath(String group, String fileName, Set used) { + String base = sanitizeGroup(group) + "/" + fileName; + if (used.add(base)) { + return base; + } + int dot = fileName.lastIndexOf('.'); + String prefix = dot < 0 ? fileName : fileName.substring(0, dot); + String suffix = dot < 0 ? "" : fileName.substring(dot); + for (int i = 1; i < 1000; i++) { + String candidate = sanitizeGroup(group) + "/" + prefix + "_" + i + suffix; + if (used.add(candidate)) { + return candidate; + } + } + return sanitizeGroup(group) + "/" + System.nanoTime() + "_" + fileName; + } + + private String sanitizeGroup(String group) { + if (group == null || group.trim().isEmpty()) { + return "generated"; + } + return group.trim().replaceAll("[\\\\/:*?\"<>|\\r\\n\\t]", "_"); + } +} diff --git a/src/main/java/com/softdev/system/generator/util/ZipFileNameResolver.java b/src/main/java/com/softdev/system/generator/util/ZipFileNameResolver.java new file mode 100644 index 0000000..d3d741b --- /dev/null +++ b/src/main/java/com/softdev/system/generator/util/ZipFileNameResolver.java @@ -0,0 +1,148 @@ +package com.softdev.system.generator.util; + +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 文件名解析器 + *

+ * 解析模板配置中的 fileName 字段,支持 ${className}、${tableName}、${group}、${name} 占位符。 + *

+ * 解析规则: + *

    + *
  • 若 fileName 中含 ${xxx} 占位符,则按占位符从 context 解析
  • + *
  • 若 fileName 为空,则根据 template.name + group 自动推断(兜底策略)
  • + *
  • 自动清理非法字符,确保可作为文件名
  • + *
+ * + * @author zhengkai.blog.csdn.net + */ +public final class ZipFileNameResolver { + + private static final Pattern PLACEHOLDER = Pattern.compile("\\$\\{([^}]+)\\}"); + + private static final Pattern INVALID_FILE_NAME_CHARS = Pattern.compile("[\\\\/:*?\"<>|\\r\\n\\t]"); + + private ZipFileNameResolver() { + } + + /** + * 解析文件名 + * + * @param fileNameTemplate 模板配置中的 fileName(可为 null/空) + * @param templateName 模板 name(如 controller / model / mapper) + * @param group 模板 group(如 mybatis / jpa / ui) + * @param context 占位符上下文(至少含 className、tableName) + * @return 最终文件名(不含路径) + */ + public static String resolve(String fileNameTemplate, + String templateName, + String group, + Map context) { + String raw = (fileNameTemplate == null || fileNameTemplate.trim().isEmpty()) + ? guessByConvention(templateName, group, context) + : fileNameTemplate; + + String resolved = replacePlaceholders(raw, context); + return sanitize(resolved, templateName, group, context); + } + + /** + * 兜底策略:根据模板名 + 分组推断文件名 + */ + private static String guessByConvention(String templateName, String group, Map context) { + String className = stringOf(context, "className"); + if (className == null || className.isEmpty()) { + className = stringOf(context, "tableName"); + } + if (className == null || className.isEmpty()) { + className = "Generated"; + } + String ext = guessExtension(templateName, group); + if (ext == null || ext.isEmpty()) { + return className + "-" + templateName; + } + return className + ext; + } + + /** + * 推断文件后缀 + */ + private static String guessExtension(String templateName, String group) { + if (group != null) { + switch (group.toLowerCase()) { + case "ui": + case "renren-fast": + return "-" + templateName + ".html"; + case "bi": + case "cloud": + return "-" + templateName + ".txt"; + default: + break; + } + } + if (templateName == null) { + return ".txt"; + } + if (templateName.contains("xml") || templateName.endsWith("-xml")) { + return ".xml"; + } + if (templateName.contains("yml") || templateName.contains("yaml")) { + return ".yml"; + } + if (templateName.contains("sql")) { + return ".sql"; + } + if (templateName.contains("vue")) { + return ".vue"; + } + if (templateName.contains("json")) { + return ".json"; + } + if (templateName.contains("md")) { + return ".md"; + } + return ".java"; + } + + private static String replacePlaceholders(String input, Map context) { + if (input == null || !input.contains("${")) { + return input; + } + Matcher matcher = PLACEHOLDER.matcher(input); + StringBuilder sb = new StringBuilder(); + while (matcher.find()) { + String key = matcher.group(1); + String value = stringOf(context, key); + if (value == null) { + value = ""; + } + matcher.appendReplacement(sb, Matcher.quoteReplacement(value)); + } + matcher.appendTail(sb); + return sb.toString(); + } + + /** + * 清理非法字符;如果清理后为空则使用兜底 + */ + private static String sanitize(String fileName, String templateName, String group, Map context) { + if (fileName == null) { + return guessByConvention(templateName, group, context); + } + String cleaned = INVALID_FILE_NAME_CHARS.matcher(fileName).replaceAll("_").trim(); + if (cleaned.isEmpty() || ".".equals(cleaned) || "..".equals(cleaned)) { + return guessByConvention(templateName, group, context); + } + return cleaned; + } + + private static String stringOf(Map map, String key) { + if (map == null || key == null) { + return null; + } + Object v = map.get(key); + return v == null ? null : v.toString(); + } +} diff --git a/src/main/resources/statics/js/main.js b/src/main/resources/statics/js/main.js index 3ed97be..e892845 100644 --- a/src/main/resources/statics/js/main.js +++ b/src/main/resources/statics/js/main.js @@ -151,6 +151,54 @@ const vm = new Vue({ }, copy : function (){ navigator.clipboard.writeText(vm.outputStr.trim()).then(r => {alert("已复制")}); + }, + //download all generated code as ZIP + downloadZip : function (){ + //get value from codemirror + vm.formData.tableSql=$.inputArea.getValue(); + if(!vm.formData.tableSql || vm.formData.tableSql.trim().length<5){ + error("请先输入 SQL/JSON/INSERT 语句"); + return; + } + // 用 axios 发起请求,responseType: 'blob' 让浏览器把响应当作二进制流处理 + axios.post(basePath+"/code/generate-zip", vm.formData, {responseType: 'blob', timeout: 60000}) + .then(function(res){ + if(res.status !== 200){ + error("下载失败,HTTP 状态码:"+res.status); + return; + } + //尝试从 Content-Disposition 中解析文件名 + var dispo = res.headers && (res.headers['content-disposition'] || res.headers['Content-Disposition']); + var fileName = "code-generator.zip"; + if(dispo){ + var matchStar = /filename\*=UTF-8''([^;]+)/i.exec(dispo); + var matchQuoted = /filename="?([^";]+)"?/i.exec(dispo); + if(matchStar && matchStar[1]){ + fileName = decodeURIComponent(matchStar[1]); + }else if(matchQuoted && matchQuoted[1]){ + fileName = matchQuoted[1]; + } + } + // 创建 Blob 并触发浏览器下载 + var blob = new Blob([res.data], {type: 'application/zip'}); + if(window.navigator && window.navigator.msSaveBlob){ + window.navigator.msSaveBlob(blob, fileName); + }else{ + var url = window.URL.createObjectURL(blob); + var a = document.createElement('a'); + a.href = url; + a.download = fileName; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + } + alert("已下载:"+fileName); + }) + .catch(function(err){ + console.error(err); + error("下载失败:"+(err && err.message ? err.message : '未知错误')); + }); } }, created: function () { diff --git a/src/main/resources/template.json b/src/main/resources/template.json index 54ff69e..84d6667 100644 --- a/src/main/resources/template.json +++ b/src/main/resources/template.json @@ -3,27 +3,32 @@ "templates": [{ "id": "10", "name": "swagger-ui", - "description": "swagger-ui" + "description": "swagger-ui", + "fileName": "swagger-ui.json" }, { "id": "11", "name": "element-ui", - "description": "element-ui" + "description": "element-ui", + "fileName": "${className}-element-ui.html" }, { "id": "12", "name": "bootstrap-ui", - "description": "bootstrap-ui" + "description": "bootstrap-ui", + "fileName": "${className}-bootstrap-ui.html" }, { "id": "13", "name": "layui-edit", - "description": "layui-edit" + "description": "layui-edit", + "fileName": "${className}-layui-edit.html" }, { "id": "14", "name": "layui-list", - "description": "layui-list" + "description": "layui-list", + "fileName": "${className}-layui-list.html" } ] }, @@ -32,37 +37,44 @@ "templates": [{ "id": "20", "name": "controller", - "description": "controller" + "description": "controller", + "fileName": "${className}Controller.java" }, { "id": "21", "name": "service", - "description": "service" + "description": "service", + "fileName": "${className}Service.java" }, { "id": "22", "name": "service_impl", - "description": "service_impl" + "description": "service_impl", + "fileName": "${className}ServiceImpl.java" }, { "id": "23", "name": "mapper", - "description": "mapper" + "description": "mapper", + "fileName": "${className}Mapper.java" }, { "id": "24", "name": "mybatis", - "description": "mybatis" + "description": "mybatis", + "fileName": "${className}Mapper.xml" }, { "id": "25", "name": "model", - "description": "model" + "description": "model", + "fileName": "${className}.java" }, { "id": "26", "name": "mapper2", - "description": "mapper annotation" + "description": "mapper annotation", + "fileName": "${className}Mapper2.java" } ] }, @@ -71,17 +83,20 @@ "templates": [{ "id": "30", "name": "entity", - "description": "entity" + "description": "entity", + "fileName": "${className}.java" }, { "id": "31", "name": "repository", - "description": "repository" + "description": "repository", + "fileName": "${className}Repository.java" }, { "id": "32", "name": "jpacontroller", - "description": "jpacontroller" + "description": "jpacontroller", + "fileName": "${className}Controller.java" } ] }, @@ -91,12 +106,14 @@ "templates": [{ "id": "40", "name": "jtdao", - "description": "jtdao" + "description": "jtdao", + "fileName": "${className}Dao.java" }, { "id": "41", "name": "jtdaoimpl", - "description": "jtdaoimpl" + "description": "jtdaoimpl", + "fileName": "${className}DaoImpl.java" } ] }, @@ -106,17 +123,20 @@ "templates": [{ "id": "50", "name": "beetlmd", - "description": "beetlmd" + "description": "beetlmd", + "fileName": "${className}.md" }, { "id": "51", "name": "beetlentity", - "description": "beetlentity" + "description": "beetlentity", + "fileName": "${className}.java" }, { "id": "52", "name": "beetlcontroller", - "description": "beetlcontroller" + "description": "beetlcontroller", + "fileName": "${className}Controller.java" } ] }, @@ -126,22 +146,26 @@ "templates": [{ "id": "60", "name": "pluscontroller", - "description": "pluscontroller" + "description": "pluscontroller", + "fileName": "${className}Controller.java" }, { "id": "61", "name": "plusservice", - "description": "plusservice" + "description": "plusservice", + "fileName": "${className}Service.java" }, { "id": "62", "name": "plusmapper", - "description": "plusmapper" + "description": "plusmapper", + "fileName": "${className}Mapper.java" }, { "id": "63", "name": "plusentity", - "description": "plusentity" + "description": "plusentity", + "fileName": "${className}.java" } ] }, @@ -151,27 +175,32 @@ "templates": [{ "id": "70", "name": "beanutil", - "description": "beanutil" + "description": "beanutil", + "fileName": "${className}BeanUtil.txt" }, { "id": "71", "name": "json", - "description": "json" + "description": "json", + "fileName": "${className}.json" }, { "id": "72", "name": "xml", - "description": "xml" + "description": "xml", + "fileName": "${className}.xml" }, { "id": "73", "name": "sql", - "description": "sql" + "description": "sql", + "fileName": "${className}.sql" }, { "id": "74", "name": "swagger-yml", - "description": "swagger-yml" + "description": "swagger-yml", + "fileName": "swagger.yml" } ] }, @@ -181,12 +210,14 @@ "templates": [{ "id": "81", "name": "tkentity", - "description": "tkentity" + "description": "tkentity", + "fileName": "${className}.java" }, { "id": "82", "name": "tkmapper", - "description": "tkmapper" + "description": "tkmapper", + "fileName": "${className}Mapper.java" } ] }, @@ -196,37 +227,50 @@ "templates": [{ "id": "91", "name": "menu-sql", - "description": "menu-sql" + "description": "menu-sql", + "fileName": "menu.sql" }, { "id": "92", "name": "vue-list", - "description": "vue-list" + "description": "vue-list", + "fileName": "${className}-list.vue" }, { "id": "93", "name": "vue-edit", - "description": "vue-edit" + "description": "vue-edit", + "fileName": "${className}-edit.vue" }, { "id": "94", "name": "rr-controller", - "description": "rr-controller" + "description": "rr-controller", + "fileName": "${className}Controller.java" }, { "id": "95", "name": "rr-dao", - "description": "rr-dao" + "description": "rr-dao", + "fileName": "${className}Dao.java" }, { "id": "96", "name": "rr-daoxml", - "description": "rr-daoxml" + "description": "rr-daoxml", + "fileName": "${className}Dao.xml" }, { "id": "97", "name": "rr-service", - "description": "rr-service" + "description": "rr-service", + "fileName": "${className}Service.java" + }, + { + "id": "98", + "name": "rr-entity", + "description": "rr-entity", + "fileName": "${className}.java" } ] }, @@ -235,17 +279,20 @@ "templates": [{ "id": "101", "name": "starp-entity", - "description": "entity" + "description": "entity", + "fileName": "${className}.java" }, { "id": "102", "name": "starp-repository", - "description": "repository" + "description": "repository", + "fileName": "${className}Repository.java" }, { "id": "103", "name": "starp-jpa-controller", - "description": "jpacontroller" + "description": "jpacontroller", + "fileName": "${className}Controller.java" } ] }, @@ -254,7 +301,8 @@ "templates": [{ "id": "201", "name": "qliksense", - "description": "qlik sense" + "description": "qlik sense", + "fileName": "qliksense.txt" }] }, { @@ -263,12 +311,14 @@ { "id": "301", "name": "bigquery", - "description": "GCP BigQuery" + "description": "GCP BigQuery", + "fileName": "bigquery.sql" }, { "id": "302", "name": "dataflowjjs", - "description": "GCP Dataflow JJS" + "description": "GCP Dataflow JJS", + "fileName": "dataflow.jjs" } ] }, @@ -278,18 +328,21 @@ { "id": "401", "name": "tk-entity", - "description": "tk-entity" + "description": "tk-entity", + "fileName": "${className}.java" }, { "id": "402", "name": "tk-mapper", - "description": "tk-mapper" + "description": "tk-mapper", + "fileName": "${className}Mapper.java" }, { "id": "403", "name": "tk-controller", - "description": "tk-controller" + "description": "tk-controller", + "fileName": "${className}Controller.java" } ] } -] \ No newline at end of file +] diff --git a/src/main/resources/templates/newui2.html b/src/main/resources/templates/newui2.html index 93f5ee7..6d3c92f 100644 --- a/src/main/resources/templates/newui2.html +++ b/src/main/resources/templates/newui2.html @@ -178,6 +178,7 @@
生成 复制 + 下载 ZIP