昨天建项目的时候, 接手了以前项目的代码, 是以大写做统一处理的, 完美运行了好几年....
新项目是需要多数据源支持的, 就增加了几个配置, 最后一个是数据源是配置的小写,,, 然后问题就来....
以前也知道 在 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;
}