diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java index a307f69c..38b8668f 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java @@ -84,7 +84,7 @@ public class RowSqlProvider { //让所有 row 的列顺序和值的数量与第条数据保持一致 Set modifyAttrs = rows.get(0).obtainModifyAttrs(); - rows.forEach(row -> row.keep(modifyAttrs)); + rows.forEach(row -> row.keepModifyAttrs(modifyAttrs)); Object[] values = new Object[]{}; @@ -164,7 +164,7 @@ public class RowSqlProvider { public static String updateById(Map params) { String tableName = ProviderUtil.getTableName(params); Row row = ProviderUtil.getRow(params); - ProviderUtil.setSqlArgs(params, row.obtainModifyValuesAndPrimaryValues()); + ProviderUtil.setSqlArgs(params, row.obtainAllModifyValues()); return DialectFactory.getDialect().forUpdateById(tableName, row); } @@ -208,7 +208,7 @@ public class RowSqlProvider { Object[] values = new Object[0]; for (Row row : rows) { - values = ArrayUtil.concat(values, row.obtainModifyValuesAndPrimaryValues()); + values = ArrayUtil.concat(values, row.obtainAllModifyValues()); } ProviderUtil.setSqlArgs(params, values); return DialectFactory.getDialect().forUpdateBatchById(tableName, rows); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/FunctionQueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/FunctionQueryColumn.java index b211546f..a3c3b712 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/FunctionQueryColumn.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/FunctionQueryColumn.java @@ -16,6 +16,7 @@ package com.mybatisflex.core.querywrapper; import com.mybatisflex.core.dialect.IDialect; +import com.mybatisflex.core.util.SqlUtil; import com.mybatisflex.core.util.StringUtil; import java.util.List; @@ -29,11 +30,14 @@ public class FunctionQueryColumn extends QueryColumn { protected QueryColumn column; public FunctionQueryColumn(String fnName, String column) { + SqlUtil.keepColumnSafely(fnName); + SqlUtil.keepColumnSafely(column); this.fnName = fnName; this.column = new QueryColumn(column); } public FunctionQueryColumn(String fnName, QueryColumn column) { + SqlUtil.keepColumnSafely(fnName); this.fnName = fnName; this.column = column; } @@ -62,6 +66,7 @@ public class FunctionQueryColumn extends QueryColumn { @Override public QueryColumn as(String alias) { + SqlUtil.keepColumnSafely(alias); this.alias = alias; return this; } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/QueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/QueryColumn.java index a07ab779..2a378101 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/QueryColumn.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/QueryColumn.java @@ -18,6 +18,7 @@ package com.mybatisflex.core.querywrapper; import com.mybatisflex.core.dialect.IDialect; import com.mybatisflex.core.table.TableDef; +import com.mybatisflex.core.util.SqlUtil; import com.mybatisflex.core.util.StringUtil; import java.io.Serializable; @@ -38,15 +39,18 @@ public class QueryColumn implements Serializable { } public QueryColumn(String name) { + SqlUtil.keepColumnSafely(name); this.name = name; } public QueryColumn(String tableName, String name) { + SqlUtil.keepColumnSafely(name); this.table = new QueryTable(tableName); this.name = name; } public QueryColumn(TableDef tableDef, String name) { + SqlUtil.keepColumnSafely(name); this.table = new QueryTable(tableDef.getTableName()); this.name = name; } @@ -77,6 +81,7 @@ public class QueryColumn implements Serializable { } public QueryColumn as(String alias) { + SqlUtil.keepColumnSafely(alias); QueryColumn newColumn = new QueryColumn(); newColumn.table = this.table; newColumn.name = this.name; @@ -175,7 +180,6 @@ public class QueryColumn implements Serializable { } - /** * IS NOT NULL * @@ -203,6 +207,7 @@ public class QueryColumn implements Serializable { /** * in child select + * * @param queryWrapper * @return */ @@ -254,6 +259,7 @@ public class QueryColumn implements Serializable { /** * not in child select + * * @param queryWrapper */ public QueryCondition notIn(QueryWrapper queryWrapper) { @@ -263,6 +269,7 @@ public class QueryColumn implements Serializable { /** * between + * * @param start * @param end */ @@ -301,13 +308,13 @@ public class QueryColumn implements Serializable { } } - String toConditionSql(List queryTables, IDialect dialect) { + String toConditionSql(List queryTables, IDialect dialect) { String tableName = WrapperUtil.getColumnTableName(queryTables, table); return wrap(dialect, tableName, name); } - String toSelectSql(List queryTables, IDialect dialect) { + String toSelectSql(List queryTables, IDialect dialect) { String tableName = WrapperUtil.getColumnTableName(queryTables, table); return wrap(dialect, tableName, name) + WrapperUtil.buildAsAlias(dialect.wrap(alias)); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/StringQueryOrderBy.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/StringQueryOrderBy.java index 2fd92757..98e4e5e2 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/StringQueryOrderBy.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/querywrapper/StringQueryOrderBy.java @@ -17,6 +17,7 @@ package com.mybatisflex.core.querywrapper; import com.mybatisflex.core.dialect.IDialect; +import com.mybatisflex.core.util.SqlUtil; import java.util.List; @@ -28,6 +29,7 @@ public class StringQueryOrderBy extends QueryOrderBy { private String orderBy; public StringQueryOrderBy(String orderBy) { + SqlUtil.keepOrderBySqlSafely(orderBy); this.orderBy = orderBy; } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java index d7b80bf7..f3940eca 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java @@ -16,12 +16,16 @@ package com.mybatisflex.core.row; import com.mybatisflex.core.javassist.ModifyAttrsRecord; +import com.mybatisflex.core.querywrapper.QueryColumn; import com.mybatisflex.core.table.TableInfo; import com.mybatisflex.core.table.TableInfos; import com.mybatisflex.core.util.ArrayUtil; +import com.mybatisflex.core.util.SqlUtil; +import com.mybatisflex.core.util.StringUtil; +import java.util.Collection; import java.util.HashMap; -import java.util.Set; +import java.util.Map; public class Row extends HashMap implements ModifyAttrsRecord { private static final Object[] NULL_ARGS = new Object[0]; @@ -84,12 +88,19 @@ public class Row extends HashMap implements ModifyAttrsRecord { } - public Row set(String key, Object value) { - put(key, value); + public Row set(String column, Object value) { + if (StringUtil.isBlank(column)) { + throw new IllegalArgumentException("key column not be null or empty."); + } + + SqlUtil.keepColumnSafely(column); + + put(column, value); + boolean isPrimaryKey = false; if (this.primaryKeys != null) { for (RowKey rowKey : primaryKeys) { - if (rowKey.getKeyColumn().equals(key)) { + if (rowKey.getKeyColumn().equals(column)) { isPrimaryKey = true; break; } @@ -97,12 +108,16 @@ public class Row extends HashMap implements ModifyAttrsRecord { } if (!isPrimaryKey) { - addModifyAttr(key); + addModifyAttr(column); } return this; } + public Row set(QueryColumn queryColumn, Object value) { + return set(queryColumn.getName(), value); + } + public Object get(Object key, Object defaultValue) { Object result = super.get(key); @@ -123,7 +138,25 @@ public class Row extends HashMap implements ModifyAttrsRecord { } - public void keep(Set attrs) { + public Map toCamelKeysMap() { + Map ret = new HashMap<>(); + for (String key : keySet()) { + ret.put(StringUtil.underlineToCamel(key), get(key)); + } + return ret; + } + + + public Map toUnderlineKeysMap() { + Map ret = new HashMap<>(); + for (String key : keySet()) { + ret.put(StringUtil.camelToUnderline(key), get(key)); + } + return ret; + } + + + public void keepModifyAttrs(Collection attrs) { if (attrs == null) { throw new NullPointerException("attrs is null."); } @@ -174,7 +207,7 @@ public class Row extends HashMap implements ModifyAttrsRecord { } - public Object[] obtainModifyValuesAndPrimaryValues() { + public Object[] obtainAllModifyValues() { return ArrayUtil.concat(obtainModifyValues(), obtainsPrimaryValues()); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowKey.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowKey.java index 1205af1c..4f4ef491 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowKey.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowKey.java @@ -16,6 +16,7 @@ package com.mybatisflex.core.row; import com.mybatisflex.core.enums.KeyType; +import com.mybatisflex.core.util.SqlUtil; /** * row 的主键策略 @@ -25,21 +26,23 @@ public class RowKey { /** * 自增 ID */ - public static final RowKey ID_AUTO = new UnModifiableRowKey("id",KeyType.Auto,null,false); + public static final RowKey ID_AUTO = new UnModifiableRowKey("id", KeyType.Auto, null, false); /** * UUID 的 ID */ - public static final RowKey ID_UUID = new UnModifiableRowKey("id",KeyType.Generator,"uuid",true); + public static final RowKey ID_UUID = new UnModifiableRowKey("id", KeyType.Generator, "uuid", true); public static RowKey of(String keyColumn) { + SqlUtil.keepColumnSafely(keyColumn); RowKey rowKey = new RowKey(); rowKey.keyColumn = keyColumn; return rowKey; } public static RowKey of(String keyColumn, KeyType keyType) { + SqlUtil.keepColumnSafely(keyColumn); RowKey rowKey = new RowKey(); rowKey.keyColumn = keyColumn; rowKey.keyType = keyType; @@ -47,6 +50,7 @@ public class RowKey { } public static RowKey of(String keyColumn, KeyType keyType, String keyTypeValue) { + SqlUtil.keepColumnSafely(keyColumn); RowKey rowKey = new RowKey(); rowKey.keyColumn = keyColumn; rowKey.keyType = keyType; @@ -55,6 +59,7 @@ public class RowKey { } public static RowKey of(String keyColumn, KeyType keyType, String keyTypeValue, boolean before) { + SqlUtil.keepColumnSafely(keyColumn); RowKey rowKey = new RowKey(); rowKey.keyColumn = keyColumn; rowKey.keyType = keyType; @@ -116,7 +121,7 @@ public class RowKey { this.before = before; } - static class UnModifiableRowKey extends RowKey{ + static class UnModifiableRowKey extends RowKey { public UnModifiableRowKey(String keyColumn, KeyType keyType, String value, boolean before) { super(); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/SqlUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/SqlUtil.java new file mode 100644 index 00000000..0ebabaaf --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/SqlUtil.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.util; + +public class SqlUtil { + + + public static void keepColumnSafely(String column) { + if (StringUtil.isBlank(column)) { + throw new IllegalArgumentException("Column must not be empty"); + } else { + column = column.trim(); + } + + int strLen = column.length(); + for (int i = 0; i < strLen; ++i) { + char ch = column.charAt(i); + if (Character.isWhitespace(ch)) { + throw new IllegalArgumentException("Column must not has space char."); + } + if (isUnSafeChar(ch)) { + throw new IllegalArgumentException("Column has unsafe char: [" + ch + "]."); + } + } + } + + + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + private static String SQL_ORDER_BY_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + public static void keepOrderBySqlSafely(String value) { + if (!value.matches(SQL_ORDER_BY_PATTERN)) { + throw new IllegalArgumentException("Order By sql not safe, order by string: " + value); + } + } + + + private static final char[] UN_SAFE_CHARS = "'`\"<>&*+=#-;".toCharArray(); + + private static boolean isUnSafeChar(char ch) { + for (char c : UN_SAFE_CHARS) { + if (c == ch) { + return true; + } + } + return false; + } + + +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/StringUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/StringUtil.java index 94c2ff42..59fa980e 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/StringUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/StringUtil.java @@ -27,7 +27,6 @@ public class StringUtil { * 第一个字符转换为小写 * * @param string - * @return */ public static String firstCharToLowerCase(String string) { char firstChar = string.charAt(0); @@ -65,9 +64,9 @@ public class StringUtil { if (isBlank(string)) { return ""; } - int len = string.length(); - StringBuilder sb = new StringBuilder(len); - for (int i = 0; i < len; i++) { + int strLen = string.length(); + StringBuilder sb = new StringBuilder(strLen); + for (int i = 0; i < strLen; i++) { char c = string.charAt(i); if (Character.isUpperCase(c) && i > 0) { sb.append('_'); @@ -87,12 +86,12 @@ public class StringUtil { return ""; } String temp = string.toLowerCase(); - int len = temp.length(); - StringBuilder sb = new StringBuilder(len); - for (int i = 0; i < len; i++) { + int strLen = temp.length(); + StringBuilder sb = new StringBuilder(strLen); + for (int i = 0; i < strLen; i++) { char c = temp.charAt(i); if (c == '_') { - if (++i < len) { + if (++i < strLen) { sb.append(Character.toUpperCase(temp.charAt(i))); } } else {