Skip to content

Commit 02f30d0

Browse files
committed
SQL语句支持{xxx}替换,从参数、常量、属性拿值替换
1 parent 92c2b42 commit 02f30d0

14 files changed

+231
-74
lines changed

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/DAOMetaData.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ public class DAOMetaData {
4040
/**
4141
* 定义在DAO接口上的常量(包含父接口的)
4242
*/
43-
private final Map<String, ?> constants;
43+
private final Map<String, Object> constants;
4444

45+
/**
46+
* DAO类上的属性
47+
*/
4548
private final Map<String, Object> attributes;
4649

4750
/**
@@ -50,9 +53,9 @@ public class DAOMetaData {
5053
*/
5154
public DAOMetaData(Class<?> daoClass, DAOConfig config) {
5255
this.daoClass = daoClass;
53-
this.constants = Collections.unmodifiableMap(//
54-
GenericUtils.getConstantFrom(daoClass, true, true));
5556
this.config = config;
57+
this.constants = Collections
58+
.unmodifiableMap(GenericUtils.getConstantFrom(daoClass, true, true));
5659
this.attributes = new ConcurrentHashMap<String, Object>(4);
5760
}
5861

@@ -80,7 +83,7 @@ public Class resolveTypeVariable(Class<?> declaringClass, String typeVarName) {
8083
return GenericUtils.resolveTypeVariable(daoClass, declaringClass, typeVarName);
8184
}
8285

83-
public Map<String, ?> getConstants() {
86+
public Map<String, Object> getConstants() {
8487
return constants;
8588
}
8689

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/GenericUtils.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public static final Class resolveTypeVariable(Class invocationClass, Type target
158158
*
159159
* @return {@link Map} 包含类的所有常量
160160
*/
161-
public static Map<String, ?> getConstantFrom(Class clazz, // NL
161+
public static Map<String, Object> getConstantFrom(Class clazz, // NL
162162
boolean findAncestor, boolean findInterfaces) {
163163

164164
HashMap<String, Object> map = new HashMap<String, Object>();

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/Interpreter.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
* <p>
2323
* 如果没有标注 {@link Order} 使用默认值0。
2424
*
25+
* 从实践看,jade插件的解析器一般应该设置为负数,以优先于系统解析器。
26+
*
2527
* @author 王志亮 [qieqie.wang@gmail.com]
2628
* @author 廖涵 [in355hz@gmail.com]
2729
*
2830
*/
29-
//按Spring语义规定,Order值越高该解释器越后执行
31+
//按Spring语义规定,根据 {@link Order} 语义,值越小越优先,值越大越后;
3032
@Order(0)
3133
public interface Interpreter {
3234

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/StatementRuntime.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public interface StatementRuntime {
3434
StatementMetaData getMetaData();
3535

3636
/**
37-
* @return 返回调用DAO方法传入的参数,key为":1"、":2"以及 {@link SQLParam} 注解指定的名称
37+
* @return 返回调用DAO方法传入的参数,key为":1"、":2"以及 {@link SQLParam} 注解指定的名称(不含冒号)
3838
*/
3939
Map<String, Object> getParameters();
4040

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/SystemInterpreter.java

+154-17
Original file line numberDiff line numberDiff line change
@@ -18,51 +18,188 @@
1818
import java.sql.SQLSyntaxErrorException;
1919
import java.util.HashMap;
2020
import java.util.Map;
21+
import java.util.regex.Matcher;
22+
import java.util.regex.Pattern;
23+
24+
import org.springframework.jdbc.BadSqlGrammarException;
2125

2226
import net.paoding.rose.jade.statement.expression.ExqlPattern;
2327
import net.paoding.rose.jade.statement.expression.impl.ExqlContextImpl;
2428
import net.paoding.rose.jade.statement.expression.impl.ExqlPatternImpl;
2529

26-
import org.springframework.jdbc.BadSqlGrammarException;
27-
2830
/**
2931
*
3032
* @author 廖涵 [in355hz@gmail.com]
3133
*/
3234
public class SystemInterpreter implements Interpreter {
3335

36+
private ReplacementInterpreter replacementInterpreter = new ReplacementInterpreter();
37+
private PreparestatmentInterpreter preparestatmentInterpreter = new PreparestatmentInterpreter();
38+
3439
@Override
3540
public void interpret(StatementRuntime runtime) {
36-
// 转换语句中的表达式
37-
ExqlPattern pattern = ExqlPatternImpl.compile(runtime.getSQL());
38-
ExqlContextImpl context = new ExqlContextImpl(runtime.getSQL().length() + 32);
39-
40-
try {
41-
pattern.execute(context, runtime.getParameters(), runtime.getMetaData()
42-
.getDAOMetaData().getConstants());
43-
runtime.setArgs(context.getParams());
44-
runtime.setSQL(context.flushOut());
45-
} catch (Exception e) {
46-
String daoInfo = runtime.getMetaData().toString();
47-
throw new BadSqlGrammarException(daoInfo, runtime.getSQL(),
41+
replacementInterpreter.interpret(runtime);
42+
preparestatmentInterpreter.interpret(runtime);
43+
}
44+
45+
/**
46+
* 使用方法参数、常量替换{xxxx}、{:xxxx}、##(:xxx)、##(xxx)等位置;
47+
* <p>
48+
*
49+
* select form ##(:table) {name} where {id}='{1}'
50+
* @author zlw
51+
*
52+
*/
53+
static class ReplacementInterpreter implements Interpreter {
54+
55+
final Pattern PATTERN = Pattern.compile("\\{([a-zA-Z0-9_\\.\\:]+)\\}|##\\((.+)\\)");
56+
57+
@Override
58+
public void interpret(StatementRuntime runtime) {// ##(:xxx)
59+
String sql = runtime.getSQL();
60+
StringBuilder sb = new StringBuilder(sql.length() + 200);
61+
Matcher matcher = PATTERN.matcher(sql);
62+
int start = 0;
63+
while (matcher.find(start)) {
64+
sb.append(sql.substring(start, matcher.start()));
65+
String group = matcher.group();
66+
String key = null;
67+
if (group.startsWith("{")) {
68+
key = matcher.group(1);
69+
} else if (group.startsWith("##(")) {
70+
key = matcher.group(2);
71+
}
72+
// get value from parameters
73+
Object value = runtime.getParameters().get(key); // 针对{paramName}、{:1}两种情况
74+
if (value == null) {
75+
if (key.startsWith(":") || key.startsWith("$")) {
76+
value = runtime.getParameters().get(key.substring(1)); // 针对{:paramName}的情况
77+
} else {
78+
char ch = key.charAt(0);// 由正则表达式知道key长度必定大于0
79+
if (ch >= '0' && ch <= '9') {
80+
value = runtime.getParameters().get(":" + key); // 针对{1}两种情况
81+
}
82+
}
83+
}
84+
// get value from constants
85+
if (value == null) {
86+
value = runtime.getMetaData().getDAOMetaData().getConstants().get(key); // 针对常量的情况
87+
}
88+
// get value from attributes
89+
if (value == null) {
90+
String attributeKey = group;
91+
if (!attributeKey.startsWith("{")) {
92+
attributeKey = "{" + key + "}";
93+
}
94+
value = runtime.getMetaData().getDAOMetaData().getAttribute(attributeKey); // 针对插件设置进来的属性的情况
95+
}
96+
// replace it
97+
if (value != null) {
98+
sb.append(value);
99+
} else {
100+
sb.append(group);
101+
}
102+
start = matcher.end();
103+
}
104+
sb.append(sql.substring(start));
105+
106+
runtime.setSQL(sb.toString());
107+
108+
}
109+
}
110+
111+
// 动态参数
112+
static class PreparestatmentInterpreter implements Interpreter {
113+
114+
@Override
115+
public void interpret(StatementRuntime runtime) {
116+
// 转换语句中的表达式
117+
ExqlPattern pattern = ExqlPatternImpl.compile(runtime.getSQL());
118+
ExqlContextImpl context = new ExqlContextImpl(runtime.getSQL().length() + 32);
119+
120+
try {
121+
Map<String, Object> constants = runtime.getMetaData().getDAOMetaData()
122+
.getConstants();
123+
pattern.execute(context, runtime.getParameters(), constants);
124+
runtime.setArgs(context.getArgs());
125+
runtime.setSQL(context.flushOut());
126+
} catch (Exception e) {
127+
String daoInfo = runtime.getMetaData().toString();
128+
throw new BadSqlGrammarException(daoInfo, runtime.getSQL(),
48129
new SQLSyntaxErrorException(daoInfo + " @SQL('" + runtime.getSQL() + "')", e));
130+
}
49131
}
50132

51133
}
52134

135+
// ReplacementInterpreter
53136
public static void main(String[] args) throws Exception {
137+
Map<String, Object> parameters = new HashMap<String, Object>();
138+
parameters.put("table", "my_table_name");
139+
parameters.put("id", "my_id");
140+
parameters.put(":1", "first_param");
141+
142+
final Pattern PATTERN = Pattern.compile("\\{([a-zA-Z0-9_\\.\\:]+)\\}|##\\((.+)\\)");
143+
144+
String sql = "select form ##(:table) {name} where {id}='{1}'";
145+
146+
StringBuilder sb = new StringBuilder(sql.length() + 200);
147+
Matcher matcher = PATTERN.matcher(sql);
148+
int start = 0;
149+
while (matcher.find(start)) {
150+
sb.append(sql.substring(start, matcher.start()));
151+
String group = matcher.group();
152+
String key = null;
153+
if (group.startsWith("{")) {
154+
key = matcher.group(1);
155+
} else if (group.startsWith("##(")) {
156+
key = matcher.group(2);
157+
}
158+
System.out.println(key);
159+
if (key == null || key.length() == 0) {
160+
continue;
161+
}
162+
Object value = parameters.get(key); // 针对{paramName}、{:1}两种情况
163+
if (value == null) {
164+
if (key.startsWith(":") || key.startsWith("$")) {
165+
value = parameters.get(key.substring(1)); // 针对{:paramName}的情况
166+
} else {
167+
char ch = key.charAt(0);
168+
if (ch >= '0' && ch <= '9') {
169+
value = parameters.get(":" + key); // 针对{1}两种情况
170+
}
171+
}
172+
}
173+
if (value == null) {
174+
value = parameters.get(key); // 针对常量的情况
175+
}
176+
if (value != null) {
177+
sb.append(value);
178+
} else {
179+
sb.append(group);
180+
}
181+
start = matcher.end();
182+
}
183+
sb.append(sql.substring(start));
184+
System.out.println(sb);
185+
186+
}
187+
188+
// ExqlInterpreter
189+
public static void main0(String[] args) throws Exception {
54190
// 转换语句中的表达式
55191
String sql = "insert ignore into table_name "
56-
+ "(`id`,`uid`,`favable_id`,`addtime`,`ranking`) "//
57-
+ "values (:1,:2,now(),0)";
192+
+ "(`id`,`uid`,`favable_id`,`addtime`,`ranking`) "//
193+
+ "values (:1,:2,now(),0)";
58194
ExqlPattern pattern = ExqlPatternImpl.compile(sql);
59195
ExqlContextImpl context = new ExqlContextImpl(sql.length() + 32);
60196

61197
Map<String, Object> parametersAsMap = new HashMap<String, Object>();
62198
parametersAsMap.put(":1", "p1");
63199
parametersAsMap.put(":2", "p2");
64200

65-
String result = pattern.execute(context, parametersAsMap);
201+
pattern.execute(context, parametersAsMap);
202+
String result = context.flushOut();
66203
System.out.println(result);
67204
}
68205

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/expression/ExqlContext.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public interface ExqlContext {
3333
*
3434
* @return 所有参数的数组
3535
*/
36-
Object[] getParams();
36+
Object[] getArgs();
3737

3838
/**
3939
* 得到输出的语句内容。

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/expression/ExqlPattern.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@ public interface ExqlPattern {
1616
*
1717
* @param map - 参数表
1818
*
19-
* @return 语句内容
20-
*
2119
* @throws Exception
2220
*/
23-
String execute(ExqlContext context, Map<String, ?> map) throws Exception;
21+
void execute(ExqlContext context, Map<String, ?> map) throws Exception;
2422

2523
/**
2624
* 输出全部的语句内容。
@@ -30,10 +28,8 @@ public interface ExqlPattern {
3028
* @param mapVars - 参数表
3129
* @param mapConsts - 常量表
3230
*
33-
* @return 语句内容
34-
*
3531
* @throws Exception
3632
*/
37-
String execute(ExqlContext context, Map<String, ?> mapVars, // NL
33+
void execute(ExqlContext context, Map<String, ?> mapVars, // NL
3834
Map<String, ?> mapConsts) throws Exception;
3935
}

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/expression/impl/ExprResolverImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class ExprResolverImpl implements ExprResolver {
5252
/**
5353
* 构造表达式处理器。
5454
*/
55-
@SuppressWarnings("unchecked")
55+
@SuppressWarnings({ "unchecked", "rawtypes" })
5656
public ExprResolverImpl() {
5757
Map map = context.getVars();
5858
map.put(VAR_PREFIX, mapVars);

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/expression/impl/ExprUnit.java

-4
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ public void fill(ExqlContext exqlContext, ExprResolver exprResolver) throws Exce
3838

3939
// 解释表达式内容
4040
Object value = exprResolver.executeExpr(expr);
41-
42-
if (value instanceof Enum) {
43-
value = ((Enum<?>) value).name();
44-
}
4541

4642
// 输出转义的对象内容
4743
exqlContext.fillValue(value);

paoding-rose-jade/src/main/java/net/paoding/rose/jade/statement/expression/impl/ExqlCompiler.java

+11-4
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ public class ExqlCompiler {
3737
private static final String SHARP_ELSE = "#else";
3838

3939
// 正则表达式
40+
// private static final Pattern PATTERN_KEYWORD = Pattern.compile( // NL
41+
// "\\:\\:|([\\:\\$]{1}[a-zA-Z0-9_\\-\\.]+)|\\{([^\\{\\}]+)\\}\\?|#(#|!|if|for)?");
42+
43+
// 正则表达式(##(:xxx)已经由ReplacementInterpreter实现,不在Exql中处理)
4044
private static final Pattern PATTERN_KEYWORD = Pattern.compile( // NL
41-
"\\:\\:|([\\:\\$]{1}[a-zA-Z0-9_\\.]+)|\\{([^\\{\\}]+)\\}\\?|#(#|!|if|for)?");
45+
"\\:\\:|([\\:\\$]{1}[a-zA-Z0-9_\\-\\.]+)|\\{([^\\{\\}]+)\\}\\?|#(!|if|for)?");
4246

4347
private static final Pattern PATTERN_IN = Pattern.compile(// NL
4448
"([a-zA-Z0-9_]*)\\s+in\\s+(.+)");
@@ -130,6 +134,7 @@ protected ExqlUnit compileUnit() {
130134

131135
// 编译 {...} 内部的子句
132136
ExqlCompiler compiler = new ExqlCompiler(group);
137+
System.out.println("DELETE>>>group=" + group);
133138
ExqlUnit unit = compiler.compileUnit();
134139

135140
// 创建 {...}? 形式的子句
@@ -437,12 +442,13 @@ private boolean match(String keyword, int fromIndex) {
437442
}
438443

439444
// 进行简单测试
445+
// 贴士:##(:xxx) 已经被ReplacementInterpreter实现,
440446
public static void main(String... args) throws Exception {
441447

442448
String string = "SELECT :expr1, #($expr2.class),"
443449
+ " WHERE #if(:expr3) {e = $expr3} #else {e IS NULL}"
444450
+ "#for(variant in $expr4.bytes) { AND c = :variant}" // NL
445-
+ " {AND d = :expr5}? {AND f = $expr6}?" // NL
451+
+ " {AND d = :expr-5}? {AND f = $expr6}?" // NL
446452
+ " BY #!(:expr7) ASC";
447453

448454
// 在输入中查找 PREFIX 字符
@@ -487,7 +493,8 @@ public static void main(String... args) throws Exception {
487493
// map.put("expr6", "expr6");
488494
map.put("expr7", "expr7");
489495

490-
System.out.println(pattern.execute(context, map, map));
491-
System.out.println(Arrays.toString(context.getParams()));
496+
pattern.execute(context, map, map);
497+
System.out.println(context.flushOut());
498+
System.out.println(Arrays.toString(context.getArgs()));
492499
}
493500
}

0 commit comments

Comments
 (0)