uniapp开发app框架在提升开发效率中的独特优势与应用探索
1311
2022-11-18
基于mybatis注解动态sql中foreach工具的方法
目录实现目标工具类测试集成进spring后的使用方法Mapper层Provider层Ognl问题解决方案创建一个DefaultMemberAccess.java文件改造ForeachMybatisUtils.java类
实现目标
由于在注解版mybatis中手动循环拼接动态sql容易出错
请看mybatis注解动态sql注入map和list(防sql注入攻击),所以封装了这个类似于foreach标签的工具方法。
由于mybatis(3.5.6、3.5.7 or earlier)的bug(mybatis can not parse #{list[0][0]} correctly),不支持数组/List直接嵌套数组/List,但是可以与Map嵌套。不过 mybatis can parse ${list[0][0]} correctly
工具类
package com.xxx.common.util;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.ibatis.binding.BindingException;
import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlException;
import java.util.Set;
public class ForeachMybatisUtils {
private ForeachMybatisUtils() {}
public static
ParamObject
paramObject.setObj(obj);
return paramObject;
}
public static
return foreach(paramObject, null);
}
@SuppressWarnings("rawtypes")
public static
return foreach(paramObject.getObj(), paramObject.getCollection(), paramObject.getItem(), paramObject.getIndex(),
paramObject.getItemFormatter(), paramObject.getSeparator(), paramObject.getOpen(), paramObject.getClose(), interceptor);
}
/**
* itemFormatter部分用法:#{item,jdbcType=VARCHAR},#{item.3345,jdbcType=VARCHAR}其中3345为map的key, ${item}, ${item['3345']}其中3345为map的key
* @param
* @param obj list、map、数组对象
* @param collection 对应xml foreach标签的collection属性
* @param item 对应xml foreach标签的item属性
* @param index 对应xml foreach标签的index属性,但是在itemFormatter中只匹配 ${ } 格式
* @param itemFormatter 对应xml foreach标签内 #{item}
* @param separator 对应xml foreach标签的separator属性
* @param open 对应xml foreach标签的open属性
* @param close 对应xml foreach标签的close属性
* @return 拼接后的动态sql
*/
public static
String separator, String open, String close) {
return foreach(obj, collection, item, null, itemFormatter, separator, open, close, null);
}
public static
String separator, String open, String close) {
return foreach(obj, collection, item, index, itemFormatter, separator, open, close, null);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static
String open, String close, ForeachMybatisUtils.Interceptor interceptor) {
if (obj == null) {
throw new NullPointerException("object cannot be null");
}
if (collection == null || collection.trim().equals("")) {
throw new NullPointerException("collection cannot be blank");
}
if (item == null || item.trim().isEmpty()) {
throw new NullPointerException("item cannot be blank");
}
if (itemFormatter == null) {
throw new NullPointerException("itemFormatter cannot be null, and you can fill #{item},please");
}
collection = collection.trim();
item = item.trim();
if (index != null && item.equals(index.trim())) {
throw new IllegalArgumentException("index cannot be equal to item");
}
Pattern itemDynamicPattern = Pattern.compile("(?<=#\\{)" + item + "(?=[\\s\\S]*\\})");
Pattern itemBindingPattern = Pattern.compile("\\$\\{" + item + "(?:(?:\\.|\\[)\\S+)?\\s*\\}");
Pattern indexStaticPattern = null;
if (index != null && !index.trim().isEmpty() && itemFormatter.contains("${")) {
indexStaticPattern = Pattern.compile("\\$\\{" + index.trim() + "\\s*\\}");
}
if (separator == null) {
separator = "";
}
StringBuilder sqlBuilder = new StringBuilder();
if (open != null) {
sqlBuilder.append(open);
}
String prod = "";
int n = 0;
try {
if (obj instanceof Map) {
Set
for (Entry entry : set) {
String key = (String) entry.getKey();
if (interceptor != null && interceptor.preBreakIntercept(obj, key, entry.getValue())) {
break;
}
if (interceptor != null && interceptor.continueIntercept(obj, key, entry.getValue())) {
continue;
}
if (key.contains(".") || key.contains(" ")) {
throw new IllegalStateException("the Key of map can not contains '.' or ' '");
}
if (n > 0) {
sqlBuilder.append(separator);
}
prod = replaceAll(itemDynamicPattern, itemFormatter, collection + "." + key);
if (indexStaticPattern != null) {
prod = replaceAll(indexStaticPattern, prod, key);
}
prod = replaceBindingMap(itemBindingPattern, item, prod, key, obj);
sqlBuilder.append(prod);
n++;
if (interceptor != null && interceptor.postBreakIntercept(obj, key, entry.getValue())) {
break;
}
}
} else if (obj instanceof List) {
List list = (List) obj;
for (int i = 0, size = list.size(); i < size; i++) {
if (interceptor != null && interceptor.preBreakIntercept(obj, i, list.get(i))) {
break;
}
if (interceptor != null && interceptor.continueIntercept(obj, i, list.get(i))) {
continue;
}
if (n > 0) {
sqlBuilder.append(separator);
}
prod = replaceAll(itemDynamicPattern, itemFormatter, collection + "[" + i + "]");
if (indexStaticPattern != null) {
prod = replaceAll(indexStaticPattern, prod, "" + i);
}
prod = replaceBindingList(itemBindingPattern, item, prod, "" + i, obj);
sqlBuilder.append(prod);
n++;
if (interceptor != null && interceptor.postBreakIntercept(obj, i, list.get(i))) {
break;
}
}
} else if (obj.getClass().isArray()) {
List list = Arrays.asList((Object[]) obj);
for (int i = 0, size = list.size(); i < size; i++) {
if (interceptor != null && interceptor.preBreakIntercept(obj, i, list.get(i))) {
break;
}
if (interceptor != null && interceptor.continueIntercept(obj, i, list.get(i))) {
continue;
}
if (n > 0) {
sqlBuilder.append(separator);
}
prod = replaceAll(itemDynamicPattern, itemFormatter, collection + "[" + i + "]");
if (indexStaticPattern != null) {
prod = replaceAll(indexStaticPattern, prod, "" + i);
}
prod = replaceBindingList(itemBindingPattern, item, prod, "" + i, obj);
sqlBuilder.append(prod);
n++;
if (interceptor != null && interceptor.postBreakIntercept(obj, i, list.get(i))) {
break;
}
}
} else {
throw new IllegalArgumentException("the Type of collection support only Array,List,Map");
}
} catch (OgnlException e) {
throw new BindingException("ognl exception", e);
}
if (n < 1) {
sqlBuilder.delete(0, sqlBuilder.length());
} else {
if (close != null) {
sqlBuilder.append(close);
}
}
return sqlBuilder;
}
public static interface Interceptor
/**
* for循环内是否执行break语句, break语句在循环内第一行
* @param collection 集合
* @param item 集合元素
* @param key 集合key或下标
* @return 返回true,则执行break语句
*/
boolean preBreakIntercept(C collection, K key, T item);
/**
* for循环内是否执行break语句, break语句在循环内最后一行
* @param collection 集合
* @param item 集合元素
* @param key 集合key或下标
* @return 返回true,则执行break语句
*/
boolean postBreakIntercept(C collection, K key, T item);
/**
* for循环内是否执行continue语句
* @param collection 集合
* @param item 集合元素
* @param key 集合key或下标
* @return 返回true,则执行continue语句
*/
boolean continueIntercept(C collection, K key, T item);
}
private static String replaceAll(Pattern pattern, String itemFormatter, String collection) {
itemFormatter = pattern.matcher(itemFormatter).replaceAll(collection);
return itemFormatter;
}
private static
Matcher matcher = pattern.matcher(itemFormatter);
StringBuffer buffer = new StringBuffer();
matcher.reset();
String group = "";
while (matcher.find()) {
group = matcher.group();
group = group.replaceFirst("\\$\\{" + item, "#root['" + index + "']");
group = group.substring(0, group.length() - 1).trim();
group = String.valueOf(Ognl.getValue(group, obj));
matcher.appendReplacement(buffer, group);
}
matcher.appendTail(buffer);
return buffer.toString();
}
private static
Matcher matcher = pattern.matcher(itemFormatter);
StringBuffer buffer = new StringBuffer();
matcher.reset();
String group = "";
while (matcher.find()) {
group = matcher.group();
group = group.replaceFirst("\\$\\{" + item, "#root[" + index + "]");
group = group.substring(0, group.length() - 1).trim();
group = String.valueOf(Ognl.getValue(group, obj));
matcher.appendReplacement(buffer, group);
}
matcher.appendTail(buffer);
return buffer.toString();
}
public static class ParamObject
private C obj;
private String collection;
private String item = "item";
private String index;
private String itemFormatter;
private String separator;
private String open;
private String close;
public C getObj() {
return obj;
}
public ParamObject
this.obj = obj;
return this;
}
public String getCollection() {
return collection;
}
public ParamObject
this.collection = collection;
return this;
}
public String getItem() {
return item;
}
public ParamObject
this.item = item;
return this;
}
public String getIndex() {
return index;
}
public ParamObject
this.index = index;
return this;
}
public String getItemFormatter() {
return itemFormatter;
}
public ParamObject
this.itemFormatter = itemFormatter;
return this;
}
public String getSeparator() {
return separator;
}
public ParamObject
this.separator = separator;
return this;
}
public String getOpen() {
return open;
}
public ParamObject
this.open = open;
return this;
}
public String getClose() {
return close;
}
public ParamObject
this.close = close;
return this;
}
public StringBuilder foreach() {
return this.foreach(null);
}
@SuppressWarnings("rawtypes")
public StringBuilder foreach(Interceptor interceptor) {
return ForeachMybatisUtils.foreach(this, interceptor);
}
}
public interface InnerForeach
CharSequence foreach(C innerObj, K index);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static
if (obj == null) {
throw new NullPointerException("object can not is null");
}
if (separator == null) {
separator = "";
}
StringBuilder sqlBuilder = new StringBuilder();
if (open != null) {
sqlBuilder.append(open);
}
int n = 0;
int i = 0;
CharSequence sqlItem = null;
if (obj instanceof Map) {
Set
for (Entry entry : set) {
sqlItem = innerForeach.foreach(entry.getValue(), entry.getKey());
if (sqlItem != null && !sqlItem.toString().trim().isEmpty()) {
if (n > 0) {
sqlBuilder.append(separator);
}
sqlBuilder.append(sqlItem);
n++;
}
i++;
}
} else if (obj instanceof List) {
List list = (List) obj;
for (Object element : list) {
sqlItem = innerForeach.foreach(element, i);
if (sqlItem != null && !sqlItem.toString().trim().isEmpty()) {
if (n > 0) {
sqlBuilder.append(separator);
}
sqlBuilder.append(sqlItem);
n++;
}
i++;
}
} else if (obj.getClass().isArray()) {
List list = Arrays.asList((Object[]) obj);
for (Object element : list) {
sqlItem = innerForeach.foreach(element, i);
if (sqlItem != null && !sqlItem.toString().trim().isEmpty()) {
if (n > 0) {
sqlBuilder.append(separator);
}
sqlBuilder.append(sqlItem);
n++;
}
i++;
}
} else {
throw new IllegalArgumentException("the Type of collection support only Array,List,Map");
}
if (n < 1) {
sqlBuilder.delete(0, sqlBuilder.length());
} else {
if (close != null) {
sqlBuilder.append(close);
}
}
return sqlBuilder;
}
测试
public static void main(String[] args) {
String[][] strs = {{"ddd","jfhd","uyijn"}, {"ddd","jgwhd","uyijn"}, {"ddd","kyugkfd","uyijn"}};
// List
Map
map.put("fwgsss", new String[] {"ddd","jfhd","uyijn"});
map.put("uytr", new String[] {"ddd","jgwhd","uyijn"});
map.put("2", new String[] {"ddd","kyugkfd","uyijn"});
StringBuilder foreach = foreach(map, "wea.arr", "item", "index", "SELECT #{item[1], jdbcType=VARCHAR, javaType=java.lang.String} AS SFF, #{item[2], jdbcType=VARCHAR} AS AT, '${index }' AS FV FROM dual", " UNION ALL ", " (", ")",
new Interceptor
@Override
public boolean preBreakIntercept(Map
// TODO Auto-generated method stub
return false;
}
@Override
public boolean postBreakIntercept(Map
// TODO Auto-generated method stub
return false;
}
@Override
public boolean continueIntercept(Map
// TODO Auto-generated method stub
return false;
}
});
System.out.println(foreach);
StringBuilder foreach1 = foreach(strs, "wea.arr", "item", "index", "SELECT #{item[1], jdbcType=VARCHAR, javaType=java.lang.String} AS SFF, #{item[2], jdbcType=VARCHAR} AS AT FROM dual", " UNION ALL ", " (", ")",
new Interceptor
@Override
public boolean preBreakIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
@Override
public boolean postBreakIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
@Override
public boolean continueIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
});
System.out.println(foreach1);
StringBuilder foreach2 = ForeachMybatisUtils.createParamObject(strs)
.setCollection("wea.arr")
.setItem("item")
.setIndex("index")
.setItemFormatter("SELECT #{item[1], jdbcType=VARCHAR, javaType=java.lang.String} AS SFF, #{item[2], jdbcType=VARCHAR} AS AT FROM dual")
.setSeparator(" UNION ALL ")
.setOpen(" (")
.setClose(")")
.foreach(new ForeachMybatisUtils.Interceptor
@Override
public boolean preBreakIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
@Override
public boolean postBreakIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
@Override
public boolean continueIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
});
System.out.println(foreach2);
StringBuilder foreach3 = ForeachMybatisUtils.foreach(ForeachMybatisUtils.createParamObject(strs)
.setCollection("wea.arr")
.setItem("item")
.setIndex("index")
.setItemFormatter("SELECT #{item[1], jdbcType=VARCHAR, javaType=java.lang.String} AS SFF, #{item[2], jdbcType=VARCHAR} AS AT FROM dual")
.setSeparator(" UNION ALL ")
.setOpen(" (")
.setClose(")"),
new ForeachMybatisUtils.Interceptor
@Override
public boolean preBreakIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
@Override
public boolean postBreakIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
@Override
public boolean continueIntercept(String[][] collection, Integer key, String[] item) {
return false;
}
}
);
System.out.println(foreach3);
}
public static void main(String[] args) {
// @Param("list")
List> lists = new ArrayList
>();
List
list1.add(1);
list1.add(2);
list1.add(3);
lists.add(list1);
List
list2.add(11);
list2.add(12);
list2.add(13);
list2.add(14);
list2.add(19);
lists.add(list2);
List
list3.add(31);
list3.add(32);
list3.add(35);
list3.add(38);
lists.add(list3);
StringBuilder sql = ForeachMybatisUtils.nestedForeach(lists,
" union all ", "select b.id, b.name from (", ") b",
new ForeachMybatisUtils.InnerForeach, Integer>() {
@Override
public CharSequence foreach(List
return ForeachMybatisUtils.createParamObject(innerObj)
.setCollection("list[" + index + "]")
.setItem("item")
.setItemFormatter("#{item}")
.setSeparator(",")
.setOpen("select id, name from table_demo where id in (")
.setClose(")")
.foreach();
}
});
System.out.println(sql);
StringBuilder sql2 = ForeachMybatisUtils.createParamObject(lists)
.setCollection("list")
.setItem("item")
.setItemFormatter("'${item[1]}'")
.setSeparator(",")
.setOpen("select id, name from table_demo where id in (")
.setClose(")")
.foreach();
System.out.println(sql2.toString());
集成进spring后的使用方法
Mapper层
package com.xxx.manage.mapper;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.SelectProvider;
import org.springframework.stereotype.Repository;
import com.xxx.manage.bo.DeviceBO;
import com.xxx.manage.provider.ManageProvider;
@Repository
public interface ManageMapper {
@SelectProvider(type = ManageProvider.class, method = "queryDevices")
List
@SelectProvider(type = ManageProvider.class, method = "queryMap")
List
@SelectProvider(type = ManageProvider.class, method = "queryList")
List
}
Provider层
package com.xxx.manage.provider;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.jdbc.SQL;
import com.xxx.common.util.ForeachMybatisUtils;
public class ManageProvider {
public String queryDevices(Map
@SuppressWarnings("unchecked")
List
SQL sql = new SQL()
.SELECT("TERMINALNUM, ORGCODE, DEVICETYPENO, DEVICENAME")
.FROM("S_DEVICE_INFO")
.WHERE("DEVICETYPENO = #{devicetypeno}");
StringBuilder inBuilder = ForeachMybatisUtils.foreach(list, "list", "item", "#{item}", ", ", "ORGCODE IN (", ")");
if (inBuilder.length() > 0) {
sql.WHERE(inBuilder.toString());
}
return sql.toString();
}
public String queryMap(Map
@SuppressWarnings("unchecked")
Map
StringBuilder sqlBuilder = ForeachMybatisUtils.nestedForeach(map,
" union all ", "select b.id, b.name from (", ") b",
new ForeachMybatisUtils.InnerForeach, String>() {
@Override
public CharSequence foreach(List
return ForeachMybatisUtils.createParamObject(innerObj)
.setCollection("map." + index + "")
.setItem("item")
.setItemFormatter("#{item, jdbcType=NUMERIC}")
.setSeparator(",")
.setOpen("select id, name from table_demo where id in (")
.setClose(")")
.foreach();
}
});
System.out.println(sqlBuilder.toString());
return sqlBuilder.toString();
}
public String queryList(Map
@SuppressWarnings("unchecked")
List
StringBuilder sqlBuilder = ForeachMybatisUtils.nestedForeach(list,
" union all ", "select b.id, b.name from (", ") b",
new ForeachMybatisUtils.InnerForeach
@Override
public CharSequence foreach(Map
return ForeachMybatisUtils.createParamObject(innerObj)
.setCollection("list[" + index + "]")
.setItem("item")
.setItemFormatter("#{item, jdbcType=NUMERIC}")
.setSeparator(",")
.setOpen("select id, name from table_demo where id in (")
.setClose(")")
.foreach();
}
});
System.out.println(sqlBuilder.toString());
return sqlBuilder.toString();
}
}
Ognl问题
高版本的mybatis使用${}注入时,可能会抛出异常
MemberAccess implementation must be provided - null not permitted!
解决方案
创建一个DefaultMemberAccess.java文件
package com.xxx.common.util;
import java.lang.reflect.*;
import java.util.*;
import org.apache.ibatis.ognl.MemberAccess;
public class DefaultMemberAccess implements MemberAccess {
private boolean allowPrivateAccess = false;
private boolean allowProtectedAccess = false;
private boolean allowPackageProtectedAccess = false;
/*===================================================================
Constructors
===================================================================*/
public DefaultMemberAccess(boolean allowAllAccess) {
this(allowAllAccess, allowAllAccess, allowAllAccess);
}
public DefaultMemberAccess(boolean allowPrivateAccess, boolean allowProtectedAccess, boolean allowPackageProtectedAccess) {
super();
this.allowPrivateAccess = allowPrivateAccess;
this.allowProtectedAccess = allowProtectedAccess;
this.allowPackageProtectedAccess = allowPackageProtectedAccess;
}
/*===================================================================
Public methods
===================================================================*/
public boolean getAllowPrivateAccess() {
return allowPrivateAccess;
}
public void setAllowPrivateAccess(boolean value) {
allowPrivateAccess = value;
}
public boolean getAllowProtectedAccess() {
return allowProtectedAccess;
}
public void setAllowProtectedAccess(boolean value) {
allowProtectedAccess = value;
}
public boolean getAllowPackageProtectedAccess() {
return allowPackageProtectedAccess;
}
public void setAllowPackageProtectedAccess(boolean value) {
allowPackageProtectedAccess = value;
}
/*===================================================================
MemberAccess interface
===================================================================*/
@Override
public Object setup(Map context, Object target, Member member, String propertyName) {
Object result = null;
if (isAccessible(context, target, member, propertyName)) {
AccessibleObject accessible = (AccessibleObject)member;
if (!accessible.isAccessible()) {
result = Boolean.FALSE;
accessible.setAccessible(true);
}
}
return result;
}
@Override
public void restore(Map context, Object target, Member member, String propertyName, Object state) {
if (state != null) {
((AccessibleObject)member).setAccessible(((Boolean)state).booleanValue());
}
}
/**
Returns true if the given member is accessible or can be made accessible
by this object.
*/
@Override
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
int modifiers = member.getModifiers();
boolean result = Modifier.isPublic(modifiers);
if (!result) {
if (Modifier.isPrivate(modifiers)) {
result = getAllowPrivateAccess();
} else {
if (Modifier.isProtected(modifiers)) {
result = getAllowProtectedAccess();
} else {
result = getAllowPackageProtectedAccess();
}
}
}
return result;
}
}
改造ForeachMybatisUtils.java类
添加一个静态字段context,
将context插入,Ognl.getValue和Ognl.setValue方法的第二个参数
private static final OgnlContext context = new OgnlContext(null,null,new DefaultMemberAccess(true));
Ognl.getValue(group, context, obj);
Ognl.setValue(group, context, obj, value);
完整的ForeachMybatisUtils.java类
package com.xxx.common.util;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.ibatis.binding.BindingException;
import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlException;
import java.util.Set;
public class ForeachMybatisUtils {
private static final OgnlContext context = new OgnlContext(null,null,new DefaultMemberAccess(true));
private ForeachMybatisUtils() {}
public static
ParamObject
paramObject.setObj(obj);
return paramObject;
}
public static
return foreach(paramObject, null);
}
@SuppressWarnings("rawtypes")
public static
return foreach(paramObject.getObj(), paramObject.getCollection(), paramObject.getItem(), paramObject.getIndex(),
paramObject.getItemFormatter(), paramObject.getSeparator(), paramObject.getOpen(), paramObject.getClose(), interceptor);
}
/**
* itemFormatter部分用法:#{item,jdbcType=VARCHAR},#{item.3345,jdbcType=VARCHAR}其中3345为map的key, ${item}, ${item['3345']}其中3345为map的key
* @param
* @param obj list、map、数组对象
* @param collection 对应xml foreach标签的collection属性
* @param item 对应xml foreach标签的item属性
* @param index 对应xml foreach标签的index属性,但是在itemFormatter中只匹配 ${ } 格式
* @param itemFormatter 对应xml foreach标签内 #{item}
* @param separator 对应xml foreach标签的separator属性
* @param open 对应xml foreach标签的open属性
* @param close 对应xml foreach标签的close属性
* @return 拼接后的动态sql
*/
public static
String separator, String open, String close) {
return foreach(obj, collection, item, null, itemFormatter, separator, open, close, null);
}
public static
String separator, String open, String close) {
return foreach(obj, collection, item, index, itemFormatter, separator, open, close, null);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static
String open, String close, ForeachMybatisUtils.Interceptor interceptor) {
if (obj == null) {
throw new NullPointerException("object cannot be null");
}
if (collection == null || collection.trim().equals("")) {
throw new NullPointerException("collection cannot be blank");
}
if (item == null || item.trim().isEmpty()) {
throw new NullPointerException("item cannot be blank");
}
if (itemFormatter == null) {
throw new NullPointerException("itemFormatter cannot be null, and you can fill #{item},please");
}
collection = collection.trim();
item = item.trim();
if (index != null && item.equals(index.trim())) {
throw new IllegalArgumentException("index cannot be equal to item");
}
Pattern itemDynamicPattern = Pattern.compile("(?<=#\\{)" + item + "(?=[\\s\\S]*\\})");
Pattern itemBindingPattern = Pattern.compile("\\$\\{" + item + "(?:(?:\\.|\\[)\\S+)?\\s*\\}");
Pattern indexStaticPattern = null;
if (index != null && !index.trim().isEmpty() && itemFormatter.contains("${")) {
indexStaticPattern = Pattern.compile("\\$\\{" + index.trim() + "\\s*\\}");
}
if (separator == null) {
separator = "";
}
StringBuilder sqlBuilder = new StringBuilder();
if (open != null) {
sqlBuilder.append(open);
}
String prod = "";
int n = 0;
try {
if (obj instanceof Map) {
Set
for (Entry entry : set) {
String key = (String) entry.getKey();
if (interceptor != null && interceptor.preBreakIntercept(obj, key, entry.getValue())) {
break;
}
if (interceptor != null && interceptor.continueIntercept(obj, key, entry.getValue())) {
continue;
}
if (key.contains(".") || key.contains(" ")) {
throw new IllegalStateException("the Key of map can not contains '.' or ' '");
}
if (n > 0) {
sqlBuilder.append(separator);
}
prod = replaceAll(itemDynamicPattern, itemFormatter, collection + "." + key);
if (indexStaticPattern != null) {
prod = replaceAll(indexStaticPattern, prod, key);
}
prod = replaceBindingMap(itemBindingPattern, item, prod, key, obj);
sqlBuilder.append(prod);
n++;
if (interceptor != null && interceptor.postBreakIntercept(obj, key, entry.getValue())) {
break;
}
}
} else if (obj instanceof List) {
List list = (List) obj;
for (int i = 0, size = list.size(); i < size; i++) {
if (interceptor != null && interceptor.preBreakIntercept(obj, i, list.get(i))) {
break;
}
if (interceptor != null && interceptor.continueIntercept(obj, i, list.get(i))) {
continue;
}
if (n > 0) {
sqlBuilder.append(separator);
}
prod = replaceAll(itemDynamicPattern, itemFormatter, collection + "[" + i + "]");
if (indexStaticPattern != null) {
prod = replaceAll(indexStaticPattern, prod, "" + i);
}
prod = replaceBindingList(itemBindingPattern, item, prod, "" + i, obj);
sqlBuilder.append(prod);
n++;
if (interceptor != null && interceptor.postBreakIntercept(obj, i, list.get(i))) {
break;
}
}
} else if (obj.getClass().isArray()) {
List list = Arrays.asList((Object[]pMwhFoz) obj);
for (int i = 0, size = list.size(); i < size; i++) {
if (interceptor != null && interceptor.preBreakIntercept(obj, i, list.get(i))) {
break;
}
if (interceptor != null && interceptor.continueIntercept(obj, i, list.get(i))) {
continue;
}
if (n > 0) {
sqlBuilder.append(separator);
}
prod = replaceAll(itemDynamicPattern, itemFormatter, collection + "[" + i + "]");
if (indexStaticPattern != null) {
prod = replaceAll(indexStaticPattern, prod, "" + i);
}
prod = replaceBindingList(itemBindingPattern, item, prod, "" + i, obj);
sqlBuilder.append(prod);
n++;
if (interceptor != null && interceptor.postBreakIntercept(obj, i, list.get(i))) {
break;
}
}
} else {
throw new IllegalArgumentException("the Type of collection support only Array,List,Map");
}
} catch (OgnlException e) {
throw new BindingException("ognl exception", e);
}
if (n < 1) {
sqlBuilder.delete(0, sqlBuilder.length());
} else {
if (close != null) {
sqlBuilder.append(close);
}
}
return sqlBuilder;
}
public static interface Interceptor
/**
* for循环内是否执行break语句, break语句在循环内第一行
* @param collection 集合
* @param item 集合元素
* @param key 集合key或下标
* @return 返回true,则执行break语句
*/
boolean preBreakIntercept(C collection, K key, T item);
/**
* for循环内是否执行break语句, break语句在循环内最后一行
* @param collection 集合
* @param item 集合元素
* @param key 集合key或下标
* @return 返回true,则执行break语句
*/
boolean postBreakIntercept(C collection, K key, T item);
/**
* for循环内是否执行continue语句
* @param collection 集合
* @param item 集合元素
* @param key 集合key或下标
* @return 返回true,则执行continue语句
*/
boolean continueIntercept(C collection, K key, T item);
}
private static String replaceAll(Pattern pattern, String itemFormatter, String collection) {
itemFormatter = pattern.matcher(itemFormatter).replaceAll(collection);
return itemFormatter;
}
private static
Matcher matcher = pattern.matcher(itemFormatter);
StringBuffer buffer = new StringBuffer();
matcher.reset();
String group = "";
while (matcher.find()) {
group = matcher.group();
group = group.replaceFirst("\\$\\{" + item, "#root['" + index + "']");
group = group.substring(0, group.length() - 1).trim();
group = String.valueOf(Ognl.getValue(group, context, obj));
matcher.appendReplacement(buffer, group);
}
matcher.appendTail(buffer);
return buffer.toString();
}
private static
Matcher matcher = pattern.matcher(itemFormatter);
StringBuffer buffer = new StringBuffer();
matcher.reset();
String group = "";
while (matcher.find()) {
group = matcher.group();
group = group.replaceFirst("\\$\\{" + item, "#root[" + index + "]");
group = group.substring(0, group.length() - 1).trim();
group = String.valueOf(Ognl.getValue(group, context, obj));
matcher.appendReplacement(buffer, group);
}
matcher.appendTail(buffer);
return buffer.toString();
}
public static class ParamObject
private C obj;
private String collection;
private String item = "item";
private String index;
private String itemFormatter;
private String separator;
private String open;
private String close;
public C getObj() {
return obj;
}
public ParamObject
this.obj = obj;
return this;
}
public String getCollection() {
return collection;
}
public ParamObject
this.collection = collection;
return this;
}
public String getItem() {
return item;
}
public ParamObject
this.item = item;
return this;
}
public String getIndex() {
return index;
}
public ParamObject
this.index = index;
return this;
}
public String getItemFormatter() {
return itemFormatter;
}
public ParamObject
this.itemFormatter = itemFormatter;
return this;
}
public String getSeparator() {
return separator;
}
public ParamObject
this.separator = separator;
return this;
}
public String getOpen() {
return open;
}
public ParamObject
this.open = open;
return this;
}
public String getClose() {
return close;
}
public ParamObject
this.close = close;
return this;
}
public StringBuilder foreach() {
return this.foreach(null);
}
@SuppressWarnings("rawtypes")
public StringBuilder foreach(Interceptor interceptor) {
return ForeachMybatisUtils.foreach(this, interceptor);
}
}
public interface InnerForeach
CharSequence foreach(C innerObj, K index);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static
if (obj == null) {
throw new NullPointerException("object can not is null");
}
if (separator == null) {
separator = "";
}
StringBuilder sqlBuilder = new StringBuilder();
if (open != null) {
sqlBuilder.append(open);
}
int n = 0;
int i = 0;
CharSequence sqlItem = null;
if (obj instanceof Map) {
Set
for (Entry entry : set) {
sqlItem = innerForeach.foreach(entry.getValue(), entry.getKey());
if (sqlItem != null && !sqlItem.toString().trim().isEmpty()) {
if (n > 0) {
sqlBuilder.append(separator);
}
sqlBuilder.append(sqlItem);
n++;
}
i++;
}
} else if (obj instanceof List) {
List list = (List) obj;
for (Object element : list) {
sqlItem = innerForeach.foreach(element, i);
if (sqlItem != null && !sqlItem.toString().trim().isEmpty()) {
if (n > 0) {
sqlBuilder.append(separator);
}
sqlBuilder.append(sqlItem);
n++;
}
i++;
}
} else if (obj.getClass().isArray()) {
List list = Arrays.asList((Object[]) obj);
for (Object element : list) {
sqlItem = innerForeach.foreach(element, i);
if (sqlItem != null && !sqlItem.toString().trim().isEmpty()) {
if (n > 0) {
sqlBuilder.append(separator);
}
sqlBuilder.append(sqlItem);
n++;
}
i++;
}
} else {
throw new IllegalArgumentException("the Type of collection support only Array,List,Map");
}
if (n < 1) {
sqlBuilder.delete(0, sqlBuilder.length());
} else {
if (close != null) {
sqlBuilder.append(close);
}
}
return sqlBuilder;
}
}
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~