This commit is contained in:
Looly
2020-08-04 12:10:06 +08:00
parent 34f49fc916
commit ed708f730c
3 changed files with 75 additions and 28 deletions

View File

@@ -16,6 +16,7 @@
### Bug修复#
* 【core 】 修复原始类型转换时,转换失败没有抛出异常的问题
* 【core 】 修复BeanUtil.mapToBean中bean的class非空构造无法实例化问题
* 【core 】 修复NamedSql多个连续变量出现替换问题
-------------------------------------------------------------------------------------------------------------

View File

@@ -1,6 +1,8 @@
package cn.hutool.db.sql;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import java.util.LinkedList;
@@ -12,8 +14,8 @@ import java.util.Map;
* 支持的占位符格式为:
* <pre>
* 1、:name
* 2、?name
* 3、@name
* 2、@name
* 3、?name
* </pre>
*
* @author looly
@@ -21,6 +23,8 @@ import java.util.Map;
*/
public class NamedSql {
private static final char[] NAME_START_CHARS = {':', '@', '?'};
private String sql;
private final List<Object> params;
@@ -69,6 +73,11 @@ public class NamedSql {
* @param paramMap 名和参数的对应Map
*/
private void parse(String namedSql, Map<String, Object> paramMap) {
if(MapUtil.isEmpty(paramMap)){
this.sql = namedSql;
return;
}
int len = namedSql.length();
final StrBuilder name = StrUtil.strBuilder();
@@ -77,51 +86,66 @@ public class NamedSql {
Character nameStartChar = null;
for (int i = 0; i < len; i++) {
c = namedSql.charAt(i);
if (c == ':' || c == '@' || c == '?') {
if (ArrayUtil.contains(NAME_START_CHARS, c)) {
nameStartChar = c;
// 新的变量开始符出现,要处理之前的变量
replaceVar(nameStartChar, name, sqlBuilder, paramMap);
} else if (null != nameStartChar) {
// 变量状态
if (isGenerateChar(c)) {
// 变量名
name.append(c);
} else {
// 变量结束
String nameStr = name.toString();
if(paramMap.containsKey(nameStr)) {
// 有变量对应值值可以为null替换占位符
final Object paramValue = paramMap.get(nameStr);
sqlBuilder.append('?');
this.params.add(paramValue);
} else {
// 无变量对应值,原样输出
sqlBuilder.append(nameStartChar).append(name);
}
// 非标准字符也非变量开始的字符出现表示变量名结束,开始替换
replaceVar(nameStartChar, name, sqlBuilder, paramMap);
nameStartChar = null;
name.clear();
sqlBuilder.append(c);
}
} else {
// 变量以外的字符原样输出
sqlBuilder.append(c);
}
}
// 收尾如果SQL末尾存在变量处理之
if (false == name.isEmpty()) {
// SQL结束依旧有变量名存在说明变量位于末尾
final Object paramValue = paramMap.get(name.toString());
if (null != paramValue) {
// 有变量对应值,替换占位符
sqlBuilder.append('?');
this.params.add(paramValue);
} else {
// 无变量对应值,原样输出
sqlBuilder.append(nameStartChar).append(name);
}
name.clear();
replaceVar(nameStartChar, name, sqlBuilder, paramMap);
}
this.sql = sqlBuilder.toString();
}
/**
* 替换变量如果无变量原样输出到SQL中去
*
* @param nameStartChar 变量开始字符
* @param name 变量名
* @param sqlBuilder 结果SQL缓存
* @param paramMap 变量map非空
*/
private void replaceVar(Character nameStartChar, StrBuilder name, StrBuilder sqlBuilder, Map<String, Object> paramMap){
if(name.isEmpty()){
// 无变量,按照普通字符处理
return;
}
// 变量结束
final String nameStr = name.toString();
if(paramMap.containsKey(nameStr)) {
// 有变量对应值值可以为null替换占位符为?变量值放入相应index位置
final Object paramValue = paramMap.get(nameStr);
sqlBuilder.append('?');
this.params.add(paramValue);
} else {
// 无变量对应值,原样输出
sqlBuilder.append(nameStartChar).append(name);
}
//清空变量,表示此变量处理结束
name.clear();
}
/**
* 是否为标准的字符,包括大小写字母、下划线和数字
*

View File

@@ -15,7 +15,11 @@ public class NamedSqlTest {
public void parseTest() {
String sql = "select * from table where id=@id and name = @name1 and nickName = :subName";
Map<String, Object> paramMap = MapUtil.builder("name1", (Object)"张三").put("age", 12).put("subName", "小豆豆").build();
Map<String, Object> paramMap = MapUtil
.builder("name1", (Object)"张三")
.put("age", 12)
.put("subName", "小豆豆")
.build();
NamedSql namedSql = new NamedSql(sql, paramMap);
//未指定参数原样输出
@@ -28,7 +32,12 @@ public class NamedSqlTest {
public void parseTest2() {
String sql = "select * from table where id=@id and name = @name1 and nickName = :subName";
Map<String, Object> paramMap = MapUtil.builder("name1", (Object)"张三").put("age", 12).put("subName", "小豆豆").put("id", null).build();
Map<String, Object> paramMap = MapUtil
.builder("name1", (Object)"张三")
.put("age", 12)
.put("subName", "小豆豆")
.put("id", null)
.build();
NamedSql namedSql = new NamedSql(sql, paramMap);
Assert.assertEquals("select * from table where id=? and name = ? and nickName = ?", namedSql.getSql());
@@ -38,6 +47,19 @@ public class NamedSqlTest {
Assert.assertEquals("小豆豆", namedSql.getParams()[2]);
}
@Test
public void parseTest3() {
// 测试连续变量名出现是否有问题
String sql = "SELECT to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as sysdate FROM dual";
Map<String, Object> paramMap = MapUtil
.builder("name1", (Object)"张三")
.build();
NamedSql namedSql = new NamedSql(sql, paramMap);
Assert.assertEquals(sql, namedSql.getSql());
}
@Test
public void queryTest() throws SQLException {
Map<String, Object> paramMap = MapUtil