diff --git a/README.md b/README.md index e745f5f0..9b2f8565 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,82 @@ -# SpringBootCodeGenerator -![image](https://img.shields.io/badge/SpringBoot2-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-brightgreen.svg) -![image](https://img.shields.io/badge/Freemarker-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-brightgreen.svg) -![image](https://img.shields.io/badge/CodeGenerator-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-brightgreen.svg) -[![Build Status](https://travis-ci.org/moshowgame/SpringBootCodeGenerator.svg?branch=master)](https://travis-ci.org/moshowgame/SpringBootCodeGenerator) - - -# Description -- √ 基于SpringBoot2+Freemarker+Bootstrap -- √ 以释放双手为目的 -- √ 支持mysql/oracle/pgsql三大数据库 -- √ 用DDL-SQL语句生成JPA/JdbcTemplate/Mybatis/MybatisPlus/BeetlSQL相关代码. - - -# Url - -|访问路径|http://localhost:1234/generator| -|-|-| -|在线地址|http://java.bejson.com/generator| -|CSDN博客|http://zhengkai.blog.csdn.net| - -感谢bejson三叔将他部署在[BEJSON](www.bejson.com)上,目前是besjon专供工具(线上版本不一定是最新的,会有延迟,请谅解,谢谢). - - -# Update - -|更新日期|更新内容| -|-|-| -|20191124|1.java代码结构优化. 2.新增简单的json生成模式 3.新增简单的正则表达式匹配模式(感谢@ydq的贡献) 4.新增对复制String代码中的乱SQL代码的支持 5.优化对JSON的父子节点/处理,JSONObject和JSONArray节点处理,子节点缺失'{'头处理| -|20191123|1.移除频繁出错和被过滤的layer,改为jquery-toast. 2.Util功能优化,新增json和xml.| -|20191116|优化对primary关键字的处理(感谢@liujiansgit的反馈). | -|20191115|1.添加tinyint类型转换(感谢@lixiliang&@liujiansgit的Suggestion) 2.添加一键复制功能(感谢@gaohanghang的Suggestion) 3.Mybatis的insert增加keyProperty="id"用于返回自增id(感谢@88888888888888888888的Suggestion) 4.优化date类型的支持(感谢@SteveLsf的反馈) 5.其他一些优化. | -|20191015|修复jdbcTemplates中insert语句第一个字段丢失的问题. | -|20190915|1.添加对象getset模板 2.添加sql模板 3.启动类添加日志输出,方便项目使用(感谢@gaohanghang 的pull request) | -|20190910-2|优化以及更新Maven依赖,减少打包体积. | -|20190910-1|1.修复mapper接口load方法,但是xml中方法不匹配问题 2.移除mapper中CRUD时的@param 注解,会影响xml的解析(感谢@caojiantao的反馈).3.优化MyBatis的xml文件对Oracle的支持.(感谢@wylove1992的反馈) 4.新增对boolean的处理(感谢@violinxsc的反馈)以及优化tinyint类型生成boolean类型问题(感谢@hahaYhui的反馈) | -|20190909|添加是否下划线转换为驼峰的选择(感谢@youngking28 的pull request).| -|20190518|1.优化注释 2.修改 mybatis模板中 controller注解 3.修改 mybatis模板中 dao文件使用为 mapper文件 4.修改 mybatis模板中 service实现类中的一个 bug 5.修改 index.ftl文件中 mybatis模板的 dao -> mapper(感谢@unqin的pull request)| -|20190511|优化mybatis模块的dao和xml模板,修改dao接口注解为@Repository,所有dao参数改为包装类,删除update语句最后的UpdateTime = NOW(),修改dao接口文件的方法注释使其更符合javaDoc的标准,修改insert语句增加插入行主键的返回,修改load的方法名为selectByPrimaryKey,修改xml的update语句新增动态if判空,修改xml的insert语句新增动态插入判空,更符合mybatisGenerator标准(感谢@Archer-Wen的贡献 ).| -|20190429|新增返回封装工具类设置,优化对oracle注释comment on column的支持(感谢@liukex反馈),优化对普通和特殊storage关键字的判断(感谢@AhHeadFloating的反馈 ).| -|20190211|提交gitignore,解决StringUtils.lowerCaseFirst潜在的NPE异常,校验修改为@RequestParam参数校验,lombok之@Data和@Slf4j优化,fix JdbcDAO模板类名显示为中文问题,WebMvcConfig整合MessageConverter,模板代码分类(感谢@liutf和@tfgzs的pull request).| -|20190210|实体生成规则切换为包装类型,不再采用基本数据类型,为实体类生成添加显示的默认构造方法(感谢@h2so的pull request).| -|20190106|修复处理number/decimal(x,x)类型的逻辑(感谢@arthaschan的反馈),修复JdbcTemplates模板两处错误(感谢@everflourish的反馈).| -|20181212|首页UI优化,新增MybatisPlus模块(感谢@三叔同事的建议),修复作者名和包名获取失败问题(感谢@Yanch1994的反馈).| -|20181122|优化正则表达式点号的处理,优化处理字段类型,对number类型增加int,long,BigDecimal的区分判断(感谢@lshz0088的指导).| -|20181108|修复非字段描述"KEY FK_xxxx (xxxx)"导致生成KEY字段情况(感谢@tornadoorz反馈).| -|20181018|支持double(x,x)的类型,以及comment里面包含一些特殊字符的处理(感谢@tanwubo的反馈).| -|20181010|CDN变更,修复CDN不稳定导致网页js报错问题.| -|20181003|新增element-ui/bootstrap生成.| -|20181002|修复公共CDN之Layer.js404问题,导致项目无法生成.| -|20180927|优化COMMENT提取逻辑,支持多种复杂情况的注释(感谢@raodeming的反馈).| -|20180926|全新BeetlSQL模块,以及一些小细节优化(感谢@三叔同事的建议).| -|20180925|优化SQL表和字段备注的推断,包括pgsql/oralce的comment on column/table情况处理等.| -|20180918|优化SQL类型推断.优化PrimaryKey判断.修复jpacontroller中Repository拼写错误问题.| -|20180917|全新首页,静态文件全部采用CDN.新增jdbcTemplate模块.| -|20180916|1.优化oracle支持,优化DDL语句中"或者'或者空格的支持. 2.补充char/clob/blob/json等类型,如果类型未知,默认为String.| -|20180915|新增Swagger-UI模板.修复一些命名和导入问题.JPA的Entity默认第一个字段为Id,如果不是请手工修改.| -|20180913|修复字段没有描述以及类型为DATE型导致的问题.新增JPA的Controller模板.| -|20180831|初始化项目.新增JPA系列Entity+Repository模板.| - -# FieldName -|字段名|说明| -|-|-| -|packageName|自定义的包名| -|authorName|自定义的作者名| -|returnUtil|自定义的返回Util| -|tableName|sql中的表名| -|className|java类名| -|classComment|sql表备注/java类备注| -|fieldName|字段名| -|fieldComment|字段备注| - - - - - - - +# SpringBootCodeGenerator +![image](https://img.shields.io/badge/SpringBoot2-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-brightgreen.svg) +![image](https://img.shields.io/badge/Freemarker-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-brightgreen.svg) +![image](https://img.shields.io/badge/CodeGenerator-%E2%98%85%E2%98%85%E2%98%85%E2%98%85%E2%98%85-brightgreen.svg) +[![Build Status](https://travis-ci.org/moshowgame/SpringBootCodeGenerator.svg?branch=master)](https://travis-ci.org/moshowgame/SpringBootCodeGenerator) + + +# Description +- √ 基于SpringBoot2+Freemarker+Bootstrap +- √ 以释放双手为目的 +- √ 支持mysql/oracle/pgsql三大数据库 +- √ 用DDL-SQL语句生成JPA/JdbcTemplate/Mybatis/MybatisPlus/BeetlSQL相关代码. + + +# Url + +|访问路径|http://localhost:1234/generator| +|-|-| +|在线地址|http://java.bejson.com/generator| +|CSDN博客|http://zhengkai.blog.csdn.net| +|最新Jar包|https://github.com/moshowgame/SpringBootCodeGenerator/releases| + +感谢bejson三叔将他部署在[BEJSON](www.bejson.com)上,目前是besjon专供工具(线上版本不一定是最新的,会有延迟,请谅解,谢谢). + + +# Update + +|更新日期|更新内容| +|-|-| +|20191128|1.修复支持string-copy导致的以n结尾的字母不显示问题 2.jpa-entity新增swagger@ApiModel@ApiModelProperty注解和SQL字段@Column注解(感谢@yjq907的建议) | +|20191126|1.springboot2内置tomcat更换为性能更强大的undertow 2.修复tinyintTransType参数丢失问题 | +|20191124|1.java代码结构优化. 2.新增简单的json生成模式 3.新增简单的正则表达式匹配模式(感谢@ydq的贡献) 4.新增对复制String代码中的乱SQL代码的支持 5.优化对JSON的父子节点/处理,JSONObject和JSONArray节点处理,子节点缺失'{'头处理| +|20191123|1.移除频繁出错和被过滤的layer,改为jquery-toast. 2.Util功能优化,新增json和xml.| +|20191116|优化对primary关键字的处理(感谢@liujiansgit的反馈). | +|20191115|1.添加tinyint类型转换(感谢@lixiliang&@liujiansgit的Suggestion) 2.添加一键复制功能(感谢@gaohanghang的Suggestion) 3.Mybatis的insert增加keyProperty="id"用于返回自增id(感谢@88888888888888888888的Suggestion) 4.优化date类型的支持(感谢@SteveLsf的反馈) 5.其他一些优化. | +|20191015|修复jdbcTemplates中insert语句第一个字段丢失的问题. | +|20190915|1.添加对象getset模板 2.添加sql模板 3.启动类添加日志输出,方便项目使用(感谢@gaohanghang 的pull request) | +|20190910-2|优化以及更新Maven依赖,减少打包体积. | +|20190910-1|1.修复mapper接口load方法,但是xml中方法不匹配问题 2.移除mapper中CRUD时的@param 注解,会影响xml的解析(感谢@caojiantao的反馈).3.优化MyBatis的xml文件对Oracle的支持.(感谢@wylove1992的反馈) 4.新增对boolean的处理(感谢@violinxsc的反馈)以及优化tinyint类型生成boolean类型问题(感谢@hahaYhui的反馈) | +|20190909|添加是否下划线转换为驼峰的选择(感谢@youngking28 的pull request).| +|20190518|1.优化注释 2.修改 mybatis模板中 controller注解 3.修改 mybatis模板中 dao文件使用为 mapper文件 4.修改 mybatis模板中 service实现类中的一个 bug 5.修改 index.ftl文件中 mybatis模板的 dao -> mapper(感谢@unqin的pull request)| +|20190511|优化mybatis模块的dao和xml模板,修改dao接口注解为@Repository,所有dao参数改为包装类,删除update语句最后的UpdateTime = NOW(),修改dao接口文件的方法注释使其更符合javaDoc的标准,修改insert语句增加插入行主键的返回,修改load的方法名为selectByPrimaryKey,修改xml的update语句新增动态if判空,修改xml的insert语句新增动态插入判空,更符合mybatisGenerator标准(感谢@Archer-Wen的贡献 ).| +|20190429|新增返回封装工具类设置,优化对oracle注释comment on column的支持(感谢@liukex反馈),优化对普通和特殊storage关键字的判断(感谢@AhHeadFloating的反馈 ).| +|20190211|提交gitignore,解决StringUtils.lowerCaseFirst潜在的NPE异常,校验修改为@RequestParam参数校验,lombok之@Data和@Slf4j优化,fix JdbcDAO模板类名显示为中文问题,WebMvcConfig整合MessageConverter,模板代码分类(感谢@liutf和@tfgzs的pull request).| +|20190210|实体生成规则切换为包装类型,不再采用基本数据类型,为实体类生成添加显示的默认构造方法(感谢@h2so的pull request).| +|20190106|修复处理number/decimal(x,x)类型的逻辑(感谢@arthaschan的反馈),修复JdbcTemplates模板两处错误(感谢@everflourish的反馈).| +|20181212|首页UI优化,新增MybatisPlus模块(感谢@三叔同事的建议),修复作者名和包名获取失败问题(感谢@Yanch1994的反馈).| +|20181122|优化正则表达式点号的处理,优化处理字段类型,对number类型增加int,long,BigDecimal的区分判断(感谢@lshz0088的指导).| +|20181108|修复非字段描述"KEY FK_xxxx (xxxx)"导致生成KEY字段情况(感谢@tornadoorz反馈).| +|20181018|支持double(x,x)的类型,以及comment里面包含一些特殊字符的处理(感谢@tanwubo的反馈).| +|20181010|CDN变更,修复CDN不稳定导致网页js报错问题.| +|20181003|新增element-ui/bootstrap生成.| +|20181002|修复公共CDN之Layer.js404问题,导致项目无法生成.| +|20180927|优化COMMENT提取逻辑,支持多种复杂情况的注释(感谢@raodeming的反馈).| +|20180926|全新BeetlSQL模块,以及一些小细节优化(感谢@三叔同事的建议).| +|20180925|优化SQL表和字段备注的推断,包括pgsql/oralce的comment on column/table情况处理等.| +|20180918|优化SQL类型推断.优化PrimaryKey判断.修复jpacontroller中Repository拼写错误问题.| +|20180917|全新首页,静态文件全部采用CDN.新增jdbcTemplate模块.| +|20180916|1.优化oracle支持,优化DDL语句中"或者'或者空格的支持. 2.补充char/clob/blob/json等类型,如果类型未知,默认为String.| +|20180915|新增Swagger-UI模板.修复一些命名和导入问题.JPA的Entity默认第一个字段为Id,如果不是请手工修改.| +|20180913|修复字段没有描述以及类型为DATE型导致的问题.新增JPA的Controller模板.| +|20180831|初始化项目.新增JPA系列Entity+Repository模板.| + +# FieldName +|字段名|说明| +|-|-| +|packageName|自定义的包名| +|authorName|自定义的作者名| +|returnUtil|自定义的返回Util| +|tableName|sql中的表名| +|className|java类名| +|classComment|sql表备注/java类备注| +|fieldName|字段名| +|fieldComment|字段备注| + + + + + + + + diff --git a/codegenerator4.png b/codegenerator4.png new file mode 100644 index 00000000..e1d23e41 Binary files /dev/null and b/codegenerator4.png differ diff --git a/generator-web/pom.xml b/generator-web/pom.xml index 3ca5e97d..fcb8dc64 100644 --- a/generator-web/pom.xml +++ b/generator-web/pom.xml @@ -7,12 +7,12 @@ com.softdev.system SpringBootCodeGenerator - 0.0.1-SNAPSHOT + 2.0 com.softdev.system generator-web - 0.0.1-SNAPSHOT + 2.0 jar @@ -38,10 +38,10 @@ spring-boot-starter-data-jpa --> - + @@ -65,7 +65,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.8.1 true javac @@ -87,25 +87,24 @@ org.apache.maven.plugins maven-resources-plugin - 3.0.1 + 3.1.0 true - + org.springframework.boot spring-boot-maven-plugin - 2.0.4.RELEASE diff --git a/generator-web/src/main/java/com/softdev/system/generator/controller/IndexController.java b/generator-web/src/main/java/com/softdev/system/generator/controller/IndexController.java index 4df4b894..4d37f206 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/controller/IndexController.java +++ b/generator-web/src/main/java/com/softdev/system/generator/controller/IndexController.java @@ -1,79 +1,83 @@ -package com.softdev.system.generator.controller; - -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.CodeGenerateException; -import com.softdev.system.generator.util.FreemarkerTool; -import com.softdev.system.generator.util.TableParseUtil; -import freemarker.template.TemplateException; -import lombok.extern.slf4j.Slf4j; -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 java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - * spring boot code generator - * @author zhengk/moshow - */ -@Controller -@Slf4j -public class IndexController { - - @Autowired - private GeneratorService generatorService; - - @GetMapping("/") - public String index() { - return "index"; - } - - @PostMapping("/genCode") - @ResponseBody - public ReturnT> codeGenerate( ParamInfo paramInfo ) { - - try { - - if (StringUtils.isBlank(paramInfo.getTableSql())) { - return new ReturnT<>(ReturnT.FAIL_CODE, "表结构信息不可为空"); - } - - // parse table - ClassInfo classInfo = null; - switch (paramInfo.getDataType()){ - //parse json - case "json":classInfo = TableParseUtil.processJsonToClassInfo(paramInfo);break; - //parse sql by regex - case "sql-regex":classInfo = TableParseUtil.processTableToClassInfoByRegex(paramInfo);break; - //default parse sql by java - default : classInfo = TableParseUtil.processTableIntoClassInfo(paramInfo);break; - } - - // process the param - Map params = new HashMap(8); - params.put("classInfo", classInfo); - params.put("authorName", paramInfo.getAuthorName()); - params.put("packageName", paramInfo.getPackageName()); - params.put("returnUtil", paramInfo.getReturnUtil()); - - // generate the code 需要加新的模板请在里面改 - Map result = generatorService.getResultByParams(params); - - return new ReturnT<>(result); - } catch (IOException | TemplateException e) { - log.error(e.getMessage(), e); - return new ReturnT<>(ReturnT.FAIL_CODE, e.getMessage()); - } catch (CodeGenerateException e) { - log.error(e.getMessage(), e); - return new ReturnT<>(ReturnT.FAIL_CODE, e.getMessage()); - } - - } - -} +package com.softdev.system.generator.controller; + +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.CodeGenerateException; +import com.softdev.system.generator.util.TableParseUtil; +import freemarker.template.TemplateException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * spring boot code generator + * @author zhengk/moshow + */ +@Controller +@Slf4j +public class IndexController { + + @Autowired + private GeneratorService generatorService; + + @GetMapping("/") + public String index() { + return "index"; + } + + @PostMapping("/genCode") + @ResponseBody + public ReturnT> codeGenerate( ParamInfo paramInfo ) { + + try { + + if (StringUtils.isBlank(paramInfo.getTableSql())) { + return new ReturnT<>(ReturnT.FAIL_CODE, "表结构信息不可为空"); + } + + // parse table + ClassInfo classInfo = null; + switch (paramInfo.getDataType()){ + //parse json + case "json":classInfo = TableParseUtil.processJsonToClassInfo(paramInfo);break; + //parse sql by regex + case "sql-regex":classInfo = TableParseUtil.processTableToClassInfoByRegex(paramInfo);break; + //default parse sql by java + default : classInfo = TableParseUtil.processTableIntoClassInfo(paramInfo);break; + } + + // process the param + Map params = new HashMap(8); + params.put("classInfo", classInfo); + params.put("authorName", paramInfo.getAuthorName()); + params.put("packageName", paramInfo.getPackageName()); + params.put("returnUtil", paramInfo.getReturnUtil()); + + log.info("generator table:"+(classInfo==null?"":classInfo.getTableName()) + +",field size:"+((classInfo==null||classInfo.getFieldList()==null)?"":classInfo.getFieldList().size())); + + // generate the code 需要加新的模板请在里面改 + Map result = generatorService.getResultByParams(params); + + return new ReturnT<>(result); + } catch (IOException | TemplateException e) { + log.error(e.getMessage(), e); + return new ReturnT<>(ReturnT.FAIL_CODE, e.getMessage()); + } catch (CodeGenerateException e) { + log.error(e.getMessage(), e); + return new ReturnT<>(ReturnT.FAIL_CODE, e.getMessage()); + } + + } + +} diff --git a/generator-web/src/main/java/com/softdev/system/generator/util/TableParseUtil.java b/generator-web/src/main/java/com/softdev/system/generator/util/TableParseUtil.java index 843bf3eb..f8658283 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/util/TableParseUtil.java +++ b/generator-web/src/main/java/com/softdev/system/generator/util/TableParseUtil.java @@ -1,425 +1,421 @@ -package com.softdev.system.generator.util; - - -import cn.hutool.core.util.XmlUtil; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.softdev.system.generator.entity.ClassInfo; -import com.softdev.system.generator.entity.FieldInfo; -import com.softdev.system.generator.entity.ParamInfo; -import org.w3c.dom.Document; - -import java.io.IOException; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @author zhengkai.blog.csdn.net - */ -public class TableParseUtil { - - /** - * 解析建表SQL生成代码(model-dao-xml) - * - * @param paramInfo - * @return - */ - public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo) - throws IOException { - //process the param - String tableSql=paramInfo.getTableSql(); - String nameCaseType=paramInfo.getNameCaseType(); - String tinyintTransType=paramInfo.getTinyintTransType(); - - if (tableSql==null || tableSql.trim().length()==0) { - throw new CodeGenerateException("Table structure can not be empty."); - } - //deal with special character - tableSql = tableSql.trim().replaceAll("'","`").replaceAll("\"","`").replaceAll(",",",").toLowerCase(); - //deal with java string copy \n" - System.out.println(tableSql); - tableSql = tableSql.trim().replaceAll("n`","").replaceAll("\\+","").replaceAll("``","`").replaceAll("\\\\",""); - System.out.println(tableSql); - // table Name - String tableName = null; - if (tableSql.contains("TABLE") && tableSql.contains("(")) { - tableName = tableSql.substring(tableSql.indexOf("TABLE")+5, tableSql.indexOf("(")); - } else if (tableSql.contains("table") && tableSql.contains("(")) { - tableName = tableSql.substring(tableSql.indexOf("table")+5, tableSql.indexOf("(")); - } else { - throw new CodeGenerateException("Table structure anomaly."); - } - - //新增处理create table if not exists members情况 - if (tableName.contains("if not exists")) { - tableName=tableName.replaceAll("if not exists",""); - } - - if (tableName.contains("`")) { - tableName = tableName.substring(tableName.indexOf("`")+1, tableName.lastIndexOf("`")); - }else{ - //空格开头的,需要替换掉\n\t空格 - tableName=tableName.replaceAll(" ","").replaceAll("\n","").replaceAll("\t",""); - } - //优化对byeas`.`ct_bd_customerdiscount这种命名的支持 - if(tableName.contains("`.`")){ - tableName=tableName.substring(tableName.indexOf("`.`")+3); - }else if(tableName.contains(".")){ - //优化对likeu.members这种命名的支持 - tableName=tableName.substring(tableName.indexOf(".")+1); - } - // class Name - String className = StringUtils.upperCaseFirst(StringUtils.underlineToCamelCase(tableName)); - if (className.contains("_")) { - className = className.replaceAll("_", ""); - } - - // class Comment - String classComment = null; - //mysql是comment=,pgsql/oracle是comment on table, - if (tableSql.contains("comment=")) { - String classCommentTmp = tableSql.substring(tableSql.lastIndexOf("comment=")+8).replaceAll("`","").trim(); - if (classCommentTmp.indexOf(" ")!=classCommentTmp.lastIndexOf(" ")) { - classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf(" ")+1, classCommentTmp.lastIndexOf(" ")); - } - if (classCommentTmp!=null && classCommentTmp.trim().length()>0) { - classComment = classCommentTmp; - }else{ - //修复表备注为空问题 - classComment = className; - } - }else if(tableSql.contains("comment on table")) { - //COMMENT ON TABLE CT_BAS_FEETYPE IS 'CT_BAS_FEETYPE'; - String classCommentTmp = tableSql.substring(tableSql.lastIndexOf("comment on table")+17).trim(); - //证明这是一个常规的COMMENT ON TABLE xxx IS 'xxxx' - if (classCommentTmp.contains("`")) { - classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf("`")+1); - classCommentTmp = classCommentTmp.substring(0,classCommentTmp.indexOf("`")); - classComment = classCommentTmp; - }else{ - //非常规的没法分析 - classComment = tableName; - } - }else{ - //修复表备注为空问题 - classComment = tableName; - } - //如果备注跟;混在一起,需要替换掉 - classComment=classComment.replaceAll(";",""); - // field List - List fieldList = new ArrayList(); - - // 正常( ) 内的一定是字段相关的定义。 - String fieldListTmp = tableSql.substring(tableSql.indexOf("(")+1, tableSql.lastIndexOf(")")); - - // 匹配 comment,替换备注里的小逗号, 防止不小心被当成切割符号切割 - String commentPattenStr1="comment `(.*?)\\`"; - Matcher matcher1 = Pattern.compile(commentPattenStr1).matcher(fieldListTmp); - while(matcher1.find()){ - - String commentTmp = matcher1.group(); - //2018-9-27 zhengk 不替换,只处理,支持COMMENT评论里面多种注释 - //commentTmp = commentTmp.replaceAll("\\ comment `|\\`", " "); // "\\{|\\}" - - if (commentTmp.contains(",")) { - String commentTmpFinal = commentTmp.replaceAll(",", ","); - fieldListTmp = fieldListTmp.replace(matcher1.group(), commentTmpFinal); - } - } - //2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况 - String commentPattenStr2="\\`(.*?)\\`"; - Matcher matcher2 = Pattern.compile(commentPattenStr2).matcher(fieldListTmp); - while(matcher2.find()){ - String commentTmp2 = matcher2.group(); - if (commentTmp2.contains(",")) { - String commentTmpFinal = commentTmp2.replaceAll(",", ",").replaceAll("\\(", "(").replaceAll("\\)", ")"); - fieldListTmp = fieldListTmp.replace(matcher2.group(), commentTmpFinal); - } - } - //2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况 - String commentPattenStr3="\\((.*?)\\)"; - Matcher matcher3 = Pattern.compile(commentPattenStr3).matcher(fieldListTmp); - while(matcher3.find()){ - String commentTmp3 = matcher3.group(); - if (commentTmp3.contains(",")) { - String commentTmpFinal = commentTmp3.replaceAll(",", ","); - fieldListTmp = fieldListTmp.replace(matcher3.group(), commentTmpFinal); - } - } - String[] fieldLineList = fieldListTmp.split(","); - if (fieldLineList.length > 0) { - int i=0; - //i为了解决primary key关键字出现的地方,出现在前3行,一般和id有关 - for (String columnLine :fieldLineList) { - i++; - columnLine = columnLine.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的反馈 ) - boolean specialFlag=(!columnLine.contains("key ")&&!columnLine.contains("constraint")&&!columnLine.contains("using")&&!columnLine.contains("unique") - &&!(columnLine.contains("primary ")&&columnLine.indexOf("storage")+3>columnLine.indexOf("(")) - &&!columnLine.contains("pctincrease") - &&!columnLine.contains("buffer_pool")&&!columnLine.contains("tablespace") - &&!(columnLine.contains("primary ")&&i>3)); - if (specialFlag){ - //如果是oracle的number(x,x),可能出现最后分割残留的,x),这里做排除处理 - if(columnLine.length()<5) {continue;} - //2018-9-16 zhengkai 支持'符号以及空格的oracle语句// userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', - String columnName = ""; - columnLine=columnLine.replaceAll("`"," ").replaceAll("\""," ").replaceAll("'","").replaceAll(" "," ").trim(); - //如果遇到username varchar(65) default '' not null,这种情况,判断第一个空格是否比第一个引号前 - columnName = columnLine.substring(0, columnLine.indexOf(" ")); - // field Name - // 2019-09-08 yj 添加是否下划线转换为驼峰的判断 - String fieldName=null; - if(ParamInfo.NAME_CASE_TYPE.CAMEL_CASE.equals(nameCaseType)){ - fieldName = StringUtils.lowerCaseFirst(StringUtils.underlineToCamelCase(columnName)); - if (fieldName.contains("_")) { - fieldName = fieldName.replaceAll("_", ""); - } - }else if(ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE.equals(nameCaseType)){ - fieldName = StringUtils.lowerCaseFirst(columnName); - }else if(ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE.equals(nameCaseType)){ - fieldName = StringUtils.lowerCaseFirst(columnName.toUpperCase()); - }else{ - fieldName=columnName; - } - - // field class - columnLine = columnLine.substring(columnLine.indexOf("`")+1).trim(); - // int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', - String fieldClass = Object.class.getSimpleName(); - //2018-9-16 zhengk 补充char/clob/blob/json等类型,如果类型未知,默认为String - //2018-11-22 lshz0088 处理字段类型的时候,不严谨columnLine.contains(" int") 类似这种的,可在前后适当加一些空格之类的加以区分,否则当我的字段包含这些字符的时候,产生类型判断问题。 - if (columnLine.contains(" int") || columnLine.contains("smallint")) { - fieldClass = Integer.class.getSimpleName(); - } else if (columnLine.contains("bigint")) { - fieldClass = Long.class.getSimpleName(); - } else if (columnLine.contains("float")) { - fieldClass = Float.class.getSimpleName(); - } else if (columnLine.contains("double")) { - fieldClass = Double.class.getSimpleName(); - } else if (columnLine.contains("time") || columnLine.contains("date") || columnLine.contains("datetime") || columnLine.contains("timestamp")) { - fieldClass = Date.class.getSimpleName(); - } else if (columnLine.contains("varchar") || columnLine.contains(" text")|| columnLine.contains("char") - || columnLine.contains("clob")||columnLine.contains("blob")||columnLine.contains("json")) { - fieldClass = String.class.getSimpleName(); - } else if (columnLine.contains("decimal")||columnLine.contains(" number")) { - //2018-11-22 lshz0088 建议对number类型增加int,long,BigDecimal的区分判断 - //如果startKh大于等于0,则表示有设置取值范围 - int startKh=columnLine.indexOf("("); - if(startKh>=0){ - int endKh=columnLine.indexOf(")",startKh); - String[] fanwei=columnLine.substring(startKh+1,endKh).split(","); - //2019-1-5 zhengk 修复@arthaschan反馈的超出范围错误 - //System.out.println("fanwei"+ JSON.toJSONString(fanwei)); - // //number(20,6) fanwei["20","6"] - // //number(0,6) fanwei["0","6"] - // //number(20,0) fanwei["20","0"] - // //number(20) fanwei["20"] - //如果括号里是1位或者2位且第二位为0,则进行特殊处理。只有有小数位,都设置为BigDecimal。 - if((fanwei.length>1&&"0".equals(fanwei[1]))||fanwei.length==1){ - int length=Integer.parseInt(fanwei[0]); - if(fanwei.length>1) { - length=Integer.valueOf(fanwei[1]); - } - //数字范围9位及一下用Integer,大的用Long - if(length<=9){ - fieldClass = Integer.class.getSimpleName(); - }else{ - fieldClass = Long.class.getSimpleName(); - } - }else{ - //有小数位数一律使用BigDecimal - fieldClass = BigDecimal.class.getSimpleName(); - } - }else{ - fieldClass = BigDecimal.class.getSimpleName(); - } - } else if (columnLine.contains("boolean")) { - //20190910 MOSHOW.K.ZHENG 新增对boolean的处理(感谢@violinxsc的反馈)以及修复tinyint类型字段无法生成boolean类型问题(感谢@hahaYhui的反馈) - fieldClass = Boolean.class.getSimpleName(); - } else if (columnLine.contains("tinyint") ) { - //20191115 MOSHOW.K.ZHENG 支持对tinyint的特殊处理 - fieldClass=tinyintTransType; - } else { - fieldClass = String.class.getSimpleName(); - } - - // field comment,MySQL的一般位于field行,而pgsql和oralce多位于后面。 - String fieldComment = null; - if(tableSql.contains("comment on column")&&(tableSql.contains("."+columnName+" is ")||tableSql.contains(".`"+columnName+"` is"))){ - //新增对pgsql/oracle的字段备注支持 - //COMMENT ON COLUMN public.check_info.check_name IS '检查者名称'; - //2018-11-22 lshz0088 正则表达式的点号前面应该加上两个反斜杠,否则会认为是任意字符 - //2019-4-29 zhengkai 优化对oracle注释comment on column的支持(@liukex) - tableSql=tableSql.replaceAll(".`"+columnName+"` is","."+columnName+" is"); - Matcher columnCommentMatcher = Pattern.compile("\\."+columnName+" is `").matcher(tableSql); - fieldComment=columnName; - while(columnCommentMatcher.find()){ - String columnCommentTmp = columnCommentMatcher.group(); - System.out.println(columnCommentTmp); - fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp)+columnCommentTmp.length()).trim(); - fieldComment = fieldComment.substring(0,fieldComment.indexOf("`")).trim(); - } - }else if (columnLine.contains("comment")) { - String commentTmp = columnLine.substring(columnLine.indexOf("comment")+7).trim(); - // '用户ID', - if (commentTmp.contains("`") || commentTmp.indexOf("`")!=commentTmp.lastIndexOf("`")) { - commentTmp = commentTmp.substring(commentTmp.indexOf("`")+1, commentTmp.lastIndexOf("`")); - } - //解决最后一句是评论,无主键且连着)的问题:album_id int(3) default '1' null comment '相册id:0 代表头像 1代表照片墙') - if(commentTmp.contains(")")){ - commentTmp = commentTmp.substring(0, commentTmp.lastIndexOf(")")+1); - } - fieldComment = commentTmp; - }else{ - //修复comment不存在导致报错的问题 - fieldComment = columnName; - } - - FieldInfo fieldInfo = new FieldInfo(); - fieldInfo.setColumnName(columnName); - fieldInfo.setFieldName(fieldName); - fieldInfo.setFieldClass(fieldClass); - fieldInfo.setFieldComment(fieldComment); - - fieldList.add(fieldInfo); - } - } - } - - if (fieldList.size() < 1) { - throw new CodeGenerateException("表结构分析失败,请检查语句或者提交issue给我"); - } - - ClassInfo codeJavaInfo = new ClassInfo(); - codeJavaInfo.setTableName(tableName); - codeJavaInfo.setClassName(className); - codeJavaInfo.setClassComment(classComment); - codeJavaInfo.setFieldList(fieldList); - - return codeJavaInfo; - } - /** - * parse JSON - * @param paramInfo - * @return - */ - public static 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 - * @author https://github.com/ydq - * @param paramInfo - * @return - */ - public static ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo){ - // field List - List fieldList = new ArrayList(); - //return classInfo - ClassInfo codeJavaInfo = new ClassInfo(); - - //匹配整个ddl,将ddl分为表名,列sql部分,表注释 - String DDL_PATTEN_STR="\\s*create\\s+table\\s+(?\\S+)[^\\(]*\\((?[\\s\\S]+)\\)[^\\)]+?(comment\\s*(=|on\\s+table)\\s*'(?.*?)'\\s*;?)?$"; - - Pattern DDL_PATTERN = Pattern.compile(DDL_PATTEN_STR, Pattern.CASE_INSENSITIVE); - - //匹配列sql部分,分别解析每一列的列名 类型 和列注释 - String COL_PATTERN_STR="\\s*(?\\S+)\\s+(?\\w+)\\s*(?:\\([\\s\\d,]+\\))?((?!comment).)*(comment\\s*'(?.*?)')?\\s*(,|$)"; - - Pattern COL_PATTERN = Pattern.compile(COL_PATTERN_STR, Pattern.CASE_INSENSITIVE); - - Matcher matcher = DDL_PATTERN.matcher(paramInfo.getTableSql().trim()); - if (matcher.find()){ - String tableName = matcher.group("tableName"); - String tableComment = matcher.group("tableComment"); - codeJavaInfo.setTableName(tableName.replaceAll("'","")); - codeJavaInfo.setClassName(tableName.replaceAll("'","")); - codeJavaInfo.setClassComment(tableComment.replaceAll("'","")); - String columnsSQL = matcher.group("columnsSQL"); - if (columnsSQL != null && columnsSQL.length() > 0){ - Matcher colMatcher = COL_PATTERN.matcher(columnsSQL); - while (colMatcher.find()){ - String fieldName = colMatcher.group("fieldName"); - String fieldType = colMatcher.group("fieldType"); - String fieldComment = colMatcher.group("fieldComment"); - if (!"key".equalsIgnoreCase(fieldType)){ - FieldInfo fieldInfo = new FieldInfo(); - fieldInfo.setFieldName(fieldName.replaceAll("'","")); - fieldInfo.setColumnName(fieldName.replaceAll("'","")); - fieldInfo.setFieldClass(fieldType.replaceAll("'","")); - fieldInfo.setFieldComment(fieldComment.replaceAll("'","")); - fieldList.add(fieldInfo); - } - } - } - codeJavaInfo.setFieldList(fieldList); - } - return codeJavaInfo; - } - public static List processJsonObjectToFieldList(JSONObject jsonObject){ - // field List - List fieldList = new ArrayList(); - 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; - } -} +package com.softdev.system.generator.util; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.softdev.system.generator.entity.ClassInfo; +import com.softdev.system.generator.entity.FieldInfo; +import com.softdev.system.generator.entity.ParamInfo; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author zhengkai.blog.csdn.net + */ +public class TableParseUtil { + + /** + * 解析建表SQL生成代码(model-dao-xml) + * + * @param paramInfo + * @return + */ + public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo) + throws IOException { + //process the param + String tableSql=paramInfo.getTableSql(); + String nameCaseType=paramInfo.getNameCaseType(); + String tinyintTransType=paramInfo.getTinyintTransType(); + + if (tableSql==null || tableSql.trim().length()==0) { + throw new CodeGenerateException("Table structure can not be empty."); + } + //deal with special character + tableSql = tableSql.trim().replaceAll("'","`").replaceAll("\"","`").replaceAll(",",",").toLowerCase(); + //deal with java string copy \n" + tableSql = tableSql.trim().replaceAll("\\\\n`","").replaceAll("\\+","").replaceAll("``","`").replaceAll("\\\\",""); + // table Name + String tableName = null; + if (tableSql.contains("TABLE") && tableSql.contains("(")) { + tableName = tableSql.substring(tableSql.indexOf("TABLE")+5, tableSql.indexOf("(")); + } else if (tableSql.contains("table") && tableSql.contains("(")) { + tableName = tableSql.substring(tableSql.indexOf("table")+5, tableSql.indexOf("(")); + } else { + throw new CodeGenerateException("Table structure anomaly."); + } + + //新增处理create table if not exists members情况 + if (tableName.contains("if not exists")) { + tableName=tableName.replaceAll("if not exists",""); + } + + if (tableName.contains("`")) { + tableName = tableName.substring(tableName.indexOf("`")+1, tableName.lastIndexOf("`")); + }else{ + //空格开头的,需要替换掉\n\t空格 + tableName=tableName.replaceAll(" ","").replaceAll("\n","").replaceAll("\t",""); + } + //优化对byeas`.`ct_bd_customerdiscount这种命名的支持 + if(tableName.contains("`.`")){ + tableName=tableName.substring(tableName.indexOf("`.`")+3); + }else if(tableName.contains(".")){ + //优化对likeu.members这种命名的支持 + tableName=tableName.substring(tableName.indexOf(".")+1); + } + // class Name + String className = StringUtils.upperCaseFirst(StringUtils.underlineToCamelCase(tableName)); + if (className.contains("_")) { + className = className.replaceAll("_", ""); + } + + // class Comment + String classComment = null; + //mysql是comment=,pgsql/oracle是comment on table, + if (tableSql.contains("comment=")) { + String classCommentTmp = tableSql.substring(tableSql.lastIndexOf("comment=")+8).replaceAll("`","").trim(); + if (classCommentTmp.indexOf(" ")!=classCommentTmp.lastIndexOf(" ")) { + classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf(" ")+1, classCommentTmp.lastIndexOf(" ")); + } + if (classCommentTmp!=null && classCommentTmp.trim().length()>0) { + classComment = classCommentTmp; + }else{ + //修复表备注为空问题 + classComment = className; + } + }else if(tableSql.contains("comment on table")) { + //COMMENT ON TABLE CT_BAS_FEETYPE IS 'CT_BAS_FEETYPE'; + String classCommentTmp = tableSql.substring(tableSql.lastIndexOf("comment on table")+17).trim(); + //证明这是一个常规的COMMENT ON TABLE xxx IS 'xxxx' + if (classCommentTmp.contains("`")) { + classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf("`")+1); + classCommentTmp = classCommentTmp.substring(0,classCommentTmp.indexOf("`")); + classComment = classCommentTmp; + }else{ + //非常规的没法分析 + classComment = tableName; + } + }else{ + //修复表备注为空问题 + classComment = tableName; + } + //如果备注跟;混在一起,需要替换掉 + classComment=classComment.replaceAll(";",""); + // field List + List fieldList = new ArrayList(); + + // 正常( ) 内的一定是字段相关的定义。 + String fieldListTmp = tableSql.substring(tableSql.indexOf("(")+1, tableSql.lastIndexOf(")")); + + // 匹配 comment,替换备注里的小逗号, 防止不小心被当成切割符号切割 + String commentPattenStr1="comment `(.*?)\\`"; + Matcher matcher1 = Pattern.compile(commentPattenStr1).matcher(fieldListTmp); + while(matcher1.find()){ + + String commentTmp = matcher1.group(); + //2018-9-27 zhengk 不替换,只处理,支持COMMENT评论里面多种注释 + //commentTmp = commentTmp.replaceAll("\\ comment `|\\`", " "); // "\\{|\\}" + + if (commentTmp.contains(",")) { + String commentTmpFinal = commentTmp.replaceAll(",", ","); + fieldListTmp = fieldListTmp.replace(matcher1.group(), commentTmpFinal); + } + } + //2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况 + String commentPattenStr2="\\`(.*?)\\`"; + Matcher matcher2 = Pattern.compile(commentPattenStr2).matcher(fieldListTmp); + while(matcher2.find()){ + String commentTmp2 = matcher2.group(); + if (commentTmp2.contains(",")) { + String commentTmpFinal = commentTmp2.replaceAll(",", ",").replaceAll("\\(", "(").replaceAll("\\)", ")"); + fieldListTmp = fieldListTmp.replace(matcher2.group(), commentTmpFinal); + } + } + //2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况 + String commentPattenStr3="\\((.*?)\\)"; + Matcher matcher3 = Pattern.compile(commentPattenStr3).matcher(fieldListTmp); + while(matcher3.find()){ + String commentTmp3 = matcher3.group(); + if (commentTmp3.contains(",")) { + String commentTmpFinal = commentTmp3.replaceAll(",", ","); + fieldListTmp = fieldListTmp.replace(matcher3.group(), commentTmpFinal); + } + } + String[] fieldLineList = fieldListTmp.split(","); + if (fieldLineList.length > 0) { + int i=0; + //i为了解决primary key关键字出现的地方,出现在前3行,一般和id有关 + for (String columnLine :fieldLineList) { + i++; + columnLine = columnLine.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的反馈 ) + boolean specialFlag=(!columnLine.contains("key ")&&!columnLine.contains("constraint")&&!columnLine.contains("using")&&!columnLine.contains("unique") + &&!(columnLine.contains("primary ")&&columnLine.indexOf("storage")+3>columnLine.indexOf("(")) + &&!columnLine.contains("pctincrease") + &&!columnLine.contains("buffer_pool")&&!columnLine.contains("tablespace") + &&!(columnLine.contains("primary ")&&i>3)); + if (specialFlag){ + //如果是oracle的number(x,x),可能出现最后分割残留的,x),这里做排除处理 + if(columnLine.length()<5) {continue;} + //2018-9-16 zhengkai 支持'符号以及空格的oracle语句// userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', + String columnName = ""; + columnLine=columnLine.replaceAll("`"," ").replaceAll("\""," ").replaceAll("'","").replaceAll(" "," ").trim(); + //如果遇到username varchar(65) default '' not null,这种情况,判断第一个空格是否比第一个引号前 + columnName = columnLine.substring(0, columnLine.indexOf(" ")); + // field Name + // 2019-09-08 yj 添加是否下划线转换为驼峰的判断 + String fieldName=null; + if(ParamInfo.NAME_CASE_TYPE.CAMEL_CASE.equals(nameCaseType)){ + fieldName = StringUtils.lowerCaseFirst(StringUtils.underlineToCamelCase(columnName)); + if (fieldName.contains("_")) { + fieldName = fieldName.replaceAll("_", ""); + } + }else if(ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE.equals(nameCaseType)){ + fieldName = StringUtils.lowerCaseFirst(columnName); + }else if(ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE.equals(nameCaseType)){ + fieldName = StringUtils.lowerCaseFirst(columnName.toUpperCase()); + }else{ + fieldName=columnName; + } + + // field class + columnLine = columnLine.substring(columnLine.indexOf("`")+1).trim(); + // int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', + String fieldClass = Object.class.getSimpleName(); + //2018-9-16 zhengk 补充char/clob/blob/json等类型,如果类型未知,默认为String + //2018-11-22 lshz0088 处理字段类型的时候,不严谨columnLine.contains(" int") 类似这种的,可在前后适当加一些空格之类的加以区分,否则当我的字段包含这些字符的时候,产生类型判断问题。 + if (columnLine.contains(" int") || columnLine.contains("smallint")) { + fieldClass = Integer.class.getSimpleName(); + } else if (columnLine.contains("bigint")) { + fieldClass = Long.class.getSimpleName(); + } else if (columnLine.contains("float")) { + fieldClass = Float.class.getSimpleName(); + } else if (columnLine.contains("double")) { + fieldClass = Double.class.getSimpleName(); + } else if (columnLine.contains("time") || columnLine.contains("date") || columnLine.contains("datetime") || columnLine.contains("timestamp")) { + fieldClass = Date.class.getSimpleName(); + } else if (columnLine.contains("varchar") || columnLine.contains(" text")|| columnLine.contains("char") + || columnLine.contains("clob")||columnLine.contains("blob")||columnLine.contains("json")) { + fieldClass = String.class.getSimpleName(); + } else if (columnLine.contains("decimal")||columnLine.contains(" number")) { + //2018-11-22 lshz0088 建议对number类型增加int,long,BigDecimal的区分判断 + //如果startKh大于等于0,则表示有设置取值范围 + int startKh=columnLine.indexOf("("); + if(startKh>=0){ + int endKh=columnLine.indexOf(")",startKh); + String[] fanwei=columnLine.substring(startKh+1,endKh).split(","); + //2019-1-5 zhengk 修复@arthaschan反馈的超出范围错误 + //System.out.println("fanwei"+ JSON.toJSONString(fanwei)); + // //number(20,6) fanwei["20","6"] + // //number(0,6) fanwei["0","6"] + // //number(20,0) fanwei["20","0"] + // //number(20) fanwei["20"] + //如果括号里是1位或者2位且第二位为0,则进行特殊处理。只有有小数位,都设置为BigDecimal。 + if((fanwei.length>1&&"0".equals(fanwei[1]))||fanwei.length==1){ + int length=Integer.parseInt(fanwei[0]); + if(fanwei.length>1) { + length=Integer.valueOf(fanwei[1]); + } + //数字范围9位及一下用Integer,大的用Long + if(length<=9){ + fieldClass = Integer.class.getSimpleName(); + }else{ + fieldClass = Long.class.getSimpleName(); + } + }else{ + //有小数位数一律使用BigDecimal + fieldClass = BigDecimal.class.getSimpleName(); + } + }else{ + fieldClass = BigDecimal.class.getSimpleName(); + } + } else if (columnLine.contains("boolean")) { + //20190910 MOSHOW.K.ZHENG 新增对boolean的处理(感谢@violinxsc的反馈)以及修复tinyint类型字段无法生成boolean类型问题(感谢@hahaYhui的反馈) + fieldClass = Boolean.class.getSimpleName(); + } else if (columnLine.contains("tinyint") ) { + //20191115 MOSHOW.K.ZHENG 支持对tinyint的特殊处理 + fieldClass=tinyintTransType; + } else { + fieldClass = String.class.getSimpleName(); + } + + // field comment,MySQL的一般位于field行,而pgsql和oralce多位于后面。 + String fieldComment = null; + if(tableSql.contains("comment on column")&&(tableSql.contains("."+columnName+" is ")||tableSql.contains(".`"+columnName+"` is"))){ + //新增对pgsql/oracle的字段备注支持 + //COMMENT ON COLUMN public.check_info.check_name IS '检查者名称'; + //2018-11-22 lshz0088 正则表达式的点号前面应该加上两个反斜杠,否则会认为是任意字符 + //2019-4-29 zhengkai 优化对oracle注释comment on column的支持(@liukex) + tableSql=tableSql.replaceAll(".`"+columnName+"` is","."+columnName+" is"); + Matcher columnCommentMatcher = Pattern.compile("\\."+columnName+" is `").matcher(tableSql); + fieldComment=columnName; + while(columnCommentMatcher.find()){ + String columnCommentTmp = columnCommentMatcher.group(); + System.out.println(columnCommentTmp); + fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp)+columnCommentTmp.length()).trim(); + fieldComment = fieldComment.substring(0,fieldComment.indexOf("`")).trim(); + } + }else if (columnLine.contains("comment")) { + String commentTmp = columnLine.substring(columnLine.indexOf("comment")+7).trim(); + // '用户ID', + if (commentTmp.contains("`") || commentTmp.indexOf("`")!=commentTmp.lastIndexOf("`")) { + commentTmp = commentTmp.substring(commentTmp.indexOf("`")+1, commentTmp.lastIndexOf("`")); + } + //解决最后一句是评论,无主键且连着)的问题:album_id int(3) default '1' null comment '相册id:0 代表头像 1代表照片墙') + if(commentTmp.contains(")")){ + commentTmp = commentTmp.substring(0, commentTmp.lastIndexOf(")")+1); + } + fieldComment = commentTmp; + }else{ + //修复comment不存在导致报错的问题 + fieldComment = columnName; + } + + FieldInfo fieldInfo = new FieldInfo(); + fieldInfo.setColumnName(columnName); + fieldInfo.setFieldName(fieldName); + fieldInfo.setFieldClass(fieldClass); + fieldInfo.setFieldComment(fieldComment); + + fieldList.add(fieldInfo); + } + } + } + + if (fieldList.size() < 1) { + throw new CodeGenerateException("表结构分析失败,请检查语句或者提交issue给我"); + } + + ClassInfo codeJavaInfo = new ClassInfo(); + codeJavaInfo.setTableName(tableName); + codeJavaInfo.setClassName(className); + codeJavaInfo.setClassComment(classComment); + codeJavaInfo.setFieldList(fieldList); + + return codeJavaInfo; + } + /** + * parse JSON + * @param paramInfo + * @return + */ + public static 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 + * @author https://github.com/ydq + * @param paramInfo + * @return + */ + public static ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo){ + // field List + List fieldList = new ArrayList(); + //return classInfo + ClassInfo codeJavaInfo = new ClassInfo(); + + //匹配整个ddl,将ddl分为表名,列sql部分,表注释 + String DDL_PATTEN_STR="\\s*create\\s+table\\s+(?\\S+)[^\\(]*\\((?[\\s\\S]+)\\)[^\\)]+?(comment\\s*(=|on\\s+table)\\s*'(?.*?)'\\s*;?)?$"; + + Pattern DDL_PATTERN = Pattern.compile(DDL_PATTEN_STR, Pattern.CASE_INSENSITIVE); + + //匹配列sql部分,分别解析每一列的列名 类型 和列注释 + String COL_PATTERN_STR="\\s*(?\\S+)\\s+(?\\w+)\\s*(?:\\([\\s\\d,]+\\))?((?!comment).)*(comment\\s*'(?.*?)')?\\s*(,|$)"; + + Pattern COL_PATTERN = Pattern.compile(COL_PATTERN_STR, Pattern.CASE_INSENSITIVE); + + Matcher matcher = DDL_PATTERN.matcher(paramInfo.getTableSql().trim()); + if (matcher.find()){ + String tableName = matcher.group("tableName"); + String tableComment = matcher.group("tableComment"); + codeJavaInfo.setTableName(tableName.replaceAll("'","")); + codeJavaInfo.setClassName(tableName.replaceAll("'","")); + codeJavaInfo.setClassComment(tableComment.replaceAll("'","")); + String columnsSQL = matcher.group("columnsSQL"); + if (columnsSQL != null && columnsSQL.length() > 0){ + Matcher colMatcher = COL_PATTERN.matcher(columnsSQL); + while (colMatcher.find()){ + String fieldName = colMatcher.group("fieldName"); + String fieldType = colMatcher.group("fieldType"); + String fieldComment = colMatcher.group("fieldComment"); + if (!"key".equalsIgnoreCase(fieldType)){ + FieldInfo fieldInfo = new FieldInfo(); + fieldInfo.setFieldName(fieldName.replaceAll("'","")); + fieldInfo.setColumnName(fieldName.replaceAll("'","")); + fieldInfo.setFieldClass(fieldType.replaceAll("'","")); + fieldInfo.setFieldComment(fieldComment.replaceAll("'","")); + fieldList.add(fieldInfo); + } + } + } + codeJavaInfo.setFieldList(fieldList); + } + return codeJavaInfo; + } + public static List processJsonObjectToFieldList(JSONObject jsonObject){ + // field List + List fieldList = new ArrayList(); + 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; + } +} diff --git a/generator-web/src/main/resources/application.yml b/generator-web/src/main/resources/application.yml index c54490d9..b8563c87 100644 --- a/generator-web/src/main/resources/application.yml +++ b/generator-web/src/main/resources/application.yml @@ -2,17 +2,25 @@ server: port: 1234 servlet: context-path: /generator -tomcat: - remote-ip-header: x-forward-for - uri-encoding: UTF-8 - max-threads: 10 - background-processor-delay: 30 - basedir: ${user.home}/tomcat/ +#tomcat: +# remote-ip-header: x-forward-for +# uri-encoding: UTF-8 +# max-threads: 10 +# background-processor-delay: 30 +# basedir: ${user.home}/tomcat/ + undertow: + # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 + # 不要设置过大,如果过大,启动项目会报错:打开文件数过多 + io-threads: 4 + # 阻塞任务线程池, 当执行类似servlet请求阻塞IO操作, undertow会从这个线程池中取得线程 + # 它的值设置取决于系统线程执行任务的阻塞系数,默认值是IO线程数*8 + worker-threads: 64 + # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 + # 每块buffer的空间大小,越小的空间被利用越充分,不要设置太大,以免影响其他应用,合适即可 + buffer-size: 1024 + # 是否分配的直接内存(NIO直接分配的堆外内存) + direct-buffers: true spring: - cloud: - nacos: - discovery: - server-addr: 127.0.0.1:8848 banner: charset: UTF-8 http: diff --git a/generator-web/src/main/resources/static/version.json b/generator-web/src/main/resources/static/version.json new file mode 100644 index 00000000..0a0277c0 --- /dev/null +++ b/generator-web/src/main/resources/static/version.json @@ -0,0 +1 @@ +{"version": "20191128"} \ No newline at end of file diff --git a/generator-web/src/main/resources/templates/code-generator/jpa/entity.ftl b/generator-web/src/main/resources/templates/code-generator/jpa/entity.ftl index 7e56e15d..d2cb299c 100644 --- a/generator-web/src/main/resources/templates/code-generator/jpa/entity.ftl +++ b/generator-web/src/main/resources/templates/code-generator/jpa/entity.ftl @@ -1,8 +1,16 @@ -import java.io.Serializable; -import javax.persistence.*; +package ${packageName}.entity; + import lombok.Data; import java.util.Date; import java.util.List; +import java.io.Serializable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.GeneratedValue; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * ${classInfo.classComment} @@ -11,6 +19,7 @@ import java.util.List; @Entity @Data @Table(name="${classInfo.tableName}") +@ApiModel("${classInfo.classComment}") public class ${classInfo.className} implements Serializable { private static final long serialVersionUID = 1L; @@ -22,6 +31,8 @@ public class ${classInfo.className} implements Serializable { /** * ${fieldItem.fieldComment} */ + @ApiModelProperty("${fieldItem.fieldComment}") + @Column("${fieldItem.columnName}") private ${fieldItem.fieldClass} ${fieldItem.fieldName}; diff --git a/generator-web/src/main/resources/templates/index.ftl b/generator-web/src/main/resources/templates/index.ftl index 3433d28f..c7234e56 100644 --- a/generator-web/src/main/resources/templates/index.ftl +++ b/generator-web/src/main/resources/templates/index.ftl @@ -1,330 +1,353 @@ - - - - - SQL转Java JPA、MYBATIS实现类代码生成平台 - - - <#import "common/common-import.ftl" as netCommon> - <@netCommon.commonStyle /> - <@netCommon.commonScript /> - - - - - - - - -
-
-

