昨天建项目的时候, 接手了以前项目的代码, 是以大写做统一处理的, 完美运行了好几年....
新项目是需要多数据源支持的, 就增加了几个配置, 最后一个是数据源是配置的小写,,, 然后问题就来....
以前也知道 在 configPlugin 里配置一下就可以统一大小写, 但是这次配了的也没好使.... 在俱乐部咨询了老大@JFinal 图文并茂的给我讲了一下实现的原理, 知道了运行原理再看我的业务代码,就知道问题在哪里了, : 多数据源设置了不同大小写... 现改为统一大写了
(下面笔记是由我有道云粘过来的, 没有整理成Java格式.. 大致看下结构就可以了...)
JFinalConfig { /** * 配置插件 */ public void configPlugin(Plugins me) { ... arp.setContainerFactory(new CaseInsensitiveContainerFactory(false));//false 是大写, true是小写, 不写是区分大小写 } /** * CaseInsensitiveContainerFactory. 内部代码 */ public class CaseInsensitiveContainerFactory implements IContainerFactory { // 这里是静态的 多数据源如果有一个 设置了, 其他地方要用大小写的话就要统一大小写了 private static Boolean toLowerCase = null; public CaseInsensitiveContainerFactory() { } public CaseInsensitiveContainerFactory(boolean toLowerCase) { CaseInsensitiveContainerFactory.toLowerCase = toLowerCase; } // 这里调用下 面的 CaseInsensitiveMap 方法 public Map<String, Object> getAttrsMap() { return new CaseInsensitiveMap<Object>(); } public Map<String, Object> getColumnsMap() { return new CaseInsensitiveMap<Object>(); } public Set<String> getModifyFlagSet() { return new CaseInsensitiveSet(); } // //false 是大写, true是小写, 不调是区分大小写 在这里转换的 private static String convertCase(String key) { if (toLowerCase != null) { return toLowerCase ? key.toLowerCase() : key.toUpperCase(); } else { return key; } } /* * 1:非静态内部类拥有对外部类的所有成员的完全访问权限,包括实例字段和方法, * 为实现这一行为,非静态内部类存储着对外部类的实例的一个隐式引用 * 2:序列化时要求所有的成员变量是Serializable 包括上面谈到的引式引用 * 3:外部类CaseInsensitiveContainerFactory 需要 implements Serializable 才能被序列化 * 4:可以使用静态内部类来实现内部类的序列化,而非让外部类实现 implements Serializable */ public static class CaseInsensitiveSet extends TreeSet<String> { private static final long serialVersionUID = 6236541338642353211L; public CaseInsensitiveSet() { super(String.CASE_INSENSITIVE_ORDER); } public boolean add(String e) { return super.add(convertCase(e)); } public boolean addAll(Collection<? extends String> c) { boolean modified = false; for (String o : c) { if (super.add(convertCase(o))) { modified = true; } } return modified; } } // 重写的 TreeMap 重点在这里 public static class CaseInsensitiveMap<V> extends TreeMap<String, V> { private static final long serialVersionUID = 7482853823611007217L; public CaseInsensitiveMap() { super(String.CASE_INSENSITIVE_ORDER); } // 重写的 TreeMap 重点在这里 convertCase(key) public V put(String key, V value) { return super.put(convertCase(key), value); } public void putAll(Map<? extends String, ? extends V> map) { for (Map.Entry<? extends String, ? extends V> e : map.entrySet()) { super.put(convertCase(e.getKey()), e.getValue()); } } } } /** * Model. * <p> * A clever person solves a problem. * A wise person avoids it. * A stupid person makes it. */ @SuppressWarnings({"rawtypes", "unchecked"}) public abstract class Model<M extends Model> implements Serializable { private static final long serialVersionUID = -990334519496260591L; public static final int FILTER_BY_SAVE = 0; public static final int FILTER_BY_UPDATE = 1; public M dao() { attrs = DaoContainerFactory.daoMap; modifyFlag = DaoContainerFactory.daoSet; return (M)this; } /** * Attributes of this model */ private Map<String, Object> attrs = getAttrsMap(); // getConfig().containerFactory.getAttrsMap(); // new HashMap<String, Object>(); private Map<String, Object> getAttrsMap() { Config config = getConfig(); if (config == null) return DbKit.brokenConfig.containerFactory.getAttrsMap();// 这里调用上面的 getAttrsMap() 方法 return config.containerFactory.getAttrsMap();// 这里调用上面的 getAttrsMap() 方法 } ....... /** * Return attribute Map. * <p> * Danger! The update method will ignore the attribute if you change it directly. * You must use set method to change attribute that update method can handle it. */ protected Map<String, Object> getAttrs() { return attrs; } /** * ModelBuilder. */ public class ModelBuilder { @SuppressWarnings({"rawtypes", "unchecked"}) public static final <T> List<T> build(ResultSet rs, Class<? extends Model> modelClass) throws SQLException, InstantiationException, IllegalAccessException { List<T> result = new ArrayList<T>(); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); String[] labelNames = new String[columnCount + 1]; int[] types = new int[columnCount + 1]; buildLabelNamesAndTypes(rsmd, labelNames, types); while (rs.next()) { Model<?> ar = modelClass.newInstance(); Map<String, Object> attrs = ar.getAttrs(); for (int i=1; i<=columnCount; i++) { Object value; if (types[i] < Types.BLOB) value = rs.getObject(i); else if (types[i] == Types.CLOB) value = handleClob(rs.getClob(i)); else if (types[i] == Types.NCLOB) value = handleClob(rs.getNClob(i)); else if (types[i] == Types.BLOB) value = handleBlob(rs.getBlob(i)); else value = rs.getObject(i); // 这个 put 就是上面 CaseInsensitiveMap 重写的那个map 的 put 方法 //这里使用了内部类 用Debug追代码的时候要按两次才能到达CaseInsensitiveMap 的方法, 表示我第一次追的时候看见是底层了以为完了 就直接F6了,,没有追进去.... attrs.put(labelNames[i], value); } result.add((T)ar); } return result; }