JFinal針對ORACLE的timestamp字段解決辦法

JFinal是個比較不錯的的框架,但JFinal起源時使用mysql數據庫,所以在對數據庫支持方面尚未達到完美。 java

本人使用JFinal有一段時間的,因爲項目的數據庫廣泛採用oracle,在使用oracle過程當中遇到了一些不便之處(好比ORACLE中的自動生成主鍵、oracletimestamp字段返回oracle.sql.timestamp等),幸虧在@JFinal 等人的幫助下已經解決了遇到的問題,本遍就是講如何解決oracletimestamp字段返回oracle.sql.timestamp mysql

  oracle總有些不同凡響的地方,好比它的字段默認沒有自增支持,更可惡的是它的字段返回類型與其餘數據庫返回類型不同,好比說timestamp字段,這貨竟然給咱們返回了oracle.sql.Timestamp,對於oracle自己暫不做評價。 sql

    之前JFinal只用在一個小項目中,並且基本就是我我的在維護,所以碰到timestamp,只能手動的進行一些轉換。但如今JFinal用到了一個大一點的項目中,並且開發人員也不僅我一個,初次你們對JFinal這種簡單的、高效的框架很喜歡,但遇到需手動處理timestamp時,對JFinal有些失望,竟然只能手動轉換。爲了提升你們對JFinal的信心,我就認真研究了一下JFINAL對字段的處理過程,得出結論以下: 數據庫

一、      JFinal在啓動時會將註冊的Model 與數據庫中對應的table進行一一綁定,綁定的過程主要是經過TableInfoBuilder.buildTableInfo()建立一個TableInfo對象,該對象以下: oracle

private String tableName;
	private String primaryKey;
	private String secondaryKey = null;
	
	@SuppressWarnings("unchecked")
	private Map<String, Class<?>> columnTypeMap = DbKit.containerFactory.getAttrsMap();	//	new HashMap<String, Class<?>>();

其實最核心的就是這個columnTypeMap對象,這個MAP記錄着table每一個字段的名字及其類型。 經過跟蹤源代碼發現目前JFinal將默認將Oracle中的timestamp轉換成java.lang.String類型,具體建立TableInfo的方法以下: app

private static TableInfo doBuildTableInfo(TableInfo tableInfo,
	    Connection conn) throws SQLException {
	TableInfo result = tableInfo;

	String sql = DbKit.getDialect().forTableInfoBuilderDoBuildTableInfo(
		tableInfo.getTableName());
	Statement stm = conn.createStatement();
	ResultSet rs = stm.executeQuery(sql);
	ResultSetMetaData rsmd = rs.getMetaData();

	for (int i = 1; i <= rsmd.getColumnCount(); i++) {
	    String colName = rsmd.getColumnName(i);
	    String colClassName = rsmd.getColumnClassName(i);
	    if ("java.lang.String".equals(colClassName)) {
		// varchar, char, enum, set, text, tinytext, mediumtext,
		// longtext
		result.addInfo(colName, java.lang.String.class);
	    } else if ("java.lang.Integer".equals(colClassName)) {
		// int, integer, tinyint, smallint, mediumint
		result.addInfo(colName, java.lang.Integer.class);
	    } else if ("java.lang.Long".equals(colClassName)) {
		// bigint
		result.addInfo(colName, java.lang.Long.class);
	    } else if ("java.sql.Date".equals(colClassName)) {
		// date, year
		result.addInfo(colName, java.sql.Date.class);
	    } else if ("java.lang.Double".equals(colClassName)) {
		// real, double
		result.addInfo(colName, java.lang.Double.class);
	    } else if ("java.lang.Float".equals(colClassName)) {
		// float
		result.addInfo(colName, java.lang.Float.class);
	    } else if ("java.lang.Boolean".equals(colClassName)) {
		// bit
		result.addInfo(colName, java.lang.Boolean.class);
	    } else if ("java.sql.Time".equals(colClassName)) {
		// time
		result.addInfo(colName, java.sql.Time.class);
	    } else if ("java.sql.Timestamp".equals(colClassName)
		    || "oracle.sql.TIMESTAMP".equals(colClassName)) {
		// timestamp, datetime
		result.addInfo(colName, java.sql.Timestamp.class);
	    } else if ("java.math.BigDecimal".equals(colClassName)) {
		// decimal, numeric
		result.addInfo(colName, java.math.BigDecimal.class);
	    } else if ("[B".equals(colClassName)) {
		// binary, varbinary, tinyblob, blob, mediumblob, longblob
		// qjd project: print_info.content varbinary(61800);
		result.addInfo(colName, byte[].class);
	    } else {
		int type = rsmd.getColumnType(i);
		if (type == Types.BLOB) {
		    result.addInfo(colName, byte[].class);
		} else if (type == Types.CLOB || type == Types.NCLOB) {
		    result.addInfo(colName, String.class);
		} else {
		    result.addInfo(colName, String.class);
		}
		// core.TypeConverter
		// throw new RuntimeException("You've got new type to mapping.
		// Please add code in " + TableInfoBuilder.class.getName() + ".
		// The ColumnClassName can't be mapped: " + colClassName);
	    }
	}

	rs.close();
	stm.close();
	return result;
    }


二、      JFinal將數據填充到Model中時,主要執行ModelBuilder. build(ResultSet rs, Class<? extends Model> modelClass)方法,該方法實現以下:其實這個過程JFinal沒有進行干預(除了CLOB、NCLOB、BLOB),數據根據JDBC默認的方式進行返回。 框架

@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);
				
				attrs.put(labelNames[i], value);
			}
			result.add((T)ar);
		}
		return result;
	}


解決思路: 編輯器

         對數據庫的數據操做有2種,set/get,爲了將oracletimestamp改形成與mysqltimestamp同樣,咱們就須要在set/get時進行一些干預,以上2點分別對應set/get操做。經過修改源碼,而後通過測試是發現思路是可行的。 測試

 一、doBuildTableInfoy()方法中在"java.sql.Timestamp".equals(colClassName)增長|| "oracle.sql.TIMESTAMP".equals(colClassName),使其能夠識別oracle.sql.timestamp ui

} else if ("java.sql.Timestamp".equals(colClassName)
		    || "oracle.sql.TIMESTAMP".equals(colClassName)) {
		// timestamp, datetime
		result.addInfo(colName, java.sql.Timestamp.class);

            二、ModelBuilder.build() 中 for (int i = 1; i <= columnCount; i++) {}循環體修改以下:

for (int i = 1; i <= columnCount; i++) {
		Object value;
		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 if (types[i] == Types.TIMESTAMP
			&& DbKit.dialect.isOracle()) {
		    // oracle.sql.timestamp --->java.sql.Timestamp
		    value = rs.getTimestamp(i);
		} else {
		    value = rs.getObject(i);
		}

		attrs.put(labelNames[i], value);
	    }

PS:本人文字功底差,而沒有用得順手的編輯器,你們湊合看看就好了。但願@JFinal 考慮一下是否能將代碼更新到版本庫中。

相關文章
相關標籤/搜索