mirror of
https://github.com/moshowgame/SpringBootCodeGenerator.git
synced 2025-12-26 05:48:33 +08:00
Merge pull request #170 from moshowgame/feature_rebuild_backend
Feature Refactoring backend
This commit is contained in:
commit
07cd5c408f
5
@run.cmd
5
@run.cmd
@ -1,4 +1,3 @@
|
||||
java -jar "./generator-web/target/generator-web-3.0.jar"
|
||||
pause
|
||||
mvn clean compile package
|
||||
mvn clean compile
|
||||
mvn spring-boot:run
|
||||
pause
|
||||
288
README.md
288
README.md
@ -1,4 +1,4 @@
|
||||
# SpringBootCodeGenerator
|
||||
# SpringBootCodeGenerator 大狼狗代码生成器
|
||||
----
|
||||
又名`Java代码生成器`、`JAVA在线代码生成平台`、`sql转java`、`大狼狗代码生成器`、`mybatis在线生成器`、`SQL转Java JPA、MYBATIS实现类代码生成平台`<br>
|
||||

|
||||
@ -7,9 +7,13 @@
|
||||
[](https://github.com/moshowgame/SpringBootCodeGenerator/actions/workflows/maven.yml)
|
||||
|
||||
# Author
|
||||
>powered by `Moshow郑锴(大狼狗)` , [https://zhengkai.blog.csdn.net](https://zhengkai.blog.csdn.net)
|
||||
>🚀
|
||||
Powered by `Moshow郑锴(大狼狗)` 🌟 Might the holy code be with you !
|
||||
> <br>**`CSDN`传送门**️️➡️ [https://zhengkai.blog.csdn.net](https://zhengkai.blog.csdn.net)
|
||||
> <br>**微信公众号**➡️`软件开发大百科`
|
||||
|
||||
# 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` 的高效代码生成平台
|
||||
|
||||
@ -34,47 +38,205 @@
|
||||
> 🙌 Special thanks to BeJSON 前站长 `三叔` 的慧眼与支持,让项目得以脱颖而出,感恩!
|
||||
|
||||
|
||||
# URL
|
||||
|
||||
- 感谢`卡卡`部署在[BEJSON](https://java.bejson.com/generator)上,目前是BeJSON专供的`金牌工具`<br>
|
||||
- 感谢`jully.top`部署的副本 [https://jully.top/generator/](https://jully.top/generator/)。<br>
|
||||
- 感谢`staticfile`CDN提供稳定、快速、免费的静态文件CDN加速服务(在线版本)
|
||||
## 功能特性
|
||||
|
||||
| 访问地址 | http://localhost:1234/generator |
|
||||
|:-----------------------|:--------------------------------------------------------------|
|
||||
| BEJSON 金牌工具 在线地址 | https://java.bejson.com/generator/ |
|
||||
| JSON.CN 金牌工具 在线地址 | https://java.json.cn/generator/ |
|
||||
| Jully 在线地址 | https://jully.top/generator/ |
|
||||
| NeverWaive 在线地址 | https://codegenerator.neverwaive.cn/ |
|
||||
| CSDN BLOG | https://zhengkai.blog.csdn.net |
|
||||
| GITEE仓库 | https://gitee.com/moshowgame/SpringBootCodeGenerator/releases |
|
||||
| GITHUB仓库 | https://github.com/moshowgame/SpringBootCodeGenerator |
|
||||
### 支持多种生成模式
|
||||
- DDL SQL 模式:通过建表语句生成代码
|
||||
- INSERT SQL 模式:通过插入语句生成代码
|
||||
- SELECT SQL 模式:通过查询语句生成代码
|
||||
- JSON 模式:通过 JSON 数据生成代码
|
||||
|
||||
# Tips or Features
|
||||
- 支持`DDL SQL`/`INSERT SQL`/`SIMPLE JSON`/`SELECT SQL`(*New)四种生成模式
|
||||
- `自动记忆`最近生成的内容,最多保留9个
|
||||
- 提供众多`通用模板`,易于使用,复制粘贴加简单修改即可完成CRUD操作
|
||||
- 支持`特殊字符`模板(`#`请用`井`代替;`$`请用`¥`代替)
|
||||
- `Util集合`提供一些基本对象的使用方法供方便COPY,如对应的CRUD SQL语句、setMap、getMap、get属性等等
|
||||
- 关于`类名注释`,可根据`comment=(mysql)`或者`comment on table(pgsql/oracle)`生成
|
||||
- 可设置是否`自动引包`(java中的import)及`引入包路径`(java类中的package),建议取消并配合IDEA的自动引包更智能(Settings→Editor→General→Auto Import,勾选Add unambiguous imports on the fly以及Optimize imports on the fly)。
|
||||
- 可设置`表名前缀`,例如sys_user前缀为sys_之后可以正确生成user类
|
||||
- 可在`applicaltion.yml`中的`OEM.mode`设置`js/css引入模式`为`local`(本地模式,默认)/`CDN`(云CDN模式,在线网站推荐,省流量)
|
||||
- OEM信息可以在`applicaltion.yml`中的`OEM`中更改
|
||||
- *支持公共js/css的Local/CDN模式切换,方便`本地`或者`工具站`进行部署,可以在`application.yml`的`OEM.Mode=`进行设置,之后请在`header-CDN-v2.html`/`header-local-v2.html`中检查对应js/css配置是否正确。默认为`CDN`模式。对于没有网络的环境请使用`local`模式。
|
||||
- 如何判断是否包含Date日期类并引入,搜索`<#assign importDdate = true />`即可找到对应的方法判断和引入
|
||||
### 支持多种模板
|
||||
- JPA 模板
|
||||
- MyBatis 模板
|
||||
- MyBatis-Plus 模板
|
||||
- BeetlSQL 模板
|
||||
- CommonMapper 模板
|
||||
- TkMyBatis 模板
|
||||
- JDBC Template 模板
|
||||
- 前端 UI 模板(Element UI、Bootstrap UI 等)
|
||||
|
||||
# Branch Detail 分支介绍
|
||||
- Master:主力分支,基于SpringBoot3+,需要JDK17+
|
||||
- JDK11:兼容分支,版本落后,基于SpringBoot2+,但支持JDK8/JDK11等旧JDK版本[https://github.com/moshowgame/SpringBootCodeGenerator/tree/jdk11]
|
||||
### 其他特性
|
||||
- 自动记忆最近生成的内容
|
||||
- 支持特殊字符模板(# 用 井 代替,$ 用 ¥ 代替)
|
||||
- 可设置表名前缀
|
||||
- 可选择是否自动引包
|
||||
- 支持本地/CDN 静态资源引入模式切换
|
||||
|
||||
# 更新预告
|
||||
1.计划加入AI来帮忙生成更多样式的模板
|
||||
2.改进JSqlParser Engine (Select SQL and Create SQL)
|
||||
## 技术栈
|
||||
|
||||
- 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
|
||||
|
||||
### 添加新模板
|
||||
|
||||
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
|
||||
[](https://starchart.cc/moshowgame/SpringBootCodeGenerator)
|
||||
|
||||
2025 NewUI V2版本<br>
|
||||
<img src="./newui_version_2.png">
|
||||
配置模板<br>
|
||||
<img src="./codegenerator2.png">
|
||||
网站流量分析-2024<br>
|
||||
<img src="./site_analysis-2024.png">
|
||||
代码与你,越变越强<br>
|
||||
<img src="./donate.png">
|
||||
|
||||
# Update Logs
|
||||
| 更新日期 | 更新内容 |
|
||||
|:-----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 2025.12.07 | 后端重构优化 ;目录结构调整! |
|
||||
| 2025.09.14 | 优化JSqlParser Engine(DDL Create SQL和Select SQL),适配更高级复杂的SQL |
|
||||
| 2025.09.13 | JSqlParser Engine全新升级,目前Select SQL模式相对稳定! <br>更新SpringBoot等类库版本,修复漏洞<br>修复CDN问题,切换为staticfile.org |
|
||||
| 2025.09.06 | 处理建表字段包含 using 字符时无法生成对应字段的情况(感谢@wubiaoo的反馈和@willxiang的PR) |
|
||||
@ -147,61 +309,3 @@
|
||||
| 2018.09.15 | 新增Swagger-UI模板.修复一些命名和导入问题.JPA的Entity默认第一个字段为Id,如果不是请手工修改. |
|
||||
| 2018.09.13 | 修复字段没有描述以及类型为DATE型导致的问题.新增JPA的Controller模板. |
|
||||
| 2018.08.31 | 初始化项目.新增JPA系列Entity+Repository模板. |
|
||||
|
||||
# ClassInfo/TableInfo
|
||||
|名称|说明|
|
||||
|:----|:----|
|
||||
|packageName|自定义的包名|
|
||||
|authorName|自定义的作者名|
|
||||
|tableName|sql中的表名|
|
||||
|className|java类名|
|
||||
|classComment|sql表备注/java类备注|
|
||||
|fieldName|字段名|
|
||||
|fieldComment|字段备注|
|
||||
|
||||
# Options
|
||||
|名称|说明|默认值|
|
||||
|:----|:----|:----|
|
||||
|作者 |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|
|
||||
|
||||
|
||||
# How to add a new template
|
||||
1. `resources/templates/code-generator`中找到对应类型
|
||||
2. COPY并编写freemarker模板文件`.ftl`
|
||||
3. 修改`template.json`文件,新增模板信息,页面可动态加载
|
||||
|
||||
# Upgrade Issue Resolution 升级问题解决方案
|
||||
- 如果你最近也在升级FastJson到FastJson2版本,而跟我一样也遇到了FastJsonHttpMessageConverter找不到类问题以及FastJsonConfig找不到问题,那么恭喜你,看完本文,安装完fastjson2、fastjson2-extension、fastjson2-extension-spring6这三个类库,你就可以成功使用新版FastJson2了。
|
||||
[FastJson2中FastJsonHttpMessageConverter找不到类问题](https://blog.csdn.net/moshowgame/article/details/138013669)
|
||||
|
||||
- 当项目从2.7.x的springboot升级到3.0.x的时候,遇到一个问题“java: 程序包javax.servlet.http不存在” 问题:
|
||||
[java: 程序包javax.servlet.http不存在](https://zhengkai.blog.csdn.net/article/details/131362304)
|
||||
|
||||
- [CSDN【SpringBoot2启示录】专栏](https://blog.csdn.net/moshowgame/category_9274885.html)
|
||||
|
||||
## Stargazers over time
|
||||
[](https://starchart.cc/moshowgame/SpringBootCodeGenerator)
|
||||
|
||||
2025 NewUI V2版本
|
||||
<img src="./newui_version_2.png">
|
||||
配置模板
|
||||
<img src="./codegenerator2.png">
|
||||
网站流量分析-2024
|
||||
<img src="./site_analysis-2024.png">
|
||||
代码与你,越变越美
|
||||
<img src="./donate.png">
|
||||
|
||||
|
||||
217
REFACTORING_DOCUMENT.md
Normal file
217
REFACTORING_DOCUMENT.md
Normal file
@ -0,0 +1,217 @@
|
||||
# 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. **增加常量定义**:将硬编码的字符串提取为常量,提高可维护性
|
||||
@ -1,128 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.softdev.system</groupId>
|
||||
<artifactId>SpringBootCodeGenerator</artifactId>
|
||||
<version>2023</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>generator-web</artifactId>
|
||||
<version>3.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail -->
|
||||
<!--<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>1.6.1</version>
|
||||
</dependency>-->
|
||||
|
||||
|
||||
<!-- spring-data-jpa -->
|
||||
<!--<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.32</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<!--解决idea打包没有xml-->
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
<compilerId>javac</compilerId>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<compilerVersion>1.8</compilerVersion>
|
||||
<verbose>true</verbose>
|
||||
<optimize>true</optimize>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-compiler-eclipse</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<!--<failOnMissingWebXml>false</failOnMissingWebXml>-->
|
||||
<includeEmptyDirs>true</includeEmptyDirs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!--<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>3.2.3</version>
|
||||
<configuration>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
<warSourceExcludes>upload/**</warSourceExcludes>
|
||||
</configuration>
|
||||
</plugin>-->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
</project>
|
||||
@ -1,105 +0,0 @@
|
||||
package com.softdev.system.generator.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.softdev.system.generator.entity.ClassInfo;
|
||||
import com.softdev.system.generator.entity.ParamInfo;
|
||||
import com.softdev.system.generator.entity.ReturnT;
|
||||
import com.softdev.system.generator.service.GeneratorService;
|
||||
import com.softdev.system.generator.util.MapUtil;
|
||||
import com.softdev.system.generator.util.TableParseUtil;
|
||||
import com.softdev.system.generator.util.ValueUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.statement.Statement;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 代码生成控制器
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Controller
|
||||
@Slf4j
|
||||
public class GeneratorController {
|
||||
@Autowired
|
||||
private ValueUtil valueUtil;
|
||||
|
||||
@Autowired
|
||||
private GeneratorService generatorService;
|
||||
|
||||
@GetMapping("/")
|
||||
public ModelAndView defaultPage() {
|
||||
return new ModelAndView("newui2").addObject("value",valueUtil);
|
||||
}
|
||||
@GetMapping("/index")
|
||||
public ModelAndView indexPage() {
|
||||
return new ModelAndView("newui2").addObject("value",valueUtil);
|
||||
}
|
||||
|
||||
@RequestMapping("/template/all")
|
||||
@ResponseBody
|
||||
public ReturnT getAllTemplates() throws Exception {
|
||||
String templates = generatorService.getTemplateConfig();
|
||||
return ReturnT.ok().put("templates", JSONArray.parseArray(templates));
|
||||
}
|
||||
@PostMapping("/code/generate")
|
||||
@ResponseBody
|
||||
public ReturnT generateCode(@RequestBody ParamInfo paramInfo) throws Exception {
|
||||
//log.info(JSON.toJSONString(paramInfo.getOptions()));
|
||||
if (StringUtils.isEmpty(paramInfo.getTableSql())) {
|
||||
return ReturnT.error("表结构信息为空");
|
||||
}
|
||||
//1.Parse Table Structure 表结构解析
|
||||
ClassInfo classInfo = null;
|
||||
String dataType = MapUtil.getString(paramInfo.getOptions(),"dataType");
|
||||
switch (dataType) {
|
||||
case "sql":
|
||||
//默认模式:parse DDL table structure from sql
|
||||
classInfo = generatorService.processTableIntoClassInfo(paramInfo);
|
||||
break;
|
||||
case "json":
|
||||
//JSON模式:parse field from json string
|
||||
classInfo = generatorService.processJsonToClassInfo(paramInfo);
|
||||
break;
|
||||
case "insert-sql":
|
||||
//INSERT SQL模式:parse field from insert sql
|
||||
classInfo = generatorService.processInsertSqlToClassInfo(paramInfo);
|
||||
break;
|
||||
case "sql-regex":
|
||||
//正则表达式模式(非完善版本):parse sql by regex
|
||||
classInfo = generatorService.processTableToClassInfoByRegex(paramInfo);
|
||||
break;
|
||||
case "select-sql":
|
||||
//SelectSqlBySQLPraser模式:parse select sql by JSqlParser
|
||||
classInfo = generatorService.generateSelectSqlBySQLPraser(paramInfo);
|
||||
break;
|
||||
case "create-sql":
|
||||
//CreateSqlBySQLPraser模式:parse create sql by JSqlParser
|
||||
classInfo = generatorService.generateCreateSqlBySQLPraser(paramInfo);
|
||||
break;
|
||||
default:
|
||||
//默认模式:parse DDL table structure from sql
|
||||
classInfo = generatorService.processTableIntoClassInfo(paramInfo);
|
||||
break;
|
||||
}
|
||||
//2.Set the params 设置表格参数
|
||||
paramInfo.getOptions().put("classInfo", classInfo);
|
||||
paramInfo.getOptions().put("tableName", classInfo == null ? System.currentTimeMillis() : classInfo.getTableName());
|
||||
|
||||
//log the generated table and filed size记录解析了什么表,有多少个字段
|
||||
//log.info("generated table :{} , size :{}",classInfo.getTableName(),(classInfo.getFieldList() == null ? "" : classInfo.getFieldList().size()));
|
||||
|
||||
//3.generate the code by freemarker templates with parameters . Freemarker根据参数和模板生成代码
|
||||
Map<String, String> result = generatorService.getResultByParams(paramInfo.getOptions());
|
||||
// log.info("result {}",result);
|
||||
log.info("table:{} - time:{} ", MapUtil.getString(result,"tableName"),new Date());
|
||||
return ReturnT.ok().put("outputJson",result);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
package com.softdev.system.generator.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* common returnT:公共返回封装类
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class ReturnT extends HashMap<String, Object> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ReturnT() {
|
||||
put("code", 0);
|
||||
put("msg", "success");
|
||||
}
|
||||
|
||||
public static ReturnT error() {
|
||||
return error(500, "未知异常,请联系管理员");
|
||||
}
|
||||
|
||||
public static ReturnT error(String msg) {
|
||||
return error(500, msg);
|
||||
}
|
||||
|
||||
public static ReturnT error(int code, String msg) {
|
||||
ReturnT r = new ReturnT();
|
||||
r.put("code", code);
|
||||
r.put("msg", msg);
|
||||
return r;
|
||||
}
|
||||
public static ReturnT define(int code, String msg) {
|
||||
ReturnT r = new ReturnT();
|
||||
r.put("code", code);
|
||||
r.put("msg", msg);
|
||||
return r;
|
||||
}
|
||||
public static ReturnT ok(String msg) {
|
||||
ReturnT r = new ReturnT();
|
||||
r.put("msg", msg);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static ReturnT ok(Map<String, Object> map) {
|
||||
ReturnT r = new ReturnT();
|
||||
r.putAll(map);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static ReturnT ok() {
|
||||
return new ReturnT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT put(String key, Object value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
package com.softdev.system.generator.service;
|
||||
|
||||
import com.softdev.system.generator.entity.ClassInfo;
|
||||
import com.softdev.system.generator.entity.ParamInfo;
|
||||
import freemarker.template.TemplateException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* GeneratorService
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public interface GeneratorService {
|
||||
|
||||
String getTemplateConfig() throws IOException;
|
||||
|
||||
Map<String, String> getResultByParams(Map<String, Object> params) throws IOException, TemplateException;
|
||||
/**
|
||||
* 解析Select-SQL生成类信息(JSQLPraser版本)
|
||||
* @auther: zhengkai.blog.csdn.net
|
||||
* @param paramInfo
|
||||
* @return
|
||||
*/
|
||||
ClassInfo generateSelectSqlBySQLPraser(ParamInfo paramInfo) throws Exception;
|
||||
ClassInfo generateCreateSqlBySQLPraser(ParamInfo paramInfo) throws Exception;
|
||||
/**
|
||||
* 解析DDL-SQL生成类信息
|
||||
* @auther: zhengkai.blog.csdn.net
|
||||
* @param paramInfo
|
||||
* @return
|
||||
*/
|
||||
ClassInfo processTableIntoClassInfo(ParamInfo paramInfo) throws Exception;
|
||||
/**
|
||||
* 解析JSON生成类信息
|
||||
* @auther: zhengkai.blog.csdn.net
|
||||
* @param paramInfo
|
||||
* @return
|
||||
*/
|
||||
ClassInfo processJsonToClassInfo(ParamInfo paramInfo);
|
||||
/**
|
||||
* 解析DDL SQL生成类信息-正则表达式版本
|
||||
* @auther: zhengkai.blog.csdn.net
|
||||
* @param paramInfo
|
||||
* @return
|
||||
*/
|
||||
ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo);
|
||||
/**
|
||||
* 解析INSERT-SQL生成类信息-正则表达式版本
|
||||
* @auther: zhengkai.blog.csdn.net
|
||||
* @param paramInfo
|
||||
* @return
|
||||
*/
|
||||
ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package com.softdev.system.generator.util;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.softdev.system.generator.entity.ClassInfo;
|
||||
import com.softdev.system.generator.entity.FieldInfo;
|
||||
import com.softdev.system.generator.entity.NonCaseString;
|
||||
import com.softdev.system.generator.entity.ParamInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 表格解析Util
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public class TableParseUtil {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,236 +0,0 @@
|
||||
//iframe自适应
|
||||
$(window).on('resize', function() {
|
||||
const $content = $('.content');
|
||||
$content.height($(this).height() - 154);
|
||||
$content.find('iframe').each(function() {
|
||||
$(this).height($content.height());
|
||||
});
|
||||
}).resize();
|
||||
|
||||
const vm = new Vue({
|
||||
el: '#rrapp',
|
||||
data: {
|
||||
main: "main",
|
||||
},
|
||||
methods: {
|
||||
donate: function () {
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
|
||||
},
|
||||
updated: function () {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$.inputArea = undefined;
|
||||
$.outputArea = undefined;
|
||||
|
||||
$(function(){
|
||||
//powered by zhengkai.blog.csdn.net
|
||||
|
||||
//init input code area
|
||||
$.inputArea = CodeMirror.fromTextArea(document.getElementById("inputArea"), {
|
||||
mode: "text/x-sql", // SQL
|
||||
theme: "idea", // IDEA主题
|
||||
lineNumbers: true, //显示行号
|
||||
smartIndent: true, // 自动缩进
|
||||
autoCloseBrackets: true// 自动补全括号
|
||||
});
|
||||
$.inputArea.setSize('auto','auto');
|
||||
|
||||
// init output code area
|
||||
$.outputArea = CodeMirror.fromTextArea(document.getElementById("outputArea"), {
|
||||
mode: "text/x-java", // JAV
|
||||
theme: "idea", // IDEA主题
|
||||
lineNumbers: true, //显示行号
|
||||
smartIndent: true, // 自动缩进
|
||||
autoCloseBrackets: true// 自动补全括号
|
||||
});
|
||||
$.outputArea.setSize('auto','auto');
|
||||
|
||||
});
|
||||
|
||||
|
||||
const vm = new Vue({
|
||||
el: '#rrapp',
|
||||
data: {
|
||||
formData: {
|
||||
tableSql: "CREATE TABLE 'sys_user_info' (\n" +
|
||||
" 'user_id' int(11) NOT NULL AUTO_INCREMENT COMMENT '用户编号',\n" +
|
||||
" 'user_name' varchar(255) NOT NULL COMMENT '用户名',\n" +
|
||||
" 'status' tinyint(1) NOT NULL COMMENT '状态',\n" +
|
||||
" 'create_time' datetime NOT NULL COMMENT '创建时间',\n" +
|
||||
//下面可以留着方便开发调试时打开
|
||||
// " `updateTime` datetime NOT NULL COMMENT '更新时间',\n" +
|
||||
// " ABc_under_Line-Hypen-CamelCase varchar comment '乱七八糟的命名风格',\n" +
|
||||
" PRIMARY KEY ('user_id')\n" +
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息'",
|
||||
options: {
|
||||
dataType: "sql",
|
||||
|
||||
authorName: "${(value.author)!!}",
|
||||
packageName: "${(value.packageName)!!}",
|
||||
returnUtilSuccess: "${(value.returnUtilSuccess)!!}",
|
||||
returnUtilFailure: "${(value.returnUtilFailure)!!}",
|
||||
|
||||
isPackageType: true,
|
||||
isSwagger: false,
|
||||
isAutoImport: false,
|
||||
isWithPackage: false,
|
||||
isComment: true,
|
||||
isLombok: true,
|
||||
|
||||
ignorePrefix:"sys_",
|
||||
tinyintTransType: "int",
|
||||
nameCaseType: "CamelCase",
|
||||
timeTransType: "Date"
|
||||
}
|
||||
},
|
||||
templates:[{}],
|
||||
historicalData:[],
|
||||
currentSelect:'plusentity',
|
||||
outputStr: "${(value.outputStr)!!}",
|
||||
outputJson: {}
|
||||
},
|
||||
methods: {
|
||||
//set the template for output 选择页面输出的模板类型
|
||||
setOutputModel: function (event) {
|
||||
const targetModel = event.target.innerText.trim();
|
||||
console.log(targetModel);
|
||||
vm.currentSelect = targetModel ;
|
||||
if(vm.outputStr.length>30){
|
||||
vm.outputStr=vm.outputJson[targetModel];
|
||||
$.outputArea.setValue(vm.outputStr.trim());
|
||||
//console.log(vm.outputStr);
|
||||
$.outputArea.setSize('auto', 'auto');
|
||||
}
|
||||
},
|
||||
//switch HistoricalData
|
||||
switchHistoricalData: function (event) {
|
||||
const tableName = event.target.innerText.trim();
|
||||
console.log(tableName);
|
||||
if (window.sessionStorage){
|
||||
const valueSession = sessionStorage.getItem(tableName);
|
||||
vm.outputJson = JSON.parse(valueSession);
|
||||
console.log(valueSession);
|
||||
alert("切换历史记录成功:"+tableName);
|
||||
}else{
|
||||
alert("浏览器不支持sessionStorage");
|
||||
}
|
||||
vm.outputStr=vm.outputJson[vm.currentSelect].trim();
|
||||
$.outputArea.setValue(vm.outputStr);
|
||||
//console.log(vm.outputStr);
|
||||
$.outputArea.setSize('auto', 'auto');
|
||||
},
|
||||
setHistoricalData : function (tableName){
|
||||
//add new table only
|
||||
if(vm.historicalData.indexOf(tableName)<0){
|
||||
vm.historicalData.unshift(tableName);
|
||||
}
|
||||
//remove last record , if more than N
|
||||
if(vm.historicalData.length>9){
|
||||
vm.historicalData.splice(9,1);
|
||||
}
|
||||
//get and set to session data
|
||||
const valueSession = sessionStorage.getItem(tableName);
|
||||
//remove if exists
|
||||
if(valueSession!==undefined && valueSession!=null){
|
||||
sessionStorage.removeItem(tableName);
|
||||
}
|
||||
//set data to session
|
||||
sessionStorage.setItem(tableName,JSON.stringify(vm.outputJson));
|
||||
//console.log(vm.historicalData);
|
||||
},
|
||||
//request with formData to generate the code 根据参数生成代码
|
||||
generate : function(){
|
||||
//get value from codemirror
|
||||
vm.formData.tableSql=$.inputArea.getValue();
|
||||
axios.post(basePath+"/code/generate",vm.formData).then(function(res){
|
||||
if(res.code===500){
|
||||
error("生成失败,请检查SQL语句!!!");
|
||||
return;
|
||||
}
|
||||
setAllCookie();
|
||||
//console.log(res.outputJson);
|
||||
//兼容后端返回数据格式
|
||||
if(res.data){
|
||||
vm.outputJson = res.data.outputJson;
|
||||
}else {
|
||||
vm.outputJson = res.outputJson;
|
||||
}
|
||||
|
||||
// console.log(vm.outputJson["bootstrap-ui"]);
|
||||
vm.outputStr=vm.outputJson[vm.currentSelect].trim();
|
||||
//console.log(vm.outputJson["bootstrap-ui"]);
|
||||
//console.log(vm.outputStr);
|
||||
$.outputArea.setValue(vm.outputStr);
|
||||
$.outputArea.setSize('auto', 'auto');
|
||||
//add to historicalData
|
||||
vm.setHistoricalData(vm.outputJson.tableName);
|
||||
alert("生成成功");
|
||||
});
|
||||
},
|
||||
copy : function (){
|
||||
navigator.clipboard.writeText(vm.outputStr.trim()).then(r => {alert("已复制")});
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
//load all templates for selections 加载所有模板供选择
|
||||
axios.post(basePath+"/template/all",{
|
||||
id:1234
|
||||
}).then(function(res){
|
||||
//console.log(res.templates);
|
||||
// vm.templates = JSON.parse(res.templates);
|
||||
// console.log(res);
|
||||
//兼容后端返回数据格式
|
||||
if(res.data){
|
||||
vm.templates = res.data.templates;
|
||||
}else {
|
||||
vm.templates = res.templates;
|
||||
}
|
||||
});
|
||||
},
|
||||
updated: function () {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 将所有 需要 保留历史纪录的字段写入Cookie中
|
||||
*/
|
||||
function setAllCookie() {
|
||||
var arr = list_key_need_load();
|
||||
for (var str of arr){
|
||||
setOneCookie(str);
|
||||
}
|
||||
}
|
||||
|
||||
function setOneCookie(key) {
|
||||
setCookie(key, vm.formData.options[key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有 历史纪录 重加载回页面
|
||||
*/
|
||||
function loadAllCookie() {
|
||||
//console.log(vm);
|
||||
var arr = list_key_need_load();
|
||||
for (var str of arr){
|
||||
loadOneCookie(str);
|
||||
}
|
||||
}
|
||||
|
||||
function loadOneCookie(key) {
|
||||
if (getCookie(key)!==""){
|
||||
vm.formData.options[key] = getCookie(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 所有 需要 纪录的 字段写入数组
|
||||
* @returns {[string]}
|
||||
*/
|
||||
function list_key_need_load() {
|
||||
return ["authorName","packageName","returnUtilSuccess","returnUtilFailure","ignorePrefix","tinyintTransType","timeTransType"];
|
||||
}
|
||||
38
pom.xml
38
pom.xml
@ -5,19 +5,15 @@
|
||||
|
||||
<groupId>com.softdev.system</groupId>
|
||||
<artifactId>SpringBootCodeGenerator</artifactId>
|
||||
<version>2023</version>
|
||||
<packaging>pom</packaging>
|
||||
<version>2025</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.5.5</version>
|
||||
<version>3.5.8</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
<module>generator-web</module>
|
||||
</modules>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>alimaven</id>
|
||||
@ -41,6 +37,16 @@
|
||||
<artifactId>jsqlparser</artifactId>
|
||||
<version>5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -70,27 +76,21 @@
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.58</version>
|
||||
<version>2.0.60</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2-extension</artifactId>
|
||||
<version>2.0.58</version>
|
||||
<version>2.0.60</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2-extension-spring6 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2-extension-spring6</artifactId>
|
||||
<version>2.0.58</version>
|
||||
<version>2.0.59</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>6.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 支持 @ConfigurationProperties 注解 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -117,7 +117,7 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.40</version>
|
||||
<version>1.18.42</version>
|
||||
</dependency>
|
||||
|
||||
<!-- freemarker -->
|
||||
@ -136,7 +136,7 @@
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<version>4.0.2</version>
|
||||
<version>4.0.4</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
/**
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(scanBasePackages = "com.softdev.system.generator")
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
@ -1,12 +1,11 @@
|
||||
package com.softdev.system.generator.config;
|
||||
|
||||
import com.softdev.system.generator.entity.ReturnT;
|
||||
import com.softdev.system.generator.entity.vo.ResultVo;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@ -15,9 +14,9 @@ public class GlobalDefaultExceptionHandler {
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseBody
|
||||
public ReturnT defaultExceptionHandler(HttpServletRequest req, Exception e) {
|
||||
public ResultVo defaultExceptionHandler(HttpServletRequest req, Exception e) {
|
||||
e.printStackTrace();
|
||||
return ReturnT.error("代码生成失败:"+e.getMessage());
|
||||
return ResultVo.error("代码生成失败:"+e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,25 +1,16 @@
|
||||
package com.softdev.system.generator.config;
|
||||
|
||||
|
||||
// import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
// import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import com.alibaba.fastjson2.JSONReader;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.alibaba.fastjson2.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson2.support.spring6.http.converter.FastJsonHttpMessageConverter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
/**
|
||||
@ -0,0 +1,29 @@
|
||||
package com.softdev.system.generator.controller;
|
||||
|
||||
import com.softdev.system.generator.entity.dto.ParamInfo;
|
||||
import com.softdev.system.generator.entity.vo.ResultVo;
|
||||
import com.softdev.system.generator.service.CodeGenService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* 代码生成控制器
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/code")
|
||||
public class CodeGenController {
|
||||
|
||||
private final CodeGenService codeGenService;
|
||||
|
||||
@PostMapping("/generate")
|
||||
public ResultVo generateCode(@RequestBody ParamInfo paramInfo) throws Exception {
|
||||
return codeGenService.generateCode(paramInfo);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.softdev.system.generator.controller;
|
||||
|
||||
import com.softdev.system.generator.util.ValueUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* 页面控制器
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Controller
|
||||
public class PageController {
|
||||
|
||||
private final ValueUtil valueUtil;
|
||||
|
||||
@GetMapping("/")
|
||||
public ModelAndView defaultPage() {
|
||||
return new ModelAndView("newui2").addObject("value", valueUtil);
|
||||
}
|
||||
|
||||
@GetMapping("/index")
|
||||
public ModelAndView indexPage() {
|
||||
return new ModelAndView("newui2").addObject("value", valueUtil);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.softdev.system.generator.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.softdev.system.generator.entity.vo.ResultVo;
|
||||
import com.softdev.system.generator.service.TemplateService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 模板管理控制器
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/template")
|
||||
public class TemplateController {
|
||||
|
||||
private final TemplateService templateService;
|
||||
|
||||
@PostMapping("/all")
|
||||
public ResultVo getAllTemplates() throws Exception {
|
||||
return ResultVo.ok(templateService.getAllTemplates());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.softdev.system.generator.entity.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 类信息
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Data
|
||||
public class ClassInfo {
|
||||
|
||||
private String tableName;
|
||||
private String originTableName;
|
||||
private String className;
|
||||
private String classComment;
|
||||
private List<FieldInfo> fieldList;
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.softdev.system.generator.entity.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 字段信息
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Data
|
||||
public class FieldInfo {
|
||||
|
||||
private String columnName;
|
||||
private String fieldName;
|
||||
private String fieldClass;
|
||||
private String swaggerClass;
|
||||
private String fieldComment;
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.softdev.system.generator.entity.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 请求参数信息
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Data
|
||||
public class ParamInfo {
|
||||
|
||||
private String tableSql;
|
||||
private Map<String, Object> options;
|
||||
|
||||
@Data
|
||||
public static class NameCaseType {
|
||||
public static final String CAMEL_CASE = "CamelCase";
|
||||
public static final String UNDER_SCORE_CASE = "UnderScoreCase";
|
||||
public static final String UPPER_UNDER_SCORE_CASE = "UpperUnderScoreCase";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.softdev.system.generator.entity.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 解析类型枚举
|
||||
*/
|
||||
@Getter
|
||||
public enum ParserTypeEnum {
|
||||
|
||||
/**
|
||||
* SQL解析类型
|
||||
*/
|
||||
SQL("sql", "默认SQL解析"),
|
||||
JSON("json", "JSON解析"),
|
||||
INSERT_SQL("insert-sql", "INSERT SQL解析"),
|
||||
SQL_REGEX("sql-regex", "正则表达式SQL解析"),
|
||||
SELECT_SQL("select-sql", "SELECT SQL解析"),
|
||||
CREATE_SQL("create-sql", "CREATE SQL解析");
|
||||
|
||||
private final String value;
|
||||
private final String description;
|
||||
|
||||
ParserTypeEnum(String value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public static ParserTypeEnum fromValue(String value) {
|
||||
for (ParserTypeEnum type : ParserTypeEnum.values()) {
|
||||
if (type.getValue().equals(value)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
// 默认返回SQL类型
|
||||
return SQL;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.softdev.system.generator.entity.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 统一返回结果VO
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Data
|
||||
public class ResultVo extends HashMap<String, Object> {
|
||||
|
||||
public ResultVo() {
|
||||
put("code", 200);
|
||||
put("msg", "success");
|
||||
}
|
||||
|
||||
public static ResultVo ok() {
|
||||
return new ResultVo();
|
||||
}
|
||||
|
||||
public static ResultVo ok(Object data) {
|
||||
ResultVo resultVo = new ResultVo();
|
||||
resultVo.put("data", data);
|
||||
return resultVo;
|
||||
}
|
||||
|
||||
public static ResultVo error(String msg) {
|
||||
ResultVo resultVo = new ResultVo();
|
||||
resultVo.put("code", 500);
|
||||
resultVo.put("msg", msg);
|
||||
return resultVo;
|
||||
}
|
||||
|
||||
public static ResultVo error(int code, String msg) {
|
||||
ResultVo resultVo = new ResultVo();
|
||||
resultVo.put("code", code);
|
||||
resultVo.put("msg", msg);
|
||||
return resultVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultVo put(String key, Object value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.softdev.system.generator.service;
|
||||
|
||||
import com.softdev.system.generator.entity.dto.ClassInfo;
|
||||
import com.softdev.system.generator.entity.dto.ParamInfo;
|
||||
import com.softdev.system.generator.entity.vo.ResultVo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 代码生成服务接口
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public interface CodeGenService {
|
||||
|
||||
/**
|
||||
* 生成代码
|
||||
*
|
||||
* @param paramInfo 参数信息
|
||||
* @return 生成的代码映射
|
||||
* @throws Exception 生成过程中的异常
|
||||
*/
|
||||
ResultVo generateCode(ParamInfo paramInfo) throws Exception;
|
||||
|
||||
/**
|
||||
* 根据参数获取结果
|
||||
*
|
||||
* @param params 参数映射
|
||||
* @return 结果映射
|
||||
* @throws Exception 处理过程中的异常
|
||||
*/
|
||||
Map<String, String> getResultByParams(Map<String, Object> params) throws Exception;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.softdev.system.generator.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 模板服务接口
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public interface TemplateService {
|
||||
|
||||
/**
|
||||
* 获取所有模板配置
|
||||
*
|
||||
* @return 模板配置字符串
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
JSONArray getAllTemplates() throws IOException;
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
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.ParamInfo;
|
||||
import com.softdev.system.generator.entity.enums.ParserTypeEnum;
|
||||
import com.softdev.system.generator.entity.vo.ResultVo;
|
||||
import com.softdev.system.generator.service.CodeGenService;
|
||||
import com.softdev.system.generator.service.TemplateService;
|
||||
import com.softdev.system.generator.service.parser.JsonParserService;
|
||||
import com.softdev.system.generator.service.parser.SqlParserService;
|
||||
import com.softdev.system.generator.util.FreemarkerUtil;
|
||||
import com.softdev.system.generator.util.MapUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 代码生成服务实现类
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class CodeGenServiceImpl implements CodeGenService {
|
||||
|
||||
private final TemplateService templateService;
|
||||
private final SqlParserService sqlParserService;
|
||||
private final JsonParserService jsonParserService;
|
||||
|
||||
@Override
|
||||
public ResultVo generateCode(ParamInfo paramInfo) throws Exception {
|
||||
if (paramInfo.getTableSql() == null || paramInfo.getTableSql().isEmpty()) {
|
||||
return ResultVo.error("表结构信息为空");
|
||||
}
|
||||
|
||||
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<String, String> result = getResultByParams(paramInfo.getOptions());
|
||||
log.info("table:{} - time:{} ", MapUtil.getString(result, "tableName"), System.currentTimeMillis());
|
||||
return ResultVo.ok(result);
|
||||
} catch (Exception e) {
|
||||
log.error("代码生成失败", e);
|
||||
return ResultVo.error("代码生成失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getResultByParams(Map<String, Object> params) throws Exception {
|
||||
Map<String, String> result = new HashMap<>(32);
|
||||
result.put("tableName", MapUtil.getString(params, "tableName"));
|
||||
|
||||
// 处理模板生成逻辑
|
||||
// 解析模板配置并生成代码
|
||||
JSONArray parentTemplates = templateService.getAllTemplates();
|
||||
for (int i = 0; i < parentTemplates.size(); i++) {
|
||||
JSONObject parentTemplateObj = parentTemplates.getJSONObject(i);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据不同的解析类型解析表结构
|
||||
*
|
||||
* @param paramInfo 参数信息
|
||||
* @return 类信息
|
||||
* @throws Exception 解析异常
|
||||
*/
|
||||
private ClassInfo parseTableStructure(ParamInfo paramInfo) throws Exception {
|
||||
String dataType = MapUtil.getString(paramInfo.getOptions(), "dataType");
|
||||
ParserTypeEnum parserType = ParserTypeEnum.fromValue(dataType);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.softdev.system.generator.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.softdev.system.generator.service.TemplateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 模板服务实现类
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class TemplateServiceImpl implements TemplateService {
|
||||
|
||||
private String templateConfig = null;
|
||||
|
||||
@Override
|
||||
public JSONArray getAllTemplates() throws IOException {
|
||||
if (templateConfig == null) {
|
||||
ClassPathResource resource = new ClassPathResource("template.json");
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
templateConfig = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
return JSONArray.parseArray(templateConfig);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.softdev.system.generator.service.impl.parser;
|
||||
|
||||
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.FieldInfo;
|
||||
import com.softdev.system.generator.entity.dto.ParamInfo;
|
||||
import com.softdev.system.generator.service.parser.JsonParserService;
|
||||
import com.softdev.system.generator.util.exception.CodeGenException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* JSON解析服务实现类
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Service
|
||||
public class JsonParserServiceImpl implements JsonParserService {
|
||||
|
||||
@Override
|
||||
public ClassInfo processJsonToClassInfo(ParamInfo paramInfo) {
|
||||
ClassInfo codeJavaInfo = new ClassInfo();
|
||||
codeJavaInfo.setTableName("JsonDto");
|
||||
codeJavaInfo.setClassName("JsonDto");
|
||||
codeJavaInfo.setClassComment("JsonDto");
|
||||
|
||||
//support children json if forget to add '{' in front of json
|
||||
if (paramInfo.getTableSql().trim().startsWith("\"")) {
|
||||
paramInfo.setTableSql("{" + paramInfo.getTableSql());
|
||||
}
|
||||
try {
|
||||
if (paramInfo.getTableSql().trim().startsWith("{")) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(paramInfo.getTableSql().trim());
|
||||
//parse FieldList by JSONObject
|
||||
codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonObject));
|
||||
} else if (paramInfo.getTableSql().trim().startsWith("[")) {
|
||||
JSONArray jsonArray = JSONArray.parseArray(paramInfo.getTableSql().trim());
|
||||
//parse FieldList by JSONObject
|
||||
codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonArray.getJSONObject(0)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// JSON解析失败,抛出自定义异常
|
||||
throw new CodeGenException("JSON格式不正确: " + e.getMessage());
|
||||
}
|
||||
|
||||
return codeJavaInfo;
|
||||
}
|
||||
|
||||
public List<FieldInfo> processJsonObjectToFieldList(JSONObject jsonObject) {
|
||||
// field List
|
||||
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
|
||||
for (String jsonField : jsonObject.keySet()) {
|
||||
FieldInfo fieldInfo = new FieldInfo();
|
||||
fieldInfo.setFieldName(jsonField);
|
||||
fieldInfo.setColumnName(jsonField);
|
||||
fieldInfo.setFieldClass(String.class.getSimpleName());
|
||||
fieldInfo.setFieldComment("father:" + jsonField);
|
||||
fieldList.add(fieldInfo);
|
||||
if (jsonObject.get(jsonField) instanceof JSONArray) {
|
||||
JSONArray jsonArray = jsonObject.getJSONArray(jsonField);
|
||||
for (Object arrayObject : jsonArray) {
|
||||
FieldInfo fieldInfo2 = new FieldInfo();
|
||||
fieldInfo2.setFieldName(arrayObject.toString());
|
||||
fieldInfo2.setColumnName(arrayObject.toString());
|
||||
fieldInfo2.setFieldClass(String.class.getSimpleName());
|
||||
fieldInfo2.setFieldComment("children:" + arrayObject.toString());
|
||||
fieldList.add(fieldInfo2);
|
||||
}
|
||||
} else if (jsonObject.get(jsonField) instanceof JSONObject) {
|
||||
JSONObject subJsonObject = jsonObject.getJSONObject(jsonField);
|
||||
for (String arrayObject : subJsonObject.keySet()) {
|
||||
FieldInfo fieldInfo2 = new FieldInfo();
|
||||
fieldInfo2.setFieldName(arrayObject.toString());
|
||||
fieldInfo2.setColumnName(arrayObject.toString());
|
||||
fieldInfo2.setFieldClass(String.class.getSimpleName());
|
||||
fieldInfo2.setFieldComment("children:" + arrayObject.toString());
|
||||
fieldList.add(fieldInfo2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fieldList.size() < 1) {
|
||||
throw new CodeGenException("JSON解析失败");
|
||||
}
|
||||
return fieldList;
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,14 @@
|
||||
package com.softdev.system.generator.service;
|
||||
package com.softdev.system.generator.service.impl.parser;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.softdev.system.generator.entity.*;
|
||||
import com.softdev.system.generator.util.*;
|
||||
import freemarker.template.TemplateException;
|
||||
import com.softdev.system.generator.entity.dto.ClassInfo;
|
||||
import com.softdev.system.generator.entity.dto.FieldInfo;
|
||||
import com.softdev.system.generator.entity.dto.ParamInfo;
|
||||
import com.softdev.system.generator.service.parser.SqlParserService;
|
||||
import com.softdev.system.generator.util.MapUtil;
|
||||
import com.softdev.system.generator.util.StringUtilsPlus;
|
||||
import com.softdev.system.generator.util.exception.SqlParseException;
|
||||
import com.softdev.system.generator.util.mysqlJavaTypeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
@ -21,69 +24,23 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.sf.jsqlparser.parser.feature.Feature.createTable;
|
||||
|
||||
/**
|
||||
* GeneratorService
|
||||
* SQL解析服务实现类
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class GeneratorServiceImpl implements GeneratorService {
|
||||
public class SqlParserServiceImpl implements SqlParserService {
|
||||
|
||||
String templateCpnfig = null;
|
||||
|
||||
/**
|
||||
* 从项目中的JSON文件读取String
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Override
|
||||
public String getTemplateConfig() throws IOException {
|
||||
templateCpnfig = null;
|
||||
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template.json");
|
||||
templateCpnfig = new BufferedReader(new InputStreamReader(inputStream))
|
||||
.lines().collect(Collectors.joining(System.lineSeparator()));
|
||||
inputStream.close();
|
||||
//log.info(JSON.toJSONString(templateCpnfig));
|
||||
return templateCpnfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置的Template模板进行遍历解析,得到生成好的String
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> getResultByParams(Map<String, Object> params) throws IOException, TemplateException {
|
||||
Map<String, String> result = new HashMap<>(32);
|
||||
result.put("tableName", MapUtil.getString(params,"tableName"));
|
||||
JSONArray parentTemplates = JSONArray.parseArray(getTemplateConfig());
|
||||
for (int i = 0; i <parentTemplates.size() ; i++) {
|
||||
JSONObject parentTemplateObj = parentTemplates.getJSONObject(i);
|
||||
for (int x = 0; x <parentTemplateObj.getJSONArray("templates").size() ; x++) {
|
||||
JSONObject childTemplate = parentTemplateObj.getJSONArray("templates").getJSONObject(x);
|
||||
result.put(childTemplate.getString("name"), FreemarkerUtil.processString(parentTemplateObj.getString("group") + "/" +childTemplate.getString("name")+ ".ftl", params));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据SQL解析器解析表结构
|
||||
* @author zhengkai.blog.csdn.net
|
||||
* @param paramInfo
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public ClassInfo generateSelectSqlBySQLPraser(ParamInfo paramInfo) throws Exception {
|
||||
ClassInfo classInfo = new ClassInfo();
|
||||
@ -128,11 +85,11 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
//转换前
|
||||
fieldInfo.setColumnName(fieldName);
|
||||
fieldName = switch ((String) paramInfo.getOptions().get("nameCaseType")) {
|
||||
case ParamInfo.NAME_CASE_TYPE.CAMEL_CASE ->
|
||||
case ParamInfo.NameCaseType.CAMEL_CASE ->
|
||||
// 2024-1-27 L&J 适配任意(maybe)原始风格转小写驼峰
|
||||
StringUtilsPlus.toLowerCamel(aliasName);
|
||||
case ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE -> StringUtilsPlus.toUnderline(aliasName, false);
|
||||
case ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE ->
|
||||
case ParamInfo.NameCaseType.UNDER_SCORE_CASE -> StringUtilsPlus.toUnderline(aliasName, false);
|
||||
case ParamInfo.NameCaseType.UPPER_UNDER_SCORE_CASE ->
|
||||
StringUtilsPlus.toUnderline(aliasName.toUpperCase(), true);
|
||||
default -> aliasName;
|
||||
};
|
||||
@ -147,13 +104,7 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
log.info("classInfo:{}", JSON.toJSONString(classInfo));
|
||||
return classInfo;
|
||||
}
|
||||
/**
|
||||
* 根据SQL解析器解析表结构
|
||||
* @author zhengkai.blog.csdn.net
|
||||
* @param paramInfo
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@Override
|
||||
public ClassInfo generateCreateSqlBySQLPraser(ParamInfo paramInfo) throws Exception {
|
||||
ClassInfo classInfo = new ClassInfo();
|
||||
@ -168,12 +119,12 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
statement = CCJSqlParserUtil.parse(processedSql);
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new SqlException("SQL语法错误:"+e.getMessage());
|
||||
throw new SqlParseException("SQL语法错误:"+e.getMessage());
|
||||
}
|
||||
|
||||
// 确保是CREATE TABLE语句
|
||||
if (!(statement instanceof CreateTable createTable)) {
|
||||
throw new SqlException("检测到SQL语句不是DLL CREATE TABLE语句");
|
||||
throw new SqlParseException("检测到SQL语句不是DLL CREATE TABLE语句");
|
||||
}
|
||||
|
||||
// 提取表名
|
||||
@ -200,9 +151,9 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
|
||||
// 根据命名规则转换字段名
|
||||
String fieldName = switch ((String) paramInfo.getOptions().get("nameCaseType")) {
|
||||
case ParamInfo.NAME_CASE_TYPE.CAMEL_CASE -> StringUtilsPlus.toLowerCamel(columnName);
|
||||
case ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE -> StringUtilsPlus.toUnderline(columnName, false);
|
||||
case ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE ->
|
||||
case ParamInfo.NameCaseType.CAMEL_CASE -> StringUtilsPlus.toLowerCamel(columnName);
|
||||
case ParamInfo.NameCaseType.UNDER_SCORE_CASE -> StringUtilsPlus.toUnderline(columnName, false);
|
||||
case ParamInfo.NameCaseType.UPPER_UNDER_SCORE_CASE ->
|
||||
StringUtilsPlus.toUnderline(columnName.toUpperCase(), true);
|
||||
default -> columnName;
|
||||
};
|
||||
@ -218,23 +169,17 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
log.info("classInfo:{}", JSON.toJSONString(classInfo));
|
||||
return classInfo;
|
||||
}
|
||||
/**
|
||||
* 解析DDL SQL生成类信息(默认模式|核心模式)
|
||||
*
|
||||
* @param paramInfo
|
||||
* @return
|
||||
*/
|
||||
|
||||
@Override
|
||||
public ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
|
||||
throws IOException {
|
||||
public ClassInfo processTableIntoClassInfo(ParamInfo paramInfo) throws Exception {
|
||||
//process the param
|
||||
NonCaseString tableSql = NonCaseString.of(paramInfo.getTableSql());
|
||||
String tableSql = paramInfo.getTableSql();
|
||||
String nameCaseType = MapUtil.getString(paramInfo.getOptions(),"nameCaseType");
|
||||
Boolean isPackageType = MapUtil.getBoolean(paramInfo.getOptions(),"isPackageType");
|
||||
String isPackageType = MapUtil.getString(paramInfo.getOptions(),"isPackageType");
|
||||
|
||||
//更新空值处理
|
||||
if (StringUtils.isBlank(tableSql)) {
|
||||
throw new CodeGenerateException("Table structure can not be empty. 表结构不能为空。");
|
||||
throw new Exception("Table structure can not be empty. 表结构不能为空。");
|
||||
}
|
||||
//deal with special character
|
||||
tableSql = tableSql.trim()
|
||||
@ -250,9 +195,9 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
String tableName = null;
|
||||
int tableKwIx = tableSql.indexOf("TABLE"); // 包含判断和位置一次搞定
|
||||
if (tableKwIx > -1 && tableSql.contains("(")) {
|
||||
tableName = tableSql.substring(tableKwIx + 5, tableSql.indexOf("(")).get();
|
||||
tableName = tableSql.substring(tableKwIx + 5, tableSql.indexOf("("));
|
||||
} else {
|
||||
throw new CodeGenerateException("Table structure incorrect.表结构不正确。");
|
||||
throw new Exception("Table structure incorrect.表结构不正确。");
|
||||
}
|
||||
|
||||
//新增处理create table if not exists members情况
|
||||
@ -288,11 +233,11 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
String classComment = null;
|
||||
//mysql是comment=,pgsql/oracle是comment on table,
|
||||
//2020-05-25 优化表备注的获取逻辑
|
||||
if (tableSql.containsAny("comment=", "comment on table")) {
|
||||
if (tableSql.contains("comment=") || tableSql.contains("comment on table")) {
|
||||
int ix = tableSql.lastIndexOf("comment=");
|
||||
String classCommentTmp = (ix > -1) ?
|
||||
tableSql.substring(ix + 8).trim().get() :
|
||||
tableSql.substring(tableSql.lastIndexOf("comment on table") + 17).trim().get();
|
||||
tableSql.substring(ix + 8).trim() :
|
||||
tableSql.substring(tableSql.lastIndexOf("comment on table") + 17).trim();
|
||||
if (classCommentTmp.contains("`")) {
|
||||
classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf("`") + 1);
|
||||
classCommentTmp = classCommentTmp.substring(0, classCommentTmp.indexOf("`"));
|
||||
@ -311,7 +256,7 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
|
||||
|
||||
// 正常( ) 内的一定是字段相关的定义。
|
||||
String fieldListTmp = tableSql.substring(tableSql.indexOf("(") + 1, tableSql.lastIndexOf(")")).get();
|
||||
String fieldListTmp = tableSql.substring(tableSql.indexOf("(") + 1, tableSql.lastIndexOf(")"));
|
||||
|
||||
// 匹配 comment,替换备注里的小逗号, 防止不小心被当成切割符号切割
|
||||
String commentPattenStr1 = "comment `(.*?)\\`";
|
||||
@ -352,17 +297,27 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
int i = 0;
|
||||
//i为了解决primary key关键字出现的地方,出现在前3行,一般和id有关
|
||||
for (String columnLine0 : fieldLineList) {
|
||||
NonCaseString columnLine = NonCaseString.of(columnLine0);
|
||||
i++;
|
||||
columnLine = columnLine.replaceAll("\n", "").replaceAll("\t", "").trim();
|
||||
String columnLine = columnLine0.replaceAll("\n", "").replaceAll("\t", "").trim();
|
||||
// `userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
// 2018-9-18 zhengk 修改为contains,提升匹配率和匹配不按照规矩出牌的语句
|
||||
// 2018-11-8 zhengkai 修复tornadoorz反馈的KEY FK_permission_id (permission_id),KEY FK_role_id (role_id)情况
|
||||
// 2019-2-22 zhengkai 要在条件中使用复杂的表达式
|
||||
// 2019-4-29 zhengkai 优化对普通和特殊storage关键字的判断(感谢@AhHeadFloating的反馈 )
|
||||
// 2020-10-20 zhengkai 优化对fulltext/index关键字的处理(感谢@WEGFan的反馈)
|
||||
// 2023-8-27 L&J 改用工具方法判断, 且修改变量名(非特殊标识), 方法抽取
|
||||
boolean notSpecialFlag = isNotSpecialColumnLine(columnLine, i);
|
||||
boolean notSpecialFlag = (
|
||||
!columnLine.contains("key ")
|
||||
&& !columnLine.contains("constraint")
|
||||
&& !columnLine.contains(" using ")
|
||||
&& !columnLine.contains("unique ")
|
||||
&& !columnLine.contains("fulltext ")
|
||||
&& !columnLine.contains("index ")
|
||||
&& !columnLine.contains("pctincrease")
|
||||
&& !columnLine.contains("buffer_pool")
|
||||
&& !columnLine.contains("tablespace")
|
||||
&& !(columnLine.contains("primary ") && columnLine.indexOf("storage") + 3 > columnLine.indexOf("("))
|
||||
&& !(columnLine.contains("primary ") && i > 3)
|
||||
);
|
||||
|
||||
if (notSpecialFlag) {
|
||||
//如果是oracle的number(x,x),可能出现最后分割残留的,x),这里做排除处理
|
||||
@ -374,7 +329,7 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
columnLine = columnLine.replaceAll("`", " ").replaceAll("\"", " ").replaceAll("'", "").replaceAll(" ", " ").trim();
|
||||
//如果遇到username varchar(65) default '' not null,这种情况,判断第一个空格是否比第一个引号前
|
||||
try {
|
||||
columnName = columnLine.substring(0, columnLine.indexOf(" ")).get();
|
||||
columnName = columnLine.substring(0, columnLine.indexOf(" "));
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
System.out.println("err happened: " + columnLine);
|
||||
throw e;
|
||||
@ -384,19 +339,19 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
// 2019-09-08 yj 添加是否下划线转换为驼峰的判断
|
||||
// 2023-8-27 L&J 支持原始列名任意命名风格, 不依赖用户是否输入下划线
|
||||
String fieldName = null;
|
||||
if (ParamInfo.NAME_CASE_TYPE.CAMEL_CASE.equals(nameCaseType)) {
|
||||
if (ParamInfo.NameCaseType.CAMEL_CASE.equals(nameCaseType)) {
|
||||
// 2024-1-27 L&J 适配任意(maybe)原始风格转小写驼峰
|
||||
fieldName = StringUtilsPlus.toLowerCamel(columnName);
|
||||
} else if (ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE.equals(nameCaseType)) {
|
||||
} else if (ParamInfo.NameCaseType.UNDER_SCORE_CASE.equals(nameCaseType)) {
|
||||
fieldName = StringUtilsPlus.toUnderline(columnName, false);
|
||||
} else if (ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE.equals(nameCaseType)) {
|
||||
} else if (ParamInfo.NameCaseType.UPPER_UNDER_SCORE_CASE.equals(nameCaseType)) {
|
||||
fieldName = StringUtilsPlus.toUnderline(columnName.toUpperCase(), true);
|
||||
} else {
|
||||
fieldName = columnName;
|
||||
}
|
||||
columnLine = columnLine.substring(columnLine.indexOf("`") + 1).trim();
|
||||
//2025-03-16 修复由于类型大写导致无法转换的问题
|
||||
String mysqlType = columnLine.split("\\s+")[1].toLowerCase(Locale.ROOT);
|
||||
String mysqlType = columnLine.split("\\s+")[1].toLowerCase();
|
||||
if(mysqlType.contains("(")){
|
||||
mysqlType = mysqlType.substring(0, mysqlType.indexOf("("));
|
||||
}
|
||||
@ -428,12 +383,12 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
while (columnCommentMatcher.find()) {
|
||||
String columnCommentTmp = columnCommentMatcher.group();
|
||||
//System.out.println(columnCommentTmp);
|
||||
fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp) + columnCommentTmp.length()).trim().get();
|
||||
fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp) + columnCommentTmp.length()).trim();
|
||||
fieldComment = fieldComment.substring(0, fieldComment.indexOf("`")).trim();
|
||||
}
|
||||
} else if (columnLine.contains(" comment")) {
|
||||
//20200518 zhengkai 修复包含comment关键字的问题
|
||||
String commentTmp = columnLine.substring(columnLine.lastIndexOf("comment") + 7).trim().get();
|
||||
String commentTmp = columnLine.substring(columnLine.lastIndexOf("comment") + 7).trim();
|
||||
// '用户ID',
|
||||
if (commentTmp.contains("`") || commentTmp.indexOf("`") != commentTmp.lastIndexOf("`")) {
|
||||
commentTmp = commentTmp.substring(commentTmp.indexOf("`") + 1, commentTmp.lastIndexOf("`"));
|
||||
@ -462,7 +417,7 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
}
|
||||
|
||||
if (fieldList.size() < 1) {
|
||||
throw new CodeGenerateException("表结构分析失败,请检查语句或者提交issue给我");
|
||||
throw new Exception("表结构分析失败,请检查语句或者提交issue给我");
|
||||
}
|
||||
|
||||
ClassInfo codeJavaInfo = new ClassInfo();
|
||||
@ -475,63 +430,7 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
return codeJavaInfo;
|
||||
}
|
||||
|
||||
private static boolean isNotSpecialColumnLine(NonCaseString columnLine, int lineSeq) {
|
||||
return (
|
||||
!columnLine.containsAny(
|
||||
"key ",
|
||||
"constraint",
|
||||
" using ",
|
||||
"unique ",
|
||||
"fulltext ",
|
||||
"index ",
|
||||
"pctincrease",
|
||||
"buffer_pool",
|
||||
"tablespace"
|
||||
)
|
||||
&& !(columnLine.contains("primary ") && columnLine.indexOf("storage") + 3 > columnLine.indexOf("("))
|
||||
&& !(columnLine.contains("primary ") && lineSeq > 3)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON生成类信息
|
||||
*
|
||||
* @param paramInfo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ClassInfo processJsonToClassInfo(ParamInfo paramInfo) {
|
||||
ClassInfo codeJavaInfo = new ClassInfo();
|
||||
codeJavaInfo.setTableName("JsonDto");
|
||||
codeJavaInfo.setClassName("JsonDto");
|
||||
codeJavaInfo.setClassComment("JsonDto");
|
||||
|
||||
//support children json if forget to add '{' in front of json
|
||||
if (paramInfo.getTableSql().trim().startsWith("\"")) {
|
||||
paramInfo.setTableSql("{" + paramInfo.getTableSql());
|
||||
}
|
||||
if (JSON.isValid(paramInfo.getTableSql())) {
|
||||
if (paramInfo.getTableSql().trim().startsWith("{")) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(paramInfo.getTableSql().trim());
|
||||
//parse FieldList by JSONObject
|
||||
codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonObject));
|
||||
} else if (paramInfo.getTableSql().trim().startsWith("[")) {
|
||||
JSONArray jsonArray = JSONArray.parseArray(paramInfo.getTableSql().trim());
|
||||
//parse FieldList by JSONObject
|
||||
codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonArray.getJSONObject(0)));
|
||||
}
|
||||
}
|
||||
|
||||
return codeJavaInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse SQL by regex
|
||||
*
|
||||
* @param paramInfo
|
||||
* @return
|
||||
* @author https://github.com/ydq
|
||||
*/
|
||||
public ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo) {
|
||||
// field List
|
||||
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
|
||||
@ -548,7 +447,7 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
|
||||
Pattern COL_PATTERN = Pattern.compile(COL_PATTERN_STR, Pattern.CASE_INSENSITIVE);
|
||||
|
||||
Matcher matcher = DDL_PATTERN.matcher(paramInfo.getTableSql().trim());
|
||||
Matcher matcher = Pattern.compile(DDL_PATTEN_STR).matcher(paramInfo.getTableSql().trim());
|
||||
if (matcher.find()) {
|
||||
String tableName = matcher.group("tableName");
|
||||
String tableComment = matcher.group("tableComment");
|
||||
@ -577,42 +476,7 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
return codeJavaInfo;
|
||||
}
|
||||
|
||||
public List<FieldInfo> processJsonObjectToFieldList(JSONObject jsonObject) {
|
||||
// field List
|
||||
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
|
||||
jsonObject.keySet().stream().forEach(jsonField -> {
|
||||
FieldInfo fieldInfo = new FieldInfo();
|
||||
fieldInfo.setFieldName(jsonField);
|
||||
fieldInfo.setColumnName(jsonField);
|
||||
fieldInfo.setFieldClass(String.class.getSimpleName());
|
||||
fieldInfo.setFieldComment("father:" + jsonField);
|
||||
fieldList.add(fieldInfo);
|
||||
if (jsonObject.get(jsonField) instanceof JSONArray) {
|
||||
jsonObject.getJSONArray(jsonField).stream().forEach(arrayObject -> {
|
||||
FieldInfo fieldInfo2 = new FieldInfo();
|
||||
fieldInfo2.setFieldName(arrayObject.toString());
|
||||
fieldInfo2.setColumnName(arrayObject.toString());
|
||||
fieldInfo2.setFieldClass(String.class.getSimpleName());
|
||||
fieldInfo2.setFieldComment("children:" + arrayObject.toString());
|
||||
fieldList.add(fieldInfo2);
|
||||
});
|
||||
} else if (jsonObject.get(jsonField) instanceof JSONObject) {
|
||||
jsonObject.getJSONObject(jsonField).keySet().stream().forEach(arrayObject -> {
|
||||
FieldInfo fieldInfo2 = new FieldInfo();
|
||||
fieldInfo2.setFieldName(arrayObject.toString());
|
||||
fieldInfo2.setColumnName(arrayObject.toString());
|
||||
fieldInfo2.setFieldClass(String.class.getSimpleName());
|
||||
fieldInfo2.setFieldComment("children:" + arrayObject.toString());
|
||||
fieldList.add(fieldInfo2);
|
||||
});
|
||||
}
|
||||
});
|
||||
if (fieldList.size() < 1) {
|
||||
throw new CodeGenerateException("JSON解析失败");
|
||||
}
|
||||
return fieldList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo) {
|
||||
// field List
|
||||
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
|
||||
@ -645,12 +509,14 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
|
||||
List<String> valueList = new ArrayList<>();
|
||||
//add values as comment
|
||||
Arrays.stream(valueStr.split(",")).forEach(column -> {
|
||||
String[] values = valueStr.split(",");
|
||||
for (String column : values) {
|
||||
valueList.add(column);
|
||||
});
|
||||
}
|
||||
AtomicInteger n = new AtomicInteger(0);
|
||||
//add column to fleldList
|
||||
Arrays.stream(columnsSQL.replaceAll(" ", "").split(",")).forEach(column -> {
|
||||
String[] columns = columnsSQL.replaceAll(" ", "").split(",");
|
||||
for (String column : columns) {
|
||||
FieldInfo fieldInfo2 = new FieldInfo();
|
||||
fieldInfo2.setFieldName(column);
|
||||
fieldInfo2.setColumnName(column);
|
||||
@ -660,14 +526,13 @@ public class GeneratorServiceImpl implements GeneratorService {
|
||||
}
|
||||
fieldList.add(fieldInfo2);
|
||||
n.getAndIncrement();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
if (fieldList.size() < 1) {
|
||||
throw new CodeGenerateException("INSERT SQL解析失败");
|
||||
throw new RuntimeException("INSERT SQL解析失败");
|
||||
}
|
||||
codeJavaInfo.setFieldList(fieldList);
|
||||
return codeJavaInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.softdev.system.generator.service.parser;
|
||||
|
||||
import com.softdev.system.generator.entity.dto.ClassInfo;
|
||||
import com.softdev.system.generator.entity.dto.ParamInfo;
|
||||
|
||||
/**
|
||||
* JSON解析服务接口
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public interface JsonParserService {
|
||||
|
||||
/**
|
||||
* 解析JSON生成类信息
|
||||
*
|
||||
* @param paramInfo 参数信息
|
||||
* @return 类信息
|
||||
*/
|
||||
ClassInfo processJsonToClassInfo(ParamInfo paramInfo);
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.softdev.system.generator.service.parser;
|
||||
|
||||
import com.softdev.system.generator.entity.dto.ClassInfo;
|
||||
import com.softdev.system.generator.entity.dto.ParamInfo;
|
||||
|
||||
/**
|
||||
* SQL解析服务接口
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public interface SqlParserService {
|
||||
|
||||
/**
|
||||
* 解析Select-SQL生成类信息(JSQLPraser版本)
|
||||
*
|
||||
* @param paramInfo 参数信息
|
||||
* @return 类信息
|
||||
* @throws Exception 解析异常
|
||||
*/
|
||||
ClassInfo generateSelectSqlBySQLPraser(ParamInfo paramInfo) throws Exception;
|
||||
|
||||
/**
|
||||
* 解析Create-SQL生成类信息(JSQLPraser版本)
|
||||
*
|
||||
* @param paramInfo 参数信息
|
||||
* @return 类信息
|
||||
* @throws Exception 解析异常
|
||||
*/
|
||||
ClassInfo generateCreateSqlBySQLPraser(ParamInfo paramInfo) throws Exception;
|
||||
|
||||
/**
|
||||
* 解析DDL-SQL生成类信息
|
||||
*
|
||||
* @param paramInfo 参数信息
|
||||
* @return 类信息
|
||||
* @throws Exception 解析异常
|
||||
*/
|
||||
ClassInfo processTableIntoClassInfo(ParamInfo paramInfo) throws Exception;
|
||||
|
||||
/**
|
||||
* 解析DDL SQL生成类信息-正则表达式版本
|
||||
*
|
||||
* @param paramInfo 参数信息
|
||||
* @return 类信息
|
||||
*/
|
||||
ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo);
|
||||
|
||||
/**
|
||||
* 解析INSERT-SQL生成类信息-正则表达式版本
|
||||
*
|
||||
* @param paramInfo 参数信息
|
||||
* @return 类信息
|
||||
*/
|
||||
ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo);
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.softdev.system.generator.util.exception;
|
||||
|
||||
/**
|
||||
* 代码生成异常
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public class CodeGenException extends RuntimeException {
|
||||
|
||||
public CodeGenException() {
|
||||
}
|
||||
|
||||
public CodeGenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CodeGenException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public CodeGenException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public CodeGenException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.softdev.system.generator.util.exception;
|
||||
|
||||
/**
|
||||
* SQL解析异常
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public class SqlParseException extends CodeGenException {
|
||||
|
||||
public SqlParseException() {
|
||||
}
|
||||
|
||||
public SqlParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SqlParseException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SqlParseException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public SqlParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 434 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
@ -130,12 +130,13 @@ const vm = new Vue({
|
||||
}
|
||||
setAllCookie();
|
||||
//console.log(res.outputJson);
|
||||
vm.outputJson = res.data.data;
|
||||
//兼容后端返回数据格式
|
||||
if(res.data){
|
||||
vm.outputJson = res.data.outputJson;
|
||||
}else {
|
||||
vm.outputJson = res.outputJson;
|
||||
}
|
||||
// if(res.data){
|
||||
// vm.outputJson = res.data.outputJson;
|
||||
// }else {
|
||||
// vm.outputJson = res.outputJson;
|
||||
// }
|
||||
|
||||
// console.log(vm.outputJson["bootstrap-ui"]);
|
||||
vm.outputStr=vm.outputJson[vm.currentSelect].trim();
|
||||
@ -159,13 +160,15 @@ const vm = new Vue({
|
||||
}).then(function(res){
|
||||
//console.log(res.templates);
|
||||
// vm.templates = JSON.parse(res.templates);
|
||||
// console.log(res);
|
||||
console.log('origin res',res);
|
||||
vm.templates = res.data.data
|
||||
console.log('templates',vm.templates);
|
||||
//兼容后端返回数据格式
|
||||
if(res.data){
|
||||
vm.templates = res.data.templates;
|
||||
}else {
|
||||
vm.templates = res.templates;
|
||||
}
|
||||
// if(res.data){
|
||||
// vm.templates = res.data.templates;
|
||||
// }else {
|
||||
// vm.templates = res.templates;
|
||||
// }
|
||||
});
|
||||
},
|
||||
updated: function () {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user