最近在做项目期间,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"));
}
}虽然不完善,但是勉强够用,权当备忘了。