JFinal使用技巧-数据库字段大小写转换原理

昨天建项目的时候, 接手了以前项目的代码, 是以大写做统一处理的,  完美运行了好几年....

新项目是需要多数据源支持的, 就增加了几个配置, 最后一个是数据源是配置的小写,,,  然后问题就来....

以前也知道 在 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;
	}

20171228194223.png





评论区

JFinal

2017-03-14 15:32

非常详细,非常感谢你的分享,赞一个 ^_^

Irin.Chan

2017-03-14 15:53

用一下editor的代码编辑功能就完美了,这样看代码有点费劲。

杜福忠

2017-03-14 16:25

@Irin.Chan 是啊用了代码格式, 就不能画底色了, 所以我放弃了用代码格式, 用这个底色主要是划重点, 然后再去看源码会有轻松些

北流家园网

2017-03-14 17:05

版面让人看不下去呀

JFinal

2017-03-14 17:06

@杜福忠 添加源代码的时候,可以点一下源码按钮,直接 copy 进来,发布上来以后会有高亮显示

JFinal

2017-03-14 17:07

对这个贴子本身进行一下修改就好,贴子的内容是随时可以修改的

zhangtianxiao

2017-06-04 16:17

看球不懂////

杜福忠

2017-06-05 09:46

@zhangtianxiao 手册上有来着

热门分享

扫码入社