JFINAL调用oracle存储过程的一种方式

        最近在做项目期间,oracle存储过程需要得比较多,在网上找了很多关于jfinal调用oracle的存储过程方法,感觉都不是很好,借鉴大牛们的思想,自己写了一个较为通用的ICallback接口实现,以下是代码:

public class TestICallback implements ICallback {

	private String sql;
	private Object[] paras;
	private String proc_name;
	private List<Record> ParamAttrs;
	private Kv result = Kv.create();
	private Kv result_index = Kv.create();
	private Kv result_name = Kv.create();

	public TestICallback(String proc_name, Kv proc_param) {
		this.sql = "{call " + Db.getSqlPara(proc_name, proc_param).getSql() + " }";
	this.paras = Db.getSqlPara(proc_name, proc_param).getPara();
	this.proc_name = getProcName(Db.getSqlPara(proc_name, proc_param).getSql());
	this.ParamAttrs = getParamAttrs(this.proc_name);
}

@SuppressWarnings("unchecked")
public Object call(Connection conn) throws SQLException {
	if (ParamAttrs.size() == paras.length) {
		CallableStatement proc = conn.prepareCall(sql);
		for (int i = 0; i < paras.length; i++) {
			if (ParamAttrs.get(i).getStr("IN_OUT").equals("IN")) {
	proc.setObject(i + 1, paras[i]);
} else {
	if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("CHAR")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.CHAR);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("DATE")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.DATE);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("FLOAT")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.FLOAT);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("LONG")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.NUMBER);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("NCHAR")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.NCHAR);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("NUMBER")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.NUMBER);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("NVARCHAR2")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.NVARCHAR);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("VARCHAR2")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.NVARCHAR);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("REF")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.REF);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("REF CURSOR")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.CURSOR);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("TABLE")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.PLSQL_INDEX_TABLE);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("TIME")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.TIME);
}
if (ParamAttrs.get(i).getStr("DATA_TYPE").equals("TIMESTAMP")) {
	proc.registerOutParameter(i + 1, oracle.jdbc.OracleTypes.TIMESTAMP);
}
result_index.set(result_index.size(), i + 1);
result_name.set(result_name.size(), ParamAttrs.get(i).get("ARGUMENT_NAME"));
	}
}
proc.execute();
for (int j = 0; j < result_index.size(); j++) {
	if (ParamAttrs.get(result_index.getInt(j) - 1).getStr("DATA_TYPE").equals("REF CURSOR")) {
		List<Record> results = new ArrayList<Record>();
		ResultSet rs = null;
		ResultSetMetaData rsmd = null;
		rs = (ResultSet) proc.getObject(result_index.getInt(j));
		if (rs != null) {
			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()) {
				Record record = new Record();
				CPI.setColumnsMap(record, DbKit.getConfig().getContainerFactory().getColumnsMap());
				Map<String, Object> columns = record.getColumns();
				for (int i=1; i<=columnCount; i++) {
					Object value;
					if (types[i] < Types.DATE) {
						value = rs.getObject(i);
					} else {
						if (types[i] == Types.TIMESTAMP) {
							value = rs.getTimestamp(i);
						} else if (types[i] == Types.DATE) {
							value = rs.getDate(i);
						} else if (types[i] == Types.CLOB) {
							value = ModelBuilder.me.handleClob(rs.getClob(i));
						} else if (types[i] == Types.NCLOB) {
							value = ModelBuilder.me.handleClob(rs.getNClob(i));
						} else if (types[i] == Types.BLOB) {
							value = ModelBuilder.me.handleBlob(rs.getBlob(i));
						} else {
							value = rs.getObject(i);
						}
					}					
					columns.put(labelNames[i], value);
				}
				results.add(record);
			}
		}
				result.set(result_name.get(j),results);
} else {
	result.set(result_name.get(j), proc.getObject(result_index.getInt(j)));
}
}
		return proc;
	} else {
		return null;
	}
}

public Kv getResult() {
	return result;
}

private String getProcName(String str) {
	if (str.contains("(")) {
str = str.substring(0, str.indexOf("(")).trim();
	} else {
		str = str.trim();
	}
	return str;
}

/*  由于是oracle 打算采用这种方式获取参数与顺序
	#sql("getParamAttr")	
		SELECT DD.POSITION,
	       DD.DATA_TYPE,
	       dd.argument_name,
	       DD.in_out
		  FROM ALL_ARGUMENTS dd
		 where upper(dd.object_name) = upper(#para(procName))
		 or upper(DD.OWNER||'.'||dd.object_name) = upper(#para(procName)) 
		 order by dd.position
	#end
*/
private List<Record> getParamAttrs(String procName) {

	return Db.find(Db.getSqlPara("getParamAttr", Kv.by("procName", procName)));
	}
	
	public void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {
		for (int i=1; i<labelNames.length; i++) {
			labelNames[i] = rsmd.getColumnLabel(i);
			types[i] = rsmd.getColumnType(i);
		}
	}
}

调用的时候,我用的是:

public class TextExec {
	public static Object execute(String proc_name,Kv proc_param){
		TestICallback callback = new TestICallback(proc_name,proc_param);
		Db.execute(callback);
		return callback.getResult();
	}
}

取数据的时候可以如下取数据:

/*
#sql("TestSql")	
  blade.pro_test(#para(i_id),#para(s_value),#para(o_id),#para(o_lst))
#end
*/

public class TestController extends Controller {

	public void index() {
		Kv con = Kv.by("i_id", "333").set("s_value", "lsadf").set("o_id", new Object()).set("o_lst", new Object());
		Kv result = (Kv) TextExec.execute("TestSql", con);
		@SuppressWarnings("unchecked")
		List<Record> records = (List<Record>) (result.containsKey("MYCUR") ? result.get("MYCUR") : null);
		setAttr("Users", records);
		render(new XmlRender("users.xml"));
	}
}

虽然不完善,但是勉强够用,权当备忘了。

评论区

JFinal

2018-01-19 17:34

这个问题的分享很稀少,十分有价值,感谢你的分享,收藏、点赞

JFinal

2018-01-19 17:35

此外,jfinal 3.4 针对 oracle 的支持做了很细致的增强,有兴趣的可以先用上,代码在这里:
https://gitee.com/jfinal/jfinal

这个代码可以直接使用,严格测试过

一直讨嫌

2018-01-19 17:37

@JFinal 感谢波总 你才是我们学习的榜样!

一直讨嫌

2018-01-19 17:41

@JFinal 我先看看3.4的增强 也许项目用得上 谢谢波总

JFinal

2018-01-19 17:46

@一直讨嫌 用的时候,将 pom.xml 里头的一个 skip 配置改为 true, 然后用:
mvn install

将项目安装到本地,最后改下 jfinal 版本号为: 3.4-SNAPSHOT 就可以使用了

jfinal 3.4 主要是对 oracle 的 Timestamp 以及与日期有关的类型做了非常细致的处理,不再需要自己做什么事情了

一直讨嫌

2018-01-19 18:05

@JFinal 好的 我项目刚好用得到。非常感谢!O了。

JFinal

2018-01-19 18:14

@一直讨嫌 已经有几位用户在用了,相当顺滑,这个版本是对 oracle 支持最好的版本,强烈推荐

热门分享

扫码入社