diff --git a/README.md b/README.md index 6d57346..13db9f9 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,7 @@ - 感谢`卡卡`部署在[BEJSON](https://java.bejson.com/generator)上,目前是BeJSON专供的`金牌工具`
- 感谢`jully.top`部署的副本 [https://jully.top/generator/](https://jully.top/generator/)。
-- 感谢`bytecdntp`字节跳动CDN提供稳定、快速、免费的静态文件CDN加速服务(在线版本) -- Thanks `JetBrains` for providing us the `Licenses for Open Source Development` ,[Get free access to all JetBrains tools for developing your open source project!](https://www.jetbrains.com/community/opensource/#support) .
+- 感谢`staticfile`CDN提供稳定、快速、免费的静态文件CDN加速服务(在线版本) | 访问地址 | http://localhost:1234/generator | |:-----------------------|:--------------------------------------------------------------| @@ -77,7 +76,7 @@ # Update Logs | 更新日期 | 更新内容 | |:-----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 2025.09.13 | 修复CDN问题,切换为staticfile.org | +| 2025.09.13 | Create SQL by JSqlParser Engine升级
更新SpringBoot等类库版本,修复漏洞
修复CDN问题,切换为staticfile.org | | 2025.03.31 | 优化说明 | | 2025.03.16 | NewUI V2前端优化:
移除不必要内容,优化Local和CDN静态文件引入。

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

JPA模板优化(感谢@PenroseYang的反馈):
修复不开启Lombok情况下Set/Get方法生成问题;
修复importDdate判断为true后没有引入日期类的问题
| | 2024.12.29 | 优化前端加载速度,优化输出代码着色,CDN改字节跳动静态资源公共库。
| 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 3797d68..9f9420a 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 @@ -32,16 +32,16 @@ public class WebMvcConfig implements WebMvcConfigurer { public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/"); } - @Bean - public FilterRegistrationBean xssFilterRegistration() { - FilterRegistrationBean registration = new FilterRegistrationBean(); - registration.setDispatcherTypes(DispatcherType.REQUEST); - registration.setFilter(new XssFilter()); - registration.addUrlPatterns("/*"); - registration.setName("xssFilter"); - registration.setOrder(Integer.MAX_VALUE); - return registration; - } +// @Bean +// public FilterRegistrationBean xssFilterRegistration() { +// FilterRegistrationBean registration = new FilterRegistrationBean(); +// registration.setDispatcherTypes(DispatcherType.REQUEST); +// registration.setFilter(new XssFilter()); +// registration.addUrlPatterns("/*"); +// registration.setName("xssFilter"); +// registration.setOrder(Integer.MAX_VALUE); +// return registration; +// } // @Override // public void configureMessageConverters(List> converters) { @@ -74,8 +74,20 @@ public class WebMvcConfig implements WebMvcConfigurer { //自定义配置... FastJsonConfig config = new FastJsonConfig(); config.setDateFormat("yyyy-MM-dd HH:mm:ss"); - config.setReaderFeatures(JSONReader.Feature.FieldBased, JSONReader.Feature.SupportArrayToBean); - config.setWriterFeatures(JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.PrettyFormat); + + // 添加更多解析特性以提高容错性 + config.setReaderFeatures( + JSONReader.Feature.FieldBased, + JSONReader.Feature.SupportArrayToBean, +// JSONReader.Feature.IgnoreNoneFieldGetter, + JSONReader.Feature.InitStringFieldAsEmpty + ); + + config.setWriterFeatures( + JSONWriter.Feature.WriteMapNullValue, + JSONWriter.Feature.PrettyFormat + ); + converter.setFastJsonConfig(config); converter.setDefaultCharset(StandardCharsets.UTF_8); converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON)); diff --git a/generator-web/src/main/java/com/softdev/system/generator/config/XssFilter.java b/generator-web/src/main/java/com/softdev/system/generator/config/XssFilter.java deleted file mode 100644 index 5689832..0000000 --- a/generator-web/src/main/java/com/softdev/system/generator/config/XssFilter.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.softdev.system.generator.config; - -import jakarta.servlet.*; -import jakarta.servlet.http.HttpServletRequest; - -import java.io.IOException; - -/** - * XSS过滤 - * - * @author Mark sunlightcs@gmail.com - */ -public class XssFilter implements Filter { - - @Override - public void init(FilterConfig config) throws ServletException { - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - - XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest)request); - chain.doFilter(xssRequest, response); - } - - @Override - public void destroy() { - } - -} \ No newline at end of file diff --git a/generator-web/src/main/java/com/softdev/system/generator/config/XssHttpServletRequestWrapper.java b/generator-web/src/main/java/com/softdev/system/generator/config/XssHttpServletRequestWrapper.java deleted file mode 100644 index 9cbe5a3..0000000 --- a/generator-web/src/main/java/com/softdev/system/generator/config/XssHttpServletRequestWrapper.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.softdev.system.generator.config; - -import jakarta.servlet.ReadListener; -import jakarta.servlet.ServletInputStream; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletRequestWrapper; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * XSS过滤处理 - * - * @author Mark sunlightcs@gmail.com - */ -public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { - /** - * 没被包装过的HttpServletRequest(特殊场景,需要自己过滤) - */ - HttpServletRequest orgRequest; - /** - * html过滤 - */ - private final static HTMLFilter htmlFilter = new HTMLFilter(); - - public XssHttpServletRequestWrapper(HttpServletRequest request) { - super(request); - orgRequest = request; - } - - @Override - public ServletInputStream getInputStream() throws IOException { - //非json类型,直接返回 - if(!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))){ - return super.getInputStream(); - } - - //为空,直接返回 - String json = IOUtils.toString(super.getInputStream(), "utf-8"); - if (StringUtils.isBlank(json)) { - return super.getInputStream(); - } - - //xss过滤 - json = xssEncode(json); - final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8")); - return new ServletInputStream() { - @Override - public boolean isFinished() { - return true; - } - - @Override - public boolean isReady() { - return true; - } - - @Override - public void setReadListener(ReadListener readListener) { - } - - @Override - public int read() throws IOException { - return bis.read(); - } - }; - } - - @Override - public String getParameter(String name) { - String value = super.getParameter(xssEncode(name)); - if (StringUtils.isNotBlank(value)) { - value = xssEncode(value); - } - return value; - } - - @Override - public String[] getParameterValues(String name) { - String[] parameters = super.getParameterValues(name); - if (parameters == null || parameters.length == 0) { - return null; - } - - for (int i = 0; i < parameters.length; i++) { - parameters[i] = xssEncode(parameters[i]); - } - return parameters; - } - - @Override - public Map getParameterMap() { - Map map = new LinkedHashMap<>(); - Map parameters = super.getParameterMap(); - for (String key : parameters.keySet()) { - String[] values = parameters.get(key); - for (int i = 0; i < values.length; i++) { - values[i] = xssEncode(values[i]); - } - map.put(key, values); - } - return map; - } - - @Override - public String getHeader(String name) { - String value = super.getHeader(xssEncode(name)); - if (StringUtils.isNotBlank(value)) { - value = xssEncode(value); - } - return value; - } - - private String xssEncode(String input) { - return htmlFilter.filter(input); - } - - /** - * 获取最原始的request - */ - public HttpServletRequest getOrgRequest() { - return orgRequest; - } - - /** - * 获取最原始的request - */ - public static HttpServletRequest getOrgRequest(HttpServletRequest request) { - if (request instanceof XssHttpServletRequestWrapper) { - return ((XssHttpServletRequestWrapper) request).getOrgRequest(); - } - - return request; - } - -} diff --git a/generator-web/src/main/java/com/softdev/system/generator/controller/GeneratorController.java b/generator-web/src/main/java/com/softdev/system/generator/controller/GeneratorController.java index c0ab73d..caa967d 100644 --- a/generator-web/src/main/java/com/softdev/system/generator/controller/GeneratorController.java +++ b/generator-web/src/main/java/com/softdev/system/generator/controller/GeneratorController.java @@ -87,6 +87,10 @@ public class GeneratorController { //SelectSqlBySQLPraser模式:parse select sql by JSqlParser classInfo = generatorService.generateSelectSqlBySQLPraser(paramInfo); break; + case "create-sql": + //SelectSqlBySQLPraser模式:parse select sql by JSqlParser + classInfo = generatorService.generateCreateSqlBySQLPraser(paramInfo); + break; default: //默认模式:parse DDL table structure from sql classInfo = generatorService.processTableIntoClassInfo(paramInfo); 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 b58e08d..5042eb3 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 @@ -25,6 +25,7 @@ public interface GeneratorService { * @return */ ClassInfo generateSelectSqlBySQLPraser(ParamInfo paramInfo) throws Exception; + ClassInfo generateCreateSqlBySQLPraser(ParamInfo paramInfo) throws Exception; /** * 解析DDL-SQL生成类信息 * @auther: zhengkai.blog.csdn.net 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 b5b9194..b4658c4 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 @@ -7,23 +7,29 @@ import com.softdev.system.generator.entity.*; import com.softdev.system.generator.util.*; import freemarker.template.TemplateException; import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.create.table.ColumnDefinition; +import net.sf.jsqlparser.statement.create.table.CreateTable; import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectItem; +import net.sf.jsqlparser.util.TablesNamesFinder; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static net.sf.jsqlparser.parser.feature.Feature.createTable; + /** * GeneratorService * @@ -81,12 +87,31 @@ public class GeneratorServiceImpl implements GeneratorService { @Override public ClassInfo generateSelectSqlBySQLPraser(ParamInfo paramInfo) throws Exception { ClassInfo classInfo = new ClassInfo(); - PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(paramInfo.getTableSql()); - List> columnNameList = select.getSelectItems(); - log.info("tableName:{}", select.getFromItem().toString()); + Statement statement = CCJSqlParserUtil.parse(paramInfo.getTableSql()); + CCJSqlParserManager parserManager = new CCJSqlParserManager(); + statement = parserManager.parse(new StringReader(paramInfo.getTableSql())); + TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); // 创建表名发现者对象 + List tableNameList = tablesNamesFinder.getTableList(statement); // 获取到表名列表 + //一般这里应该只解析到一个表名,除非多个表名,取第一个 + if (!CollectionUtils.isEmpty(tableNameList)) { + String tableName = tableNameList.get(0).trim(); + classInfo.setTableName(tableName); + String className = StringUtilsPlus.upperCaseFirst(StringUtilsPlus.underlineToCamelCase(tableName)); + if (className.contains("_")) { + className = className.replaceAll("_", ""); + } + classInfo.setClassName(className); + classInfo.setClassComment(paramInfo.getTableSql()); + } + //解析查询元素 + Select select = null; + select = (Select) CCJSqlParserUtil.parse(paramInfo.getTableSql()); + PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); + List> selectItems = plainSelect.getSelectItems(); + // field List List fieldList = new ArrayList(); - columnNameList.forEach(t->{ + selectItems.forEach(t->{ FieldInfo fieldInfo = new FieldInfo(); String fieldName = ((Column)t.getExpression()).getColumnName(); String aliasName = t.getAlias() != null ? t.getAlias().getName() : ((Column)t.getExpression()).getColumnName(); @@ -119,18 +144,79 @@ public class GeneratorServiceImpl implements GeneratorService { fieldList.add(fieldInfo); }); classInfo.setFieldList(fieldList); - String tableName = select.getFromItem().toString(); - classInfo.setTableName(tableName); - //如果表名有空格,取空格前的第一个单词作为类名 - if(tableName.indexOf(" ")>0){ - classInfo.setClassName(StringUtilsPlus.upperCaseFirst(StringUtilsPlus.underlineToCamelCase(tableName.substring(0,tableName.indexOf(" "))))); - }else{ - classInfo.setClassName(StringUtilsPlus.upperCaseFirst(StringUtilsPlus.underlineToCamelCase(tableName))); - } log.info("classInfo:{}", JSON.toJSONString(classInfo)); return classInfo; } + /** + * 根据SQL解析器解析表结构 + * @author zhengkai.blog.csdn.net + * @param paramInfo + * @return + * @throws Exception + */ + @Override + public ClassInfo generateCreateSqlBySQLPraser(ParamInfo paramInfo) throws Exception { + ClassInfo classInfo = new ClassInfo(); + Statement statement = CCJSqlParserUtil.parse(paramInfo.getTableSql()); + CCJSqlParserManager parserManager = new CCJSqlParserManager(); + statement = parserManager.parse(new StringReader(paramInfo.getTableSql())); + TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); // 创建表名发现者对象 + List tableNameList = tablesNamesFinder.getTableList(statement); // 获取到表名列表 + //一般这里应该只解析到一个表名,除非多个表名,取第一个 + if (!CollectionUtils.isEmpty(tableNameList)) { + String tableName = tableNameList.get(0).trim(); + classInfo.setTableName(tableName); + String className = StringUtilsPlus.upperCaseFirst(StringUtilsPlus.underlineToCamelCase(tableName)); + if (className.contains("_")) { + className = className.replaceAll("_", ""); + } + classInfo.setClassName(className); + classInfo.setClassComment(paramInfo.getTableSql()); + } + //解析查询元素 + Select select = null; + select = (Select) CCJSqlParserUtil.parse(paramInfo.getTableSql()); + PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); + List> selectItems = plainSelect.getSelectItems(); + // field List + List fieldList = new ArrayList(); + selectItems.forEach(t->{ + FieldInfo fieldInfo = new FieldInfo(); + String fieldName = ((Column)t.getExpression()).getColumnName(); + String aliasName = t.getAlias() != null ? t.getAlias().getName() : ((Column)t.getExpression()).getColumnName(); + //存储原始字段名 + fieldInfo.setFieldComment(aliasName);fieldInfo.setColumnName(aliasName); + //处理字段名是t.xxx的情况 + fieldName=fieldName.contains(".")?fieldName.substring(fieldName.indexOf(".")+1):fieldName; + //转换前 + fieldInfo.setColumnName(fieldName); + switch ((String) paramInfo.getOptions().get("nameCaseType")) { + case ParamInfo.NAME_CASE_TYPE.CAMEL_CASE: + // 2024-1-27 L&J 适配任意(maybe)原始风格转小写驼峰 + fieldName = StringUtilsPlus.toLowerCamel(aliasName); + break; + case ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE: + fieldName = StringUtilsPlus.toUnderline(aliasName, false); + break; + case ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE: + fieldName = StringUtilsPlus.toUnderline(aliasName.toUpperCase(), true); + break; + default: + fieldName = aliasName; + break; + } + //转换后 + fieldInfo.setFieldName(fieldName); + + //无法推测类型,所有都set为String + fieldInfo.setFieldClass("String"); + fieldList.add(fieldInfo); + }); + classInfo.setFieldList(fieldList); + log.info("classInfo:{}", JSON.toJSONString(classInfo)); + return classInfo; + } /** * 解析DDL SQL生成类信息(默认模式|核心模式) * diff --git a/generator-web/src/main/resources/application.yml b/generator-web/src/main/resources/application.yml index caf4dfc..6857c9d 100644 --- a/generator-web/src/main/resources/application.yml +++ b/generator-web/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - active: dev \ No newline at end of file + active: bejson \ No newline at end of file diff --git a/generator-web/src/main/resources/templates/newui2.html b/generator-web/src/main/resources/templates/newui2.html index 141215c..be1da78 100644 --- a/generator-web/src/main/resources/templates/newui2.html +++ b/generator-web/src/main/resources/templates/newui2.html @@ -100,6 +100,15 @@
+ + + + + + + + + @@ -115,14 +124,6 @@ - - - - - - - -