diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java index 144d4e68d70cd0ac01f976d896ae2c81bfa4e902..6520109ec4f01c1f48ac256708a551e25e4b078e 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java @@ -28,6 +28,9 @@ import org.ssssssss.script.parsing.ast.statement.ClassConverter; import org.ssssssss.script.runtime.RuntimeContext; import java.beans.Transient; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; import java.sql.*; import java.util.*; import java.util.function.Function; @@ -39,6 +42,8 @@ import java.util.function.Function; */ @MagicModule("db") public class SQLModule implements DynamicAttribute, DynamicModule { + private final static List CALL_RESULT_TYPE_HANDLERS = new ArrayList<>(); + static { try { ClassConverter.register("sql", (value, params) -> { @@ -58,6 +63,8 @@ public class SQLModule implements DynamicAttribute, Dynami } catch (Exception ignored) { } + + CALL_RESULT_TYPE_HANDLERS.add(new CallResultClobTypeHandler()); } private MagicDynamicDataSource dynamicDataSource; @@ -775,33 +782,82 @@ public class SQLModule implements DynamicAttribute, Dynami return key; } } - - @Comment("调用存储过程") - public Object call(RuntimeContext runtimeContext, - @Comment(name = "sqlOrXml", value = "`SQL`语句或`xml`") String sqlOrXml) { + + @Comment("调用存储过程") + public Object call(RuntimeContext runtimeContext, + @Comment(name = "sqlOrXml", value = "`SQL`语句或`xml`") String sqlOrXml) { assertDatasourceNotNull(); BoundSql boundSql = new BoundSql(runtimeContext, sqlOrXml, Collections.emptyMap(), this); - return boundSql.execute(this.sqlInterceptors, () -> this.dataSourceNode.getJdbcTemplate().call( - con -> { - CallableStatement statement = con.prepareCall(boundSql.getSql()); - Object[] parameters = boundSql.getParameters(); - for (int i = 0, size = parameters.length; i < size; i++) { - Object parameter = parameters[i]; - if (parameter instanceof SqlOutParameter) { - SqlOutParameter sop = (SqlOutParameter)parameter; - statement.registerOutParameter(i + 1, sop.getSqlType()); - } else if(parameter instanceof SqlParameterValue){ - SqlParameterValue spv = (SqlParameterValue)parameter; - if(spv.getName() != null){ - statement.registerOutParameter(i + 1, spv.getSqlType()); + return boundSql.execute(this.sqlInterceptors, () -> { + Map resultMap = this.dataSourceNode.getJdbcTemplate().call( + con -> { + CallableStatement statement = con.prepareCall(boundSql.getSql()); + Object[] parameters = boundSql.getParameters(); + for (int i = 0, size = parameters.length; i < size; i++) { + Object parameter = parameters[i]; + if (parameter instanceof SqlOutParameter) { + SqlOutParameter sop = (SqlOutParameter)parameter; + statement.registerOutParameter(i + 1, sop.getSqlType()); + } else if(parameter instanceof SqlParameterValue){ + SqlParameterValue spv = (SqlParameterValue)parameter; + if(spv.getName() != null){ + statement.registerOutParameter(i + 1, spv.getSqlType()); + } + statement.setObject(i + 1, spv.getValue()); + } else { + statement.setObject(i + 1, parameter); } - statement.setObject(i + 1, spv.getValue()); - } else { - statement.setObject(i + 1, parameter); } + return statement; + }, boundSql.getDeclareParameters()); + + for (Map.Entry entry : resultMap.entrySet()) { + Object value = entry.getValue(); + for (CallResultTypeHandler callResultTypeHandler : CALL_RESULT_TYPE_HANDLERS) { + if (!callResultTypeHandler.support(value)) { + continue; } - return statement; - }, boundSql.getDeclareParameters())); - } - + try { + entry.setValue(callResultTypeHandler.handle(value)); + } catch (Exception e) { + throw new RuntimeException(String.format("[%s]出参转换失败", entry.getKey()), e); + } + break; + } + } + + return resultMap; + }); + } + + public static interface CallResultTypeHandler { + public boolean support(Object value); + + public Object handle(Object value) throws SQLException, IOException; + } + + /** + * 处理 Clob 类型,将 Clob 转换为 String + */ + private static class CallResultClobTypeHandler implements CallResultTypeHandler { + @Override + public boolean support(Object value) { + return value instanceof Clob; + } + + @Override + public Object handle(Object value) throws SQLException, IOException { + Clob clob = (Clob) value; + try (Reader reader = clob.getCharacterStream(); + BufferedReader bufferedReader = new BufferedReader(reader)) { + StringBuilder stringBuilder = new StringBuilder(); + int read; + char[] chars = new char[1024]; + while ((read = bufferedReader.read(chars)) != -1) { + stringBuilder.append(chars, 0, read); + } + return stringBuilder.toString(); + } + } + } }