diff --git a/generator-web/src/main/java/com/softdev/system/generator/GeneratorWebApplication.java b/generator-web/src/main/java/com/softdev/system/generator/GeneratorWebApplication.java index d009d5e..39c1e85 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/GeneratorWebApplication.java +++ b/generator-web/src/main/java/com/softdev/system/generator/GeneratorWebApplication.java @@ -6,7 +6,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class GeneratorWebApplication { - public static void main(String[] args) { - SpringApplication.run(GeneratorWebApplication.class,args); - } + + public static void main(String[] args) { + SpringApplication.run(GeneratorWebApplication.class, args); + } + } diff --git a/generator-web/src/main/java/com/softdev/system/generator/config/GlobalDefaultExceptionHandler.java b/generator-web/src/main/java/com/softdev/system/generator/config/GlobalDefaultExceptionHandler.java index a9e7be2..fbe0c3f 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/config/GlobalDefaultExceptionHandler.java +++ b/generator-web/src/main/java/com/softdev/system/generator/config/GlobalDefaultExceptionHandler.java @@ -1,20 +1,20 @@ -package com.softdev.system.generator.config; - -import com.softdev.system.generator.entity.ReturnT; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; - -import javax.servlet.http.HttpServletRequest; - -@ControllerAdvice -public class GlobalDefaultExceptionHandler { - - @ExceptionHandler(Exception.class) - @ResponseBody - public ReturnT defaultExceptionHandler(HttpServletRequest req,Exception e) { - e.printStackTrace(); - return ReturnT.ERROR(e.getMessage()); - } - -} +package com.softdev.system.generator.config; + +import com.softdev.system.generator.entity.ReturnT; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; + +@ControllerAdvice +public class GlobalDefaultExceptionHandler { + + @ExceptionHandler(Exception.class) + @ResponseBody + public ReturnT defaultExceptionHandler(HttpServletRequest req, Exception e) { + e.printStackTrace(); + return ReturnT.ERROR(e.getMessage()); + } + +} diff --git a/generator-web/src/main/java/com/softdev/system/generator/config/ServerConfig.java b/generator-web/src/main/java/com/softdev/system/generator/config/ServerConfig.java index 4a0ea1d..7bab405 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/config/ServerConfig.java +++ b/generator-web/src/main/java/com/softdev/system/generator/config/ServerConfig.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; + import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; diff --git a/generator-web/src/main/java/com/softdev/system/generator/config/WebMvcConfig.java b/generator-web/src/main/java/com/softdev/system/generator/config/WebMvcConfig.java index 642eea4..6129b2e 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/config/WebMvcConfig.java +++ b/generator-web/src/main/java/com/softdev/system/generator/config/WebMvcConfig.java @@ -1,49 +1,50 @@ -package com.softdev.system.generator.config; - -import com.alibaba.fastjson.support.config.FastJsonConfig; -import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; -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.WebMvcConfigurer; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -/** -* 2019-2-11 liutf WebMvcConfig 整合 cors 和 SpringMvc MessageConverter -*/ -@Configuration -public class WebMvcConfig implements WebMvcConfigurer { - -/* @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOrigins("*") - .allowedHeaders("x-requested-with") - .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE") - .maxAge(3600); - }*/ - - @Override - public void configureMessageConverters(List> converters) { - //FastJsonHttpMessageConverter - FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); - - List fastMediaTypes = new ArrayList<>(); - fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); - fastConverter.setSupportedMediaTypes(fastMediaTypes); - - FastJsonConfig fastJsonConfig = new FastJsonConfig(); - fastJsonConfig.setCharset(StandardCharsets.UTF_8); - fastConverter.setFastJsonConfig(fastJsonConfig); - - //StringHttpMessageConverter - StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(); - stringConverter.setDefaultCharset(StandardCharsets.UTF_8); - stringConverter.setSupportedMediaTypes(fastMediaTypes); - converters.add(stringConverter); - converters.add(fastConverter); - } -} \ No newline at end of file +package com.softdev.system.generator.config; + +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +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.WebMvcConfigurer; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +/** +* 2019-2-11 liutf WebMvcConfig 整合 cors 和 SpringMvc MessageConverter +*/ +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + /* @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedHeaders("x-requested-with") + .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE") + .maxAge(3600); + }*/ + + @Override + public void configureMessageConverters(List> converters) { + //FastJsonHttpMessageConverter + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + + List fastMediaTypes = new ArrayList<>(); + fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); + fastConverter.setSupportedMediaTypes(fastMediaTypes); + + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + fastJsonConfig.setCharset(StandardCharsets.UTF_8); + fastConverter.setFastJsonConfig(fastJsonConfig); + + //StringHttpMessageConverter + StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(); + stringConverter.setDefaultCharset(StandardCharsets.UTF_8); + stringConverter.setSupportedMediaTypes(fastMediaTypes); + converters.add(stringConverter); + converters.add(fastConverter); + } + +} 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 4a822f5..43e831a 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 @@ -18,6 +18,7 @@ import java.util.Map; /** * spring boot code generator + * * @author zhengk/moshow */ @Controller @@ -34,29 +35,37 @@ public class IndexController { @PostMapping("/genCode") @ResponseBody - public ReturnT codeGenerate(@RequestBody ParamInfo paramInfo ) throws Exception { + public ReturnT codeGenerate(@RequestBody ParamInfo paramInfo) throws Exception { - if (paramInfo.getTableSql().trim().length()<1) { + if (paramInfo.getTableSql().trim().length() < 1) { return ReturnT.ERROR("表结构信息不可为空"); } //1.Parse Table Structure 表结构解析 ClassInfo classInfo = null; - switch (paramInfo.getDataType()){ + switch (paramInfo.getDataType()) { //JSON模式:parse field from json string - case "json":classInfo = TableParseUtil.processJsonToClassInfo(paramInfo);break; + case "json": + classInfo = TableParseUtil.processJsonToClassInfo(paramInfo); + break; //INSERT SQL模式:parse field from insert sql - case "insert-sql":classInfo = TableParseUtil.processInsertSqlToClassInfo(paramInfo);break; + case "insert-sql": + classInfo = TableParseUtil.processInsertSqlToClassInfo(paramInfo); + break; //正则表达式模式(非完善版本):parse sql by regex - case "sql-regex":classInfo = TableParseUtil.processTableToClassInfoByRegex(paramInfo);break; + case "sql-regex": + classInfo = TableParseUtil.processTableToClassInfoByRegex(paramInfo); + break; //默认模式:default parse sql by java - default : classInfo = TableParseUtil.processTableIntoClassInfo(paramInfo);break; + default: + classInfo = TableParseUtil.processTableIntoClassInfo(paramInfo); + break; } //2.Set the params 设置表格参数 Map params = new HashMap(8); params.put("classInfo", classInfo); - params.put("tableName", classInfo==null?System.currentTimeMillis():classInfo.getTableName()); + params.put("tableName", classInfo == null ? System.currentTimeMillis() : classInfo.getTableName()); params.put("authorName", paramInfo.getAuthorName()); params.put("packageName", paramInfo.getPackageName()); params.put("returnUtil", paramInfo.getReturnUtil()); diff --git a/generator-web/src/main/java/com/softdev/system/generator/entity/ClassInfo.java b/generator-web/src/main/java/com/softdev/system/generator/entity/ClassInfo.java index 61ae3ff..cfecd96 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/entity/ClassInfo.java +++ b/generator-web/src/main/java/com/softdev/system/generator/entity/ClassInfo.java @@ -14,7 +14,7 @@ public class ClassInfo { private String tableName; private String className; - private String classComment; - private List fieldList; + private String classComment; + private List fieldList; -} \ No newline at end of file +} diff --git a/generator-web/src/main/java/com/softdev/system/generator/entity/ParamInfo.java b/generator-web/src/main/java/com/softdev/system/generator/entity/ParamInfo.java index 1de1805..459d17b 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/entity/ParamInfo.java +++ b/generator-web/src/main/java/com/softdev/system/generator/entity/ParamInfo.java @@ -1,26 +1,29 @@ -package com.softdev.system.generator.entity; - -import lombok.Data; - -/** - * Post data - ParamInfo - * @author zhengkai.blog.csdn.net - */ -@Data -public class ParamInfo { - private String tableSql; - private String authorName; - private String packageName; - private String returnUtil; - private String nameCaseType; - private String tinyintTransType; - private String dataType; - private boolean swagger; - - @Data - public static class NAME_CASE_TYPE{ - public static String CAMEL_CASE="CamelCase"; - public static String UNDER_SCORE_CASE="UnderScoreCase"; - public static String UPPER_UNDER_SCORE_CASE="UpperUnderScoreCase"; - } -} +package com.softdev.system.generator.entity; + +import lombok.Data; + +/** + * Post data - ParamInfo + * + * @author zhengkai.blog.csdn.net + */ +@Data +public class ParamInfo { + + private String tableSql; + private String authorName; + private String packageName; + private String returnUtil; + private String nameCaseType; + private String tinyintTransType; + private String dataType; + private boolean swagger; + + @Data + public static class NAME_CASE_TYPE { + public static String CAMEL_CASE = "CamelCase"; + public static String UNDER_SCORE_CASE = "UnderScoreCase"; + public static String UPPER_UNDER_SCORE_CASE = "UpperUnderScoreCase"; + } + +} diff --git a/generator-web/src/main/java/com/softdev/system/generator/entity/ReturnT.java b/generator-web/src/main/java/com/softdev/system/generator/entity/ReturnT.java index d516cc0..42499a8 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/entity/ReturnT.java +++ b/generator-web/src/main/java/com/softdev/system/generator/entity/ReturnT.java @@ -6,60 +6,73 @@ import java.io.Serializable; /** * common returnT:公共返回封装类 + * * @author zhengkai.blog.csdn.net */ @Data public class ReturnT implements Serializable { - public static final long serialVersionUID = 42L; - public static final int SUCCESS_CODE = 200; - public static final int FAIL_CODE = 500; - public static final int PAGE_CODE = 0; - public static final String OBJECT_NOT_FOUND = "找不到该对象"; - public static final String OPERATION_SUCCESS = "操作成功"; + public static final long serialVersionUID = 42L; - private int code; - private String msg; - private Object data; - private int count; + public static final int SUCCESS_CODE = 200; + public static final int FAIL_CODE = 500; + public static final int PAGE_CODE = 0; + public static final String OBJECT_NOT_FOUND = "找不到该对象"; + public static final String OPERATION_SUCCESS = "操作成功"; + + private int code; + private String msg; + private Object data; + private int count; + + public ReturnT(int code, String msg) { + this.code = code; + this.msg = msg; + } + + public ReturnT(int code, String msg, Object data) { + this.code = code; + this.msg = msg; + this.data = data; + } + + public ReturnT(Object data) { + this.code = SUCCESS_CODE; + this.data = data; + } + + public ReturnT(Object data, int count) { + this.code = PAGE_CODE; + this.data = data; + this.count = count; + } + + public static ReturnT PAGE(Object data, int count) { + return new ReturnT(data, count); + } + + public static ReturnT PAGE(Object data, long count) { + return new ReturnT(data, Integer.parseInt(count + "")); + } + + public static ReturnT SUCCESS() { + return new ReturnT(SUCCESS_CODE, OPERATION_SUCCESS); + } + + public static ReturnT SUCCESS(String msg) { + return new ReturnT(SUCCESS_CODE, msg); + } + + public static ReturnT SUCCESS(Object data) { + return new ReturnT(data); + } + + public static ReturnT ERROR(String msg) { + return new ReturnT(FAIL_CODE, msg); + } + + public static ReturnT ERROR() { + return new ReturnT(FAIL_CODE, OBJECT_NOT_FOUND); + } - public ReturnT(int code, String msg) { - this.code = code; - this.msg = msg; - } - public ReturnT(int code, String msg,Object data) { - this.code = code; - this.msg = msg; - this.data = data; - } - public ReturnT(Object data) { - this.code = SUCCESS_CODE; - this.data = data; - } - public ReturnT( Object data , int count ) { - this.code = PAGE_CODE; - this.data = data; - this.count = count; - } - public static ReturnT PAGE( Object data , int count){ - return new ReturnT(data,count); - } - public static ReturnT PAGE( Object data , long count){ - return new ReturnT(data,Integer.parseInt(count+"")); - } - public static ReturnT SUCCESS(){ - return new ReturnT(SUCCESS_CODE,OPERATION_SUCCESS); - } - public static ReturnT SUCCESS(String msg){ - return new ReturnT(SUCCESS_CODE,msg); - } - public static ReturnT SUCCESS(Object data){ - return new ReturnT(data); - } - public static ReturnT ERROR(String msg){ - return new ReturnT(FAIL_CODE,msg); - } - public static ReturnT ERROR(){ - return new ReturnT(FAIL_CODE,OBJECT_NOT_FOUND); - } } diff --git a/generator-web/src/main/java/com/softdev/system/generator/service/GeneratorService.java b/generator-web/src/main/java/com/softdev/system/generator/service/GeneratorService.java index 507196a..3026454 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/service/GeneratorService.java +++ b/generator-web/src/main/java/com/softdev/system/generator/service/GeneratorService.java @@ -1,17 +1,18 @@ -package com.softdev.system.generator.service; - -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 { - - public Map getResultByParams(Map params) throws IOException, TemplateException; - -} +package com.softdev.system.generator.service; + +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 { + + public Map getResultByParams(Map params) throws IOException, TemplateException; + +} diff --git a/generator-web/src/main/java/com/softdev/system/generator/service/GeneratorServiceImpl.java b/generator-web/src/main/java/com/softdev/system/generator/service/GeneratorServiceImpl.java index 233eb16..59862d4 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/service/GeneratorServiceImpl.java +++ b/generator-web/src/main/java/com/softdev/system/generator/service/GeneratorServiceImpl.java @@ -1,62 +1,68 @@ -package com.softdev.system.generator.service; - -import com.alibaba.fastjson.JSON; -import com.softdev.system.generator.entity.TemplateConfig; -import com.softdev.system.generator.util.FreemarkerUtil; -import freemarker.template.TemplateException; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * GeneratorService - * @author zhengkai.blog.csdn.net - */ -@Slf4j -@Service -public class GeneratorServiceImpl implements GeneratorService { - - @Autowired - private FreemarkerUtil freemarkerTool; - - String templateCpnfig=null; - /** - * 从项目中的JSON文件读取String - * @author zhengkai.blog.csdn.net - */ - public String getTemplateConfig() throws IOException { - templateCpnfig=null; - if(templateCpnfig!=null){ - }else{ - 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 getResultByParams(Map params) throws IOException, TemplateException { - Map result = new LinkedHashMap<>(32); - result.put("tableName",params.get("tableName")+""); - List templateConfigList = JSON.parseArray(getTemplateConfig(),TemplateConfig.class); - for (TemplateConfig item:templateConfigList){ - result.put(item.getName(), freemarkerTool.processString(item.getGroup()+"/"+item.getName()+".ftl", params)); - } - return result; - } -} +package com.softdev.system.generator.service; + +import com.alibaba.fastjson.JSON; +import com.softdev.system.generator.entity.TemplateConfig; +import com.softdev.system.generator.util.FreemarkerUtil; +import freemarker.template.TemplateException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * GeneratorService + * + * @author zhengkai.blog.csdn.net + */ +@Slf4j +@Service +public class GeneratorServiceImpl implements GeneratorService { + + @Autowired + private FreemarkerUtil freemarkerTool; + + String templateCpnfig = null; + + /** + * 从项目中的JSON文件读取String + * + * @author zhengkai.blog.csdn.net + */ + public String getTemplateConfig() throws IOException { + templateCpnfig = null; + if (templateCpnfig != null) { + } else { + 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 getResultByParams(Map params) throws IOException, TemplateException { + Map result = new LinkedHashMap<>(32); + result.put("tableName", params.get("tableName") + ""); + List templateConfigList = JSON.parseArray(getTemplateConfig(), TemplateConfig.class); + for (TemplateConfig item : templateConfigList) { + result.put(item.getName(), freemarkerTool.processString(item.getGroup() + "/" + item.getName() + ".ftl", params)); + } + return result; + } + +} diff --git a/generator-web/src/main/java/com/softdev/system/generator/util/CodeGenerateException.java b/generator-web/src/main/java/com/softdev/system/generator/util/CodeGenerateException.java index 3afaf5a..4fdf82b 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/util/CodeGenerateException.java +++ b/generator-web/src/main/java/com/softdev/system/generator/util/CodeGenerateException.java @@ -4,7 +4,9 @@ package com.softdev.system.generator.util; * @author xuxueli 2018-05-02 21:10:28 */ public class CodeGenerateException extends RuntimeException { + private static final long serialVersionUID = 42L; + public CodeGenerateException() { super(); } @@ -22,8 +24,9 @@ public class CodeGenerateException extends RuntimeException { } public CodeGenerateException(String message, Throwable cause, - boolean enableSuppression, - boolean writableStackTrace) { + boolean enableSuppression, + boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } + } diff --git a/generator-web/src/main/java/com/softdev/system/generator/util/FreemarkerUtil.java b/generator-web/src/main/java/com/softdev/system/generator/util/FreemarkerUtil.java index cb3a2bf..ff28e74 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/util/FreemarkerUtil.java +++ b/generator-web/src/main/java/com/softdev/system/generator/util/FreemarkerUtil.java @@ -23,23 +23,23 @@ import java.util.Map; @Component public class FreemarkerUtil { - @Autowired private Configuration configuration; /** * 传入需要转义的字符串进行转义 * 20200503 zhengkai.blog.csdn.net - * */ - public static String escapeString(String originStr){ - return originStr.replaceAll("井","\\#").replaceAll("¥","\\$"); + */ + public static String escapeString(String originStr) { + return originStr.replaceAll("井", "\\#").replaceAll("¥", "\\$"); } /** * freemarker config */ private static Configuration freemarkerConfig = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); - static{ + + static { try { //2020-06-21 zhengkai 修复path问题导致jar无法运行而本地项目可以运行的bug freemarkerConfig.setClassForTemplateLoading(FreemarkerUtil.class, "/templates/code-generator"); @@ -89,5 +89,4 @@ public class FreemarkerUtil { return htmlText; } - } diff --git a/generator-web/src/main/java/com/softdev/system/generator/util/StringUtils.java b/generator-web/src/main/java/com/softdev/system/generator/util/StringUtils.java index a2c5182..9b554ff 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/util/StringUtils.java +++ b/generator-web/src/main/java/com/softdev/system/generator/util/StringUtils.java @@ -25,7 +25,7 @@ public class StringUtils { */ public static String lowerCaseFirst(String str) { //2019-2-10 解决StringUtils.lowerCaseFirst潜在的NPE异常@liutf - return (str!=null&&str.length()>1)?str.substring(0, 1).toLowerCase() + str.substring(1):""; + return (str != null && str.length() > 1) ? str.substring(0, 1).toLowerCase() + str.substring(1) : ""; } /** @@ -58,4 +58,5 @@ public class StringUtils { public static void main(String[] args) { } + } 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 4d8ddf7..dc8e820 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,472 +1,481 @@ -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.Arrays; -import java.util.Date; -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 { - - /** - * 解析DDL SQL生成类信息 - * @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 incorrect.表结构不正确。"); - } - - //新增处理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, - //2020-05-25 优化表备注的获取逻辑 - if (tableSql.contains("comment=")||tableSql.contains("comment on table")) { - String classCommentTmp = (tableSql.contains("comment="))? - tableSql.substring(tableSql.lastIndexOf("comment=")+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("`")); - classComment = classCommentTmp; - }else{ - //非常规的没法分析 - classComment = className; - } - }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") 类似这种的,可在前后适当加一些空格之类的加以区分,否则当我的字段包含这些字符的时候,产生类型判断问题。 - //2020-05-03 MOSHOW.K.ZHENG 优化对所有类型的处理 - if (columnLine.contains(" tinyint") ) { - //20191115 MOSHOW.K.ZHENG 支持对tinyint的特殊处理 - fieldClass=tinyintTransType; - } - else 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 { - 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")) { - //20200518 zhengkai 修复包含comment关键字的问题 - 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("`")); - } - //解决最后一句是评论,无主键且连着)的问题: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; - } - /** - * 解析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; - } - - public static ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo) { - // field List - List fieldList = new ArrayList(); - //return classInfo - ClassInfo codeJavaInfo = new ClassInfo(); - - //get origin sql - String fieldSqlStr = paramInfo.getTableSql().toLowerCase().trim(); - fieldSqlStr=fieldSqlStr.replaceAll(" "," ").replaceAll("\\\\n`","") - .replaceAll("\\+","").replaceAll("``","`").replaceAll("\\\\",""); - String valueStr = fieldSqlStr.substring(fieldSqlStr.lastIndexOf("values")+6).replaceAll(" ","").replaceAll("\\(","").replaceAll("\\)",""); - //get the string between insert into and values - fieldSqlStr=fieldSqlStr.substring(0,fieldSqlStr.lastIndexOf("values")); - - System.out.println(fieldSqlStr); - - String insertSqlPattenStr = "insert into (?.*) \\((?.*)\\)"; - //String DDL_PATTEN_STR="\\s*create\\s+table\\s+(?\\S+)[^\\(]*\\((?[\\s\\S]+)\\)[^\\)]+?(comment\\s*(=|on\\s+table)\\s*'(?.*?)'\\s*;?)?$"; - - Matcher matcher1 = Pattern.compile(insertSqlPattenStr).matcher(fieldSqlStr); - while(matcher1.find()){ - - String tableName = matcher1.group("tableName"); - //System.out.println("tableName:"+tableName); - codeJavaInfo.setClassName(tableName); - codeJavaInfo.setTableName(tableName); - - String columnsSQL = matcher1.group("columnsSQL"); - //System.out.println("columnsSQL:"+columnsSQL); - - List valueList = new ArrayList<>(); - //add values as comment - Arrays.stream(valueStr.split(",")).forEach(column->{ - valueList.add(column); - }); - AtomicInteger n= new AtomicInteger(0); - //add column to fleldList - Arrays.stream(columnsSQL.replaceAll(" ", "").split(",")).forEach(column->{ - FieldInfo fieldInfo2 = new FieldInfo(); - fieldInfo2.setFieldName(column); - fieldInfo2.setColumnName(column); - fieldInfo2.setFieldClass(String.class.getSimpleName()); - if(n.get() 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") 类似这种的,可在前后适当加一些空格之类的加以区分,否则当我的字段包含这些字符的时候,产生类型判断问题。 + //2020-05-03 MOSHOW.K.ZHENG 优化对所有类型的处理 + if (columnLine.contains(" tinyint")) { + //20191115 MOSHOW.K.ZHENG 支持对tinyint的特殊处理 + fieldClass = tinyintTransType; + } else 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 { + 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")) { + //20200518 zhengkai 修复包含comment关键字的问题 + 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("`")); + } + //解决最后一句是评论,无主键且连着)的问题: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; + } + + /** + * 解析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 + * + * @param paramInfo + * @return + * @author https://github.com/ydq + */ + 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; + } + + public static ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo) { + // field List + List fieldList = new ArrayList(); + //return classInfo + ClassInfo codeJavaInfo = new ClassInfo(); + + //get origin sql + String fieldSqlStr = paramInfo.getTableSql().toLowerCase().trim(); + fieldSqlStr = fieldSqlStr.replaceAll(" ", " ").replaceAll("\\\\n`", "") + .replaceAll("\\+", "").replaceAll("``", "`").replaceAll("\\\\", ""); + String valueStr = fieldSqlStr.substring(fieldSqlStr.lastIndexOf("values") + 6).replaceAll(" ", "").replaceAll("\\(", "").replaceAll("\\)", ""); + //get the string between insert into and values + fieldSqlStr = fieldSqlStr.substring(0, fieldSqlStr.lastIndexOf("values")); + + System.out.println(fieldSqlStr); + + String insertSqlPattenStr = "insert into (?.*) \\((?.*)\\)"; + //String DDL_PATTEN_STR="\\s*create\\s+table\\s+(?\\S+)[^\\(]*\\((?[\\s\\S]+)\\)[^\\)]+?(comment\\s*(=|on\\s+table)\\s*'(?.*?)'\\s*;?)?$"; + + Matcher matcher1 = Pattern.compile(insertSqlPattenStr).matcher(fieldSqlStr); + while (matcher1.find()) { + + String tableName = matcher1.group("tableName"); + //System.out.println("tableName:"+tableName); + codeJavaInfo.setClassName(tableName); + codeJavaInfo.setTableName(tableName); + + String columnsSQL = matcher1.group("columnsSQL"); + //System.out.println("columnsSQL:"+columnsSQL); + + List valueList = new ArrayList<>(); + //add values as comment + Arrays.stream(valueStr.split(",")).forEach(column -> { + valueList.add(column); + }); + AtomicInteger n = new AtomicInteger(0); + //add column to fleldList + Arrays.stream(columnsSQL.replaceAll(" ", "").split(",")).forEach(column -> { + FieldInfo fieldInfo2 = new FieldInfo(); + fieldInfo2.setFieldName(column); + fieldInfo2.setColumnName(column); + fieldInfo2.setFieldClass(String.class.getSimpleName()); + if (n.get() < valueList.size()) { + fieldInfo2.setFieldComment(column + " , eg." + valueList.get(n.get())); + } + fieldList.add(fieldInfo2); + n.getAndIncrement(); + }); + + } + if (fieldList.size() < 1) { + throw new CodeGenerateException("INSERT SQL解析失败"); + } + codeJavaInfo.setFieldList(fieldList); + return codeJavaInfo; + } + +}