Spring Boot Code Generator!

-

- √基于SpringBoot2+Freemarker的代码生成器,√以释放双手为目的,√支持mysql/oracle/pgsql三大数据库,
- √用DDL-SQL语句生成JPA/JdbcTemplate/Mybatis/MybatisPlus/BeetlSQL相关代码。
- 欢迎大家多多提交模板和交流想法,如果发现有SQL语句不能识别,请留言,同时欢迎大家提PR点击赞赏,谢谢! -

- -
-
-
- 作者名称 -
- -
- 返回封装 -
- -
- 包名路径 -
- -
-
-
- 数据类型 -
- -
- tinyint转换类型 -
- -
- 命名转换规则 -
- -
-
-

-
- -
- - -
- -
- - - -
- -
- - -
-
- - -
-
- - -
-
- -
-
- - <@netCommon.commonFooter /> - - + + + + + SQL转Java JPA、MYBATIS实现类代码生成平台 + + + <#import "common/common-import.ftl" as netCommon> + <@netCommon.commonStyle /> + <@netCommon.commonScript /> + + + + + + + + +
+
+

Spring Boot Code Generator!

+

+ √基于SpringBoot2+Freemarker的代码生成器,√以释放双手为目的,√支持mysql/oracle/pgsql三大数据库,
+ √用DDL-SQL语句生成JPA/JdbcTemplate/Mybatis/MybatisPlus/BeetlSQL相关代码。
+ 如果发现有SQL语句不能识别,请留言,同时欢迎大家提PR赞赏,谢谢!查看版本 +

+ +
+
+
+ 作者名称 +
+ +
+ 返回封装 +
+ +
+ 包名路径 +
+ +
+
+
+ 数据类型 +
+ +
+ tinyint转换类型 +
+ +
+ 命名转换规则 +
+ +
+
+

+
+ +
+ + +
+ +
+ + + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + <@netCommon.commonFooter /> + + diff --git a/pom.xml b/pom.xml index a4e4264a..951718af 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.softdev.system SpringBootCodeGenerator - 0.0.1-SNAPSHOT + 2.0 pom @@ -31,6 +31,18 @@ org.springframework.boot spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + org.springframework.boot + spring-boot-starter-undertow @@ -67,7 +79,7 @@ cn.hutool hutool-all - 4.6.1 + 5.0.6 @@ -134,7 +146,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.8.1 true javac @@ -156,13 +168,13 @@ org.apache.maven.plugins maven-resources-plugin - 3.0.1 + 3.1.0 true - + org.springframework.boot spring-boot-maven-plugin