实现目标
由于在注解版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 staticParamObject createParamObject(C obj) { ParamObject paramObject = new ParamObject (); paramObject.setObj(obj); return paramObject; } public static StringBuilder foreach(ParamObject paramObject) { return foreach(paramObject, null); } @SuppressWarnings("rawtypes") public static StringBuilder foreach(ParamObject paramObject, Interceptor interceptor) { 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 List.class、Map.class、Array * @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 StringBuilder foreach(C obj, String collection, String item, String itemFormatter, String separator, String open, String close) { return foreach(obj, collection, item, null, itemFormatter, separator, open, close, null); } public static StringBuilder foreach(C obj, String collection, String item, String index, String itemFormatter, String separator, String open, String close) { return foreach(obj, collection, item, index, itemFormatter, separator, open, close, null); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static StringBuilder foreach(C obj, String collection, String item, String index, String itemFormatter, String separator, 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 set = ((Map) obj).entrySet(); 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 String replaceBindingMap(Pattern pattern, String item, String itemFormatter, String index, C obj) throws OgnlException { 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 String replaceBindingList(Pattern pattern, String item, String itemFormatter, String index, C obj) throws OgnlException { 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 setObj(C obj) { this.obj = obj; return this; } public String getCollection() { return collection; } public ParamObject setCollection(String collection) { this.collection = collection; return this; } public String getItem() { return item; } public ParamObject setItem(String item) { this.item = item; return this; } public String getIndex() { return index; } public ParamObject setIndex(String index) { this.index = index; return this; } public String getItemFormatter() { return itemFormatter; } public ParamObject setItemFormatter(String itemFormatter) { this.itemFormatter = itemFormatter; return this; } public String getSeparator() { return separator; } public ParamObject setSeparator(String separator) { this.separator = separator; return this; } public String getOpen() { return open; } public ParamObject setOpen(String open) { this.open = open; return this; } public String getClose() { return close; } public ParamObject setClose(String close) { 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 StringBuilder nestedForeach(C obj, String separator, String open, String close, InnerForeach innerForeach) { 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 set = ((Map) obj).entrySet(); 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"}}; // Listlist = Arrays.asList(strs); Map map = new HashMap<>(); 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
集成进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
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(Mapparams) { @SuppressWarnings("unchecked") List
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 staticParamObject createParamObject(C obj) { ParamObject paramObject = new ParamObject (); paramObject.setObj(obj); return paramObject; } public static StringBuilder foreach(ParamObject paramObject) { return foreach(paramObject, null); } @SuppressWarnings("rawtypes") public static StringBuilder foreach(ParamObject paramObject, Interceptor interceptor) { 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 List.class、Map.class、Array * @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 StringBuilder foreach(C obj, String collection, String item, String itemFormatter, String separator, String open, String close) { return foreach(obj, collection, item, null, itemFormatter, separator, open, close, null); } public static StringBuilder foreach(C obj, String collection, String item, String index, String itemFormatter, String separator, String open, String close) { return foreach(obj, collection, item, index, itemFormatter, separator, open, close, null); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static StringBuilder foreach(C obj, String collection, String item, String index, String itemFormatter, String separator, 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 set = ((Map) obj).entrySet(); 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 String replaceBindingMap(Pattern pattern, String item, String itemFormatter, String index, C obj) throws OgnlException { 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 String replaceBindingList(Pattern pattern, String item, String itemFormatter, String index, C obj) throws OgnlException { 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 setObj(C obj) { this.obj = obj; return this; } public String getCollection() { return collection; } public ParamObject setCollection(String collection) { this.collection = collection; return this; } public String getItem() { return item; } public ParamObject setItem(String item) { this.item = item; return this; } public String getIndex() { return index; } public ParamObject setIndex(String index) { this.index = index; return this; } public String getItemFormatter() { return itemFormatter; } public ParamObject setItemFormatter(String itemFormatter) { this.itemFormatter = itemFormatter; return this; } public String getSeparator() { return separator; } public ParamObject setSeparator(String separator) { this.separator = separator; return this; } public String getOpen() { return open; } public ParamObject setOpen(String open) { this.open = open; return this; } public String getClose() { return close; } public ParamObject setClose(String close) { 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 StringBuilder nestedForeach(C obj, String separator, String open, String close, InnerForeach innerForeach) { 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 set = ((Map) obj).entrySet(); 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; } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。