Skip to content

Commit 068472d

Browse files
authored
Merge pull request #144 from Nisus-Liu/bugfix/143-sqlcamel
fix: 驼峰列名转命名风格错误问题 #143
2 parents 17d668a + e008e4d commit 068472d

File tree

6 files changed

+265
-28
lines changed

6 files changed

+265
-28
lines changed

generator-web/pom.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
<properties>
1818
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1919
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20-
<java.version>1.8</java.version>
2120
</properties>
2221

2322
<dependencies>
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package com.softdev.system.generator.entity;
2+
3+
import lombok.AllArgsConstructor;
4+
5+
/**
6+
* String 包装类
7+
* <p>
8+
* 忽略大小写
9+
**考虑增加这个类是, 如果在 StringUtils 中加工具方法, 使用起来代码非常冗长且不方便
10+
* @author Nisus
11+
* @see String
12+
*/
13+
@AllArgsConstructor
14+
public class NonCaseString implements CharSequence {
15+
private String value;
16+
17+
public static NonCaseString of(String str) {
18+
assert str != null;
19+
return new NonCaseString(str);
20+
}
21+
22+
23+
/**
24+
* {@link String#indexOf(String)} 增强, 忽略大小写
25+
*/
26+
public int indexOf(String m) {
27+
String text = this.value;
28+
if (text == null || m == null || text.length() < m.length()) {
29+
return -1;
30+
}
31+
return text.toLowerCase().indexOf(m.toLowerCase());
32+
}
33+
34+
/**
35+
* {@link String#lastIndexOf(String)} 增强, 忽略大小写
36+
*/
37+
public int lastIndexOf(String m) {
38+
String text = this.value;
39+
if (text == null || m == null || text.length() < m.length()) {
40+
return -1;
41+
}
42+
return text.toLowerCase().lastIndexOf(m.toLowerCase());
43+
}
44+
45+
/**
46+
* 是否包含, 大小写不敏感
47+
* <pre
48+
* "abcxyz" 包含 "abc" => true
49+
* "abcxyz" 包含 "ABC" => true
50+
* "abcxyz" 包含 "aBC" => true
51+
* </pre>
52+
*
53+
* @param m 被包含字符串
54+
*/
55+
public boolean contains(String m) {
56+
String text = this.value;
57+
if (text.length() < m.length()) {
58+
return false;
59+
}
60+
return text.toLowerCase().contains(m.toLowerCase());
61+
}
62+
63+
/**
64+
* 任意一个包含返回true
65+
* <pre>
66+
* containsAny("abcdef", "a", "b)
67+
* 等价
68+
* "abcdef".contains("a") || "abcdef".contains("b")
69+
* </pre>
70+
*
71+
* @param matchers 多个要判断的被包含项
72+
*/
73+
public boolean containsAny(String... matchers) {
74+
for (String matcher : matchers) {
75+
if (contains(matcher)) {
76+
return true;
77+
}
78+
}
79+
return false;
80+
}
81+
82+
/**
83+
* 所有都包含才返回true
84+
*
85+
* @param matchers 多个要判断的被包含项
86+
*/
87+
public boolean containsAllIgnoreCase(String... matchers) {
88+
for (String matcher : matchers) {
89+
if (contains(matcher) == false) {
90+
return false;
91+
}
92+
}
93+
return true;
94+
}
95+
96+
public NonCaseString trim() {
97+
return NonCaseString.of(this.value.trim());
98+
}
99+
100+
public NonCaseString replace(char oldChar, char newChar) {
101+
return NonCaseString.of(this.value.replace(oldChar, newChar));
102+
}
103+
104+
public NonCaseString replaceAll(String regex, String replacement) {
105+
return NonCaseString.of(this.value.replaceAll(regex, replacement));
106+
}
107+
108+
public NonCaseString substring(int beginIndex) {
109+
return NonCaseString.of(this.value.substring(beginIndex));
110+
}
111+
112+
public NonCaseString substring(int beginIndex, int endIndex) {
113+
return NonCaseString.of(this.value.substring(beginIndex, endIndex));
114+
}
115+
116+
public boolean isNotEmpty() {
117+
return !this.value.isEmpty();
118+
}
119+
120+
@Override
121+
public int length() {
122+
return this.value.length();
123+
}
124+
125+
@Override
126+
public char charAt(int index) {
127+
return this.value.charAt(index);
128+
}
129+
130+
131+
@Override
132+
public CharSequence subSequence(int start, int end) {
133+
return this.value.subSequence(start, end);
134+
}
135+
136+
public String[] split(String regex) {
137+
return this.value.split(regex);
138+
}
139+
140+
141+
/**
142+
* @return 原始字符串
143+
*/
144+
public String get() {
145+
return this.value;
146+
}
147+
148+
@Override
149+
public String toString() {
150+
return this.value;
151+
}
152+
}

generator-web/src/main/java/com/softdev/system/generator/util/StringUtils.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public static String underlineToCamelCase(String underscoreName) {
4040
boolean flag = false;
4141
for (int i = 0; i < underscoreName.length(); i++) {
4242
char ch = underscoreName.charAt(i);
43-
if ("_".charAt(0) == ch) {
43+
if ('_' == ch) {
4444
flag = true;
4545
} else {
4646
if (flag) {
@@ -54,6 +54,42 @@ public static String underlineToCamelCase(String underscoreName) {
5454
}
5555
return result.toString();
5656
}
57+
58+
/**
59+
* 转 user_name 风格
60+
*
61+
* 不管原始是什么风格
62+
*/
63+
public static String toUnderline(String str, boolean upperCase) {
64+
if (str == null || str.trim().isEmpty()) {
65+
return str;
66+
}
67+
68+
StringBuilder result = new StringBuilder();
69+
boolean preIsUnderscore = false;
70+
for (int i = 0; i < str.length(); i++) {
71+
char ch = str.charAt(i);
72+
if (ch == '_') {
73+
preIsUnderscore = true;
74+
} else if (ch == '-') {
75+
ch = '_';
76+
preIsUnderscore = true; // -A -> _a
77+
} else if (ch >= 'A' && ch <= 'Z') {
78+
// A -> _a
79+
if (!preIsUnderscore && i > 0) { // _A -> _a
80+
result.append("_");
81+
}
82+
preIsUnderscore = false;
83+
} else {
84+
preIsUnderscore = false;
85+
}
86+
result.append(upperCase ? Character.toUpperCase(ch) : Character.toLowerCase(ch));
87+
}
88+
89+
return result.toString();
90+
}
91+
92+
5793
public static boolean isNotNull(String str){
5894
return org.apache.commons.lang3.StringUtils.isNotEmpty(str);
5995
}

generator-web/src/main/java/com/softdev/system/generator/util/TableParseUtil.java

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
package com.softdev.system.generator.util;
22

3-
import com.softdev.system.generator.util.mysqlJavaTypeUtil;
43
import com.alibaba.fastjson.JSON;
54
import com.alibaba.fastjson.JSONArray;
65
import com.alibaba.fastjson.JSONObject;
76
import com.softdev.system.generator.entity.ClassInfo;
87
import com.softdev.system.generator.entity.FieldInfo;
8+
import com.softdev.system.generator.entity.NonCaseString;
99
import com.softdev.system.generator.entity.ParamInfo;
1010

1111
import java.io.IOException;
12-
import java.math.BigDecimal;
1312
import java.util.ArrayList;
1413
import java.util.Arrays;
15-
import java.util.Date;
1614
import java.util.List;
1715
import java.util.concurrent.atomic.AtomicInteger;
1816
import java.util.regex.Matcher;
@@ -34,23 +32,28 @@ public class TableParseUtil {
3432
public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
3533
throws IOException {
3634
//process the param
37-
String tableSql = paramInfo.getTableSql();
35+
NonCaseString tableSql = NonCaseString.of(paramInfo.getTableSql());
3836
String nameCaseType = MapUtil.getString(paramInfo.getOptions(),"nameCaseType");
3937
Boolean isPackageType = MapUtil.getBoolean(paramInfo.getOptions(),"isPackageType");
4038

4139
if (tableSql == null || tableSql.trim().length() == 0) {
4240
throw new CodeGenerateException("Table structure can not be empty. 表结构不能为空。");
4341
}
4442
//deal with special character
45-
tableSql = tableSql.trim().replaceAll("'", "`").replaceAll("\"", "`").replaceAll(",", ",").toLowerCase();
43+
tableSql = tableSql.trim()
44+
.replaceAll("'", "`")
45+
.replaceAll("\"", "`")
46+
.replaceAll(",", ",")
47+
// 这里全部转小写, 会让驼峰风格的字段名丢失驼峰信息(真有驼峰sql字段名的呢(* ̄︶ ̄)); 下文使用工具方法处理包含等
48+
// .toLowerCase()
49+
;
4650
//deal with java string copy \n"
4751
tableSql = tableSql.trim().replaceAll("\\\\n`", "").replaceAll("\\+", "").replaceAll("``", "`").replaceAll("\\\\", "");
4852
// table Name
4953
String tableName = null;
50-
if (tableSql.contains("TABLE") && tableSql.contains("(")) {
51-
tableName = tableSql.substring(tableSql.indexOf("TABLE") + 5, tableSql.indexOf("("));
52-
} else if (tableSql.contains("table") && tableSql.contains("(")) {
53-
tableName = tableSql.substring(tableSql.indexOf("table") + 5, tableSql.indexOf("("));
54+
int tableKwIx = tableSql.indexOf("TABLE"); // 包含判断和位置一次搞定
55+
if (tableKwIx > -1 && tableSql.contains("(")) {
56+
tableName = tableSql.substring(tableKwIx + 5, tableSql.indexOf("(")).get();
5457
} else {
5558
throw new CodeGenerateException("Table structure incorrect.表结构不正确。");
5659
}
@@ -88,9 +91,11 @@ public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
8891
String classComment = null;
8992
//mysql是comment=,pgsql/oracle是comment on table,
9093
//2020-05-25 优化表备注的获取逻辑
91-
if (tableSql.contains("comment=") || tableSql.contains("comment on table")) {
92-
String classCommentTmp = (tableSql.contains("comment=")) ?
93-
tableSql.substring(tableSql.lastIndexOf("comment=") + 8).trim() : tableSql.substring(tableSql.lastIndexOf("comment on table") + 17).trim();
94+
if (tableSql.containsAny("comment=", "comment on table")) {
95+
int ix = tableSql.lastIndexOf("comment=");
96+
String classCommentTmp = (ix > -1) ?
97+
tableSql.substring(ix + 8).trim().get() :
98+
tableSql.substring(tableSql.lastIndexOf("comment on table") + 17).trim().get();
9499
if (classCommentTmp.contains("`")) {
95100
classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf("`") + 1);
96101
classCommentTmp = classCommentTmp.substring(0, classCommentTmp.indexOf("`"));
@@ -109,7 +114,7 @@ public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
109114
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
110115

111116
// 正常( ) 内的一定是字段相关的定义。
112-
String fieldListTmp = tableSql.substring(tableSql.indexOf("(") + 1, tableSql.lastIndexOf(")"));
117+
String fieldListTmp = tableSql.substring(tableSql.indexOf("(") + 1, tableSql.lastIndexOf(")")).get();
113118

114119
// 匹配 comment,替换备注里的小逗号, 防止不小心被当成切割符号切割
115120
String commentPattenStr1 = "comment `(.*?)\\`";
@@ -149,7 +154,8 @@ public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
149154
if (fieldLineList.length > 0) {
150155
int i = 0;
151156
//i为了解决primary key关键字出现的地方,出现在前3行,一般和id有关
152-
for (String columnLine : fieldLineList) {
157+
for (String columnLine0 : fieldLineList) {
158+
NonCaseString columnLine = NonCaseString.of(columnLine0);
153159
i++;
154160
columnLine = columnLine.replaceAll("\n", "").replaceAll("\t", "").trim();
155161
// `userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
@@ -158,13 +164,10 @@ public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
158164
// 2019-2-22 zhengkai 要在条件中使用复杂的表达式
159165
// 2019-4-29 zhengkai 优化对普通和特殊storage关键字的判断(感谢@AhHeadFloating的反馈 )
160166
// 2020-10-20 zhengkai 优化对fulltext/index关键字的处理(感谢@WEGFan的反馈)
161-
boolean specialFlag = (!columnLine.contains("key ") && !columnLine.contains("constraint") && !columnLine.contains("using") && !columnLine.contains("unique ")
162-
&& !(columnLine.contains("primary ") && columnLine.indexOf("storage") + 3 > columnLine.indexOf("("))
163-
&& !columnLine.contains("fulltext ") && !columnLine.contains("index ")
164-
&& !columnLine.contains("pctincrease")
165-
&& !columnLine.contains("buffer_pool") && !columnLine.contains("tablespace")
166-
&& !(columnLine.contains("primary ") && i > 3));
167-
if (specialFlag) {
167+
// 2023-8-27 zhangfei 改用工具方法判断, 且修改变量名(非特殊标识), 方法抽取
168+
boolean notSpecialFlag = isNotSpecialColumnLine(columnLine, i);
169+
170+
if (notSpecialFlag) {
168171
//如果是oracle的number(x,x),可能出现最后分割残留的,x),这里做排除处理
169172
if (columnLine.length() < 5) {
170173
continue;
@@ -174,24 +177,25 @@ public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
174177
columnLine = columnLine.replaceAll("`", " ").replaceAll("\"", " ").replaceAll("'", "").replaceAll(" ", " ").trim();
175178
//如果遇到username varchar(65) default '' not null,这种情况,判断第一个空格是否比第一个引号前
176179
try {
177-
columnName = columnLine.substring(0, columnLine.indexOf(" "));
180+
columnName = columnLine.substring(0, columnLine.indexOf(" ")).get();
178181
} catch (StringIndexOutOfBoundsException e) {
179182
System.out.println("err happened: " + columnLine);
180183
throw e;
181184
}
182185

183186
// field Name
184187
// 2019-09-08 yj 添加是否下划线转换为驼峰的判断
188+
// 2023-8-27 zhangfei 支持原始列名任意命名风格, 不依赖用户是否输入下划线
185189
String fieldName = null;
186190
if (ParamInfo.NAME_CASE_TYPE.CAMEL_CASE.equals(nameCaseType)) {
187191
fieldName = StringUtils.lowerCaseFirst(StringUtils.underlineToCamelCase(columnName));
188192
if (fieldName.contains("_")) {
189193
fieldName = fieldName.replaceAll("_", "");
190194
}
191195
} else if (ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE.equals(nameCaseType)) {
192-
fieldName = StringUtils.lowerCaseFirst(columnName);
196+
fieldName = StringUtils.toUnderline(columnName, false);
193197
} else if (ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE.equals(nameCaseType)) {
194-
fieldName = StringUtils.lowerCaseFirst(columnName.toUpperCase());
198+
fieldName = StringUtils.toUnderline(columnName.toUpperCase(), true);
195199
} else {
196200
fieldName = columnName;
197201
}
@@ -228,12 +232,12 @@ public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
228232
while (columnCommentMatcher.find()) {
229233
String columnCommentTmp = columnCommentMatcher.group();
230234
//System.out.println(columnCommentTmp);
231-
fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp) + columnCommentTmp.length()).trim();
235+
fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp) + columnCommentTmp.length()).trim().get();
232236
fieldComment = fieldComment.substring(0, fieldComment.indexOf("`")).trim();
233237
}
234238
} else if (columnLine.contains(" comment")) {
235239
//20200518 zhengkai 修复包含comment关键字的问题
236-
String commentTmp = columnLine.substring(columnLine.lastIndexOf("comment") + 7).trim();
240+
String commentTmp = columnLine.substring(columnLine.lastIndexOf("comment") + 7).trim().get();
237241
// '用户ID',
238242
if (commentTmp.contains("`") || commentTmp.indexOf("`") != commentTmp.lastIndexOf("`")) {
239243
commentTmp = commentTmp.substring(commentTmp.indexOf("`") + 1, commentTmp.lastIndexOf("`"));
@@ -275,6 +279,24 @@ public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)
275279
return codeJavaInfo;
276280
}
277281

282+
private static boolean isNotSpecialColumnLine(NonCaseString columnLine, int lineSeq) {
283+
return (
284+
!columnLine.containsAny(
285+
"key ",
286+
"constraint",
287+
"using",
288+
"unique ",
289+
"fulltext ",
290+
"index ",
291+
"pctincrease",
292+
"buffer_pool",
293+
"tablespace"
294+
)
295+
&& !(columnLine.contains("primary ") && columnLine.indexOf("storage") + 3 > columnLine.indexOf("("))
296+
&& !(columnLine.contains("primary ") && lineSeq > 3)
297+
);
298+
}
299+
278300
/**
279301
* 解析JSON生成类信息
280302
*

generator-web/src/main/resources/statics/js/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ const vm = new Vue({
3636
" 'user_name' varchar(255) NOT NULL COMMENT '用户名',\n" +
3737
" 'status' tinyint(1) NOT NULL COMMENT '状态',\n" +
3838
" 'create_time' datetime NOT NULL COMMENT '创建时间',\n" +
39+
//下面可以留着方便开发调试时打开
40+
// " `updateTime` datetime NOT NULL COMMENT '更新时间',\n" +
41+
// " ABc_under_Line-Hypen-CamelCase varchar comment '乱七八糟的命名风格',\n" +
3942
" PRIMARY KEY ('user_id')\n" +
4043
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息'",
4144
options: {

0 commit comments

Comments
 (0)