From 0c57376d2ed4780783f03afeadff8acd95a21d0b Mon Sep 17 00:00:00 2001 From: datagear Date: Mon, 16 Dec 2019 21:05:45 +0800 Subject: [PATCH] =?UTF-8?q?[analysis]=E5=AE=8C=E5=96=84DataSetFactory?= =?UTF-8?q?=E5=8F=8A=E7=9B=B8=E5=85=B3API=EF=BC=8C=E6=B7=BB=E5=8A=A0SqlDat?= =?UTF-8?q?aSetFactory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datagear/analysis/DashboardWidget.java | 2 +- .../datagear/analysis/DataSetException.java | 39 + .../org/datagear/analysis/DataSetFactory.java | 3 +- .../support/AbstractDataSetFactory.java | 55 ++ .../DataSetParamNotFountException.java | 58 ++ .../DataSetParamValueRequiredException.java | 57 ++ .../support/ParameterSqlResolver.java | 139 ++++ .../SqlDataSetConnectionException.java | 24 + .../analysis/support/SqlDataSetFactory.java | 669 ++++++++++++++++++ .../support/UnsupportedSqlTypeException.java | 57 ++ ...HtmlFreemarkerDashboardWidgetRenderer.java | 10 +- .../analysis/support/DBTestSupport.java | 74 ++ .../support/SqlDataSetFactoryTest.java | 128 ++++ 13 files changed, 1307 insertions(+), 8 deletions(-) create mode 100644 datagear-analysis/src/main/java/org/datagear/analysis/DataSetException.java create mode 100644 datagear-analysis/src/main/java/org/datagear/analysis/support/DataSetParamNotFountException.java create mode 100644 datagear-analysis/src/main/java/org/datagear/analysis/support/DataSetParamValueRequiredException.java create mode 100644 datagear-analysis/src/main/java/org/datagear/analysis/support/ParameterSqlResolver.java create mode 100644 datagear-analysis/src/main/java/org/datagear/analysis/support/SqlDataSetConnectionException.java create mode 100644 datagear-analysis/src/main/java/org/datagear/analysis/support/SqlDataSetFactory.java create mode 100644 datagear-analysis/src/main/java/org/datagear/analysis/support/UnsupportedSqlTypeException.java create mode 100644 datagear-analysis/src/test/java/org/datagear/analysis/support/DBTestSupport.java create mode 100644 datagear-analysis/src/test/java/org/datagear/analysis/support/SqlDataSetFactoryTest.java diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/DashboardWidget.java b/datagear-analysis/src/main/java/org/datagear/analysis/DashboardWidget.java index 198901a5..cd065f7a 100644 --- a/datagear-analysis/src/main/java/org/datagear/analysis/DashboardWidget.java +++ b/datagear-analysis/src/main/java/org/datagear/analysis/DashboardWidget.java @@ -22,5 +22,5 @@ public interface DashboardWidget extends Identifiable * @return * @throws RenderException */ - public abstract Dashboard render(T renderContext) throws RenderException; + Dashboard render(T renderContext) throws RenderException; } diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/DataSetException.java b/datagear-analysis/src/main/java/org/datagear/analysis/DataSetException.java new file mode 100644 index 00000000..400c1d3e --- /dev/null +++ b/datagear-analysis/src/main/java/org/datagear/analysis/DataSetException.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 datagear.tech. All Rights Reserved. + */ + +/** + * + */ +package org.datagear.analysis; + +/** + * 数据集异常。 + * + * @author datagear@163.com + * + */ +public class DataSetException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + public DataSetException() + { + super(); + } + + public DataSetException(String message) + { + super(message); + } + + public DataSetException(Throwable cause) + { + super(cause); + } + + public DataSetException(String message, Throwable cause) + { + super(message, cause); + } +} diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/DataSetFactory.java b/datagear-analysis/src/main/java/org/datagear/analysis/DataSetFactory.java index 0ffdad73..020bb421 100644 --- a/datagear-analysis/src/main/java/org/datagear/analysis/DataSetFactory.java +++ b/datagear-analysis/src/main/java/org/datagear/analysis/DataSetFactory.java @@ -27,6 +27,7 @@ public interface DataSetFactory extends Identifiable * * @param dataSetParamValues * @return + * @throws DataSetException */ - DataSet getDataSet(DataSetParamValues dataSetParamValues); + DataSet getDataSet(DataSetParamValues dataSetParamValues) throws DataSetException; } diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/support/AbstractDataSetFactory.java b/datagear-analysis/src/main/java/org/datagear/analysis/support/AbstractDataSetFactory.java index 280cd5e3..9c7440e7 100644 --- a/datagear-analysis/src/main/java/org/datagear/analysis/support/AbstractDataSetFactory.java +++ b/datagear-analysis/src/main/java/org/datagear/analysis/support/AbstractDataSetFactory.java @@ -7,8 +7,12 @@ */ package org.datagear.analysis.support; +import java.util.ArrayList; +import java.util.List; + import org.datagear.analysis.AbstractIdentifiable; import org.datagear.analysis.DataSetFactory; +import org.datagear.analysis.DataSetParam; import org.datagear.analysis.DataSetParams; /** @@ -42,4 +46,55 @@ public abstract class AbstractDataSetFactory extends AbstractIdentifiable implem { this.dataSetParams = dataSetParams; } + + /** + * 获取指定名称列表的{@linkplain DataSetParam}列表,找不到将抛出{@linkplain DataSetParamNotFountException}。 + * + * @param names + * @return + * @throws DataSetParamNotFountException + */ + protected List getDataSetParam(List names) throws DataSetParamNotFountException + { + List dataSetParams = new ArrayList(names.size()); + + for (String name : names) + dataSetParams.add(getDataSetParamNotNull(name)); + + return dataSetParams; + } + + /** + * 获取指定名称的{@linkplain DataSetParam},找不到将抛出{@linkplain DataSetParamNotFountException}。 + * + * @param name + * @return + */ + protected DataSetParam getDataSetParamNotNull(String name) throws DataSetParamNotFountException + { + DataSetParam dataSetParam = getDataSetParam(name); + + if (dataSetParam == null) + throw new DataSetParamNotFountException(name); + + return dataSetParam; + } + + /** + * 获取指定名称的{@linkplain DataSetParam},找不到则返回{@code null}。 + * + * @param name + * @return + */ + protected DataSetParam getDataSetParam(String name) + { + DataSetParam dataSetParam = null; + + DataSetParams dataSetParams = getDataSetParams(); + + if (dataSetParams != null) + dataSetParam = dataSetParams.getByName(name); + + return dataSetParam; + } } diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/support/DataSetParamNotFountException.java b/datagear-analysis/src/main/java/org/datagear/analysis/support/DataSetParamNotFountException.java new file mode 100644 index 00000000..09698b97 --- /dev/null +++ b/datagear-analysis/src/main/java/org/datagear/analysis/support/DataSetParamNotFountException.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 datagear.tech. All Rights Reserved. + */ + +/** + * + */ +package org.datagear.analysis.support; + +import org.datagear.analysis.DataSetException; +import org.datagear.analysis.DataSetParam; + +/** + * 指定名称的{@linkplain DataSetParam}不存在异常。 + * + * @author datagear@163.com + * + */ +public class DataSetParamNotFountException extends DataSetException +{ + private static final long serialVersionUID = 1L; + + private String name; + + public DataSetParamNotFountException(String name) + { + super(); + this.name = name; + } + + public DataSetParamNotFountException(String name, String message) + { + super(message); + this.name = name; + } + + public DataSetParamNotFountException(String name, Throwable cause) + { + super(cause); + this.name = name; + } + + public DataSetParamNotFountException(String name, String message, Throwable cause) + { + super(message, cause); + this.name = name; + } + + public String getName() + { + return name; + } + + protected void setName(String name) + { + this.name = name; + } +} diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/support/DataSetParamValueRequiredException.java b/datagear-analysis/src/main/java/org/datagear/analysis/support/DataSetParamValueRequiredException.java new file mode 100644 index 00000000..62a23e23 --- /dev/null +++ b/datagear-analysis/src/main/java/org/datagear/analysis/support/DataSetParamValueRequiredException.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018 datagear.tech. All Rights Reserved. + */ + +/** + * + */ +package org.datagear.analysis.support; + +import org.datagear.analysis.DataSetException; + +/** + * 指定参数值必填异常。 + * + * @author datagear@163.com + * + */ +public class DataSetParamValueRequiredException extends DataSetException +{ + private static final long serialVersionUID = 1L; + + private String name; + + public DataSetParamValueRequiredException(String name) + { + super(); + this.name = name; + } + + public DataSetParamValueRequiredException(String name, String message) + { + super(message); + this.name = name; + } + + public DataSetParamValueRequiredException(String name, Throwable cause) + { + super(cause); + this.name = name; + } + + public DataSetParamValueRequiredException(String name, String message, Throwable cause) + { + super(message, cause); + this.name = name; + } + + public String getName() + { + return name; + } + + protected void setName(String name) + { + this.name = name; + } +} diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/support/ParameterSqlResolver.java b/datagear-analysis/src/main/java/org/datagear/analysis/support/ParameterSqlResolver.java new file mode 100644 index 00000000..aaabd216 --- /dev/null +++ b/datagear-analysis/src/main/java/org/datagear/analysis/support/ParameterSqlResolver.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018 datagear.tech. All Rights Reserved. + */ + +/** + * + */ +package org.datagear.analysis.support; + +import java.util.ArrayList; +import java.util.List; + +import org.datagear.util.expression.Expression; +import org.datagear.util.expression.ExpressionResolver; + +/** + * 参数SQL解析器。 + *

+ * 它解析包含...${parameter0}...${parameter1}的SQL语句,并将它们替换为JDBC规范的?占位符。 + *

+ * + * @author datagear@163.com + * + */ +public class ParameterSqlResolver +{ + private ExpressionResolver expressionResolver; + + public ParameterSqlResolver() + { + super(); + this.expressionResolver = new ExpressionResolver(); + this.expressionResolver.setStartIdentifier(ExpressionResolver.DEFAULT_START_IDENTIFIER_DOLLAR); + this.expressionResolver.setEndIdentifier(ExpressionResolver.DEFAULT_END_IDENTIFIER); + } + + protected ExpressionResolver getExpressionResolver() + { + return expressionResolver; + } + + protected void setExpressionResolver(ExpressionResolver expressionResolver) + { + this.expressionResolver = expressionResolver; + } + + /** + * 解析包含参数的SQL语句。 + * + * @param parameterSql + * @return + */ + public ParameterSql resolve(String parameterSql) + { + List expressions = this.expressionResolver.resolve(parameterSql); + + if (expressions == null || expressions.isEmpty()) + return new ParameterSql(parameterSql); + + List parameters = new ArrayList(expressions.size()); + + List values = new ArrayList(expressions.size()); + + for (Expression expression : expressions) + { + parameters.add(expression.getContent()); + values.add("?"); + } + + String sql = this.expressionResolver.evaluate(parameterSql, expressions, values, "?"); + + return new ParameterSql(sql, parameters); + } + + /** + * 参数SQL解析结果。 + *

+ * 它的{@linkplain #getSql()}中的...${parameter}...已被替换为?。 + *

+ * + * @author datagear@163.com + * + */ + public static class ParameterSql + { + private String sql; + + private List parameters; + + public ParameterSql() + { + super(); + } + + public ParameterSql(String sql) + { + super(); + this.sql = sql; + } + + public ParameterSql(String sql, List parameters) + { + super(); + this.sql = sql; + this.parameters = parameters; + } + + public String getSql() + { + return sql; + } + + public void setSql(String sql) + { + this.sql = sql; + } + + public boolean hasParameter() + { + return (this.parameters != null && !this.parameters.isEmpty()); + } + + public List getParameters() + { + return parameters; + } + + public void setParameters(List parameters) + { + this.parameters = parameters; + } + + @Override + public String toString() + { + return getClass().getSimpleName() + " [sql=" + sql + ", parameters=" + parameters + "]"; + } + } +} diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/support/SqlDataSetConnectionException.java b/datagear-analysis/src/main/java/org/datagear/analysis/support/SqlDataSetConnectionException.java new file mode 100644 index 00000000..023b70db --- /dev/null +++ b/datagear-analysis/src/main/java/org/datagear/analysis/support/SqlDataSetConnectionException.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 datagear.tech. All Rights Reserved. + */ + +/** + * + */ +package org.datagear.analysis.support; + +import org.datagear.analysis.DataSetException; + +/** + * @author datagear@163.com + * + */ +public class SqlDataSetConnectionException extends DataSetException +{ + private static final long serialVersionUID = 1L; + + public SqlDataSetConnectionException(Throwable cause) + { + super(cause); + } +} diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/support/SqlDataSetFactory.java b/datagear-analysis/src/main/java/org/datagear/analysis/support/SqlDataSetFactory.java new file mode 100644 index 00000000..4059b101 --- /dev/null +++ b/datagear-analysis/src/main/java/org/datagear/analysis/support/SqlDataSetFactory.java @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2018 datagear.tech. All Rights Reserved. + */ + +/** + * + */ +package org.datagear.analysis.support; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.datagear.analysis.ColumnMeta; +import org.datagear.analysis.DataSet; +import org.datagear.analysis.DataSetException; +import org.datagear.analysis.DataSetFactory; +import org.datagear.analysis.DataSetMeta; +import org.datagear.analysis.DataSetParam; +import org.datagear.analysis.DataSetParamValues; +import org.datagear.analysis.DataSetParams; +import org.datagear.analysis.DataType; +import org.datagear.analysis.support.ParameterSqlResolver.ParameterSql; +import org.datagear.util.JdbcUtil; +import org.datagear.util.StringUtil; +import org.datagear.util.resource.ConnectionFactory; + +/** + * SQL {@linkplain DataSetFactory}。 + *

+ * 它的{@linkplain #setSql(String)}中可以包含${parameter}格式的参数(parameter必须是在{@linkplain #getDataSetParams()}中预定义的), + * 在{@linkplain #getDataSet(DataSetParamValues)}中会被替换为具体的参数值。 + *

+ * + * @author datagear@163.com + * + */ +public class SqlDataSetFactory extends AbstractDataSetFactory +{ + protected static final ParameterSqlResolver PARAMETER_SQL_RESOLVER = new ParameterSqlResolver(); + + private ConnectionFactory connectionFactory; + + private String sql; + + public SqlDataSetFactory() + { + super(); + } + + public SqlDataSetFactory(String id, DataSetParams dataSetParams, ConnectionFactory connectionFactory, String sql) + { + super(id, dataSetParams); + this.connectionFactory = connectionFactory; + this.sql = sql; + } + + public ConnectionFactory getConnectionFactory() + { + return connectionFactory; + } + + public void setConnectionFactory(ConnectionFactory connectionFactory) + { + this.connectionFactory = connectionFactory; + } + + public String getSql() + { + return sql; + } + + public void setSql(String sql) + { + this.sql = sql; + } + + @Override + public DataSet getDataSet(DataSetParamValues dataSetParamValues) throws DataSetException + { + Connection cn = null; + + try + { + cn = getConnectionFactory().get(); + } + catch (Exception e) + { + JdbcUtil.closeConnection(cn); + throw new SqlDataSetConnectionException(e); + } + + try + { + return getDataSet(cn, this.sql, dataSetParamValues); + } + finally + { + try + { + getConnectionFactory().release(cn); + } + catch (Exception e) + { + } + } + } + + /** + * 获取指定SQL的{@linkplain DataSet}。 + * + * @param cn + * @param sql + * @param dataSetParamValues + * @return + */ + protected DataSet getDataSet(Connection cn, String sql, DataSetParamValues dataSetParamValues) + throws DataSetException + { + ParameterSql parameterSql = resolveParameterSql(sql); + + sql = parameterSql.getSql(); + List dataSetParams = (parameterSql.hasParameter() ? getDataSetParam(parameterSql.getParameters()) + : null); + + Statement st = null; + ResultSet rs = null; + + try + { + if (dataSetParams == null || dataSetParams.isEmpty()) + { + st = cn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = st.executeQuery(sql); + } + else + { + PreparedStatement pst = cn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY); + setPreparedStatementParams(pst, dataSetParams, dataSetParamValues); + + st = pst; + rs = pst.executeQuery(); + } + + return toDataSet(cn, rs); + } + catch (SQLException e) + { + throw new DataSetException(e); + } + finally + { + JdbcUtil.closeResultSet(rs); + JdbcUtil.closeStatement(st); + } + } + + /** + * 设置参数值。 + * + * @param pst + * @param dataSetParams + * @param dataSetParamValues + * @throws SQLException + */ + protected void setPreparedStatementParams(PreparedStatement pst, List dataSetParams, + DataSetParamValues dataSetParamValues) throws SQLException, DataSetException + { + for (int i = 0, len = dataSetParams.size(); i < len; i++) + { + DataSetParam dataSetParam = dataSetParams.get(i); + Object value = dataSetParamValues.get(dataSetParam.getName()); + if (value == null) + value = dataSetParam.getDefaultValue(); + + if (value == null && dataSetParam.isRequired()) + throw new DataSetParamValueRequiredException(dataSetParam.getName()); + + setPreparedStatementParam(pst, i + 1, dataSetParam, value); + } + } + + /** + * 设置参数值。 + * + * @param pst + * @param parameterIndex + * @param dataSetParam + * @param paramValue + * @throws SQLException + * @throws DataSetException + */ + protected void setPreparedStatementParam(PreparedStatement pst, int parameterIndex, DataSetParam dataSetParam, + Object paramValue) throws SQLException, DataSetException + { + DataType dataType = dataSetParam.getType(); + + if (DataType.STRING.equals(dataType)) + { + String value = null; + + if (paramValue == null) + ; + else if (paramValue instanceof String) + value = (String) paramValue; + else + throw new DataSetException("Type [" + paramValue.getClass().getName() + "] for [" + DataType.STRING + + "] is not supported"); + + if (paramValue == null) + pst.setNull(parameterIndex, Types.VARCHAR); + else + pst.setString(parameterIndex, value); + } + else if (DataType.BOOLEAN.equals(dataType)) + { + boolean value = false; + + if (paramValue == null) + ; + else if (paramValue instanceof Boolean) + value = ((Boolean) paramValue).booleanValue(); + else + throw new DataSetException("Type [" + paramValue.getClass().getName() + "] for [" + DataType.BOOLEAN + + "] is not supported"); + + if (paramValue == null) + pst.setNull(parameterIndex, Types.BOOLEAN); + else + pst.setBoolean(parameterIndex, value); + } + else if (DataType.INTEGER.equals(dataType)) + { + if (paramValue == null) + pst.setNull(parameterIndex, Types.INTEGER); + else if (paramValue instanceof BigInteger) + pst.setBigDecimal(parameterIndex, new BigDecimal((BigInteger) paramValue)); + else if (paramValue instanceof Long) + pst.setLong(parameterIndex, (Long) paramValue); + else if (paramValue instanceof Number) + pst.setInt(parameterIndex, ((Number) paramValue).intValue()); + else + throw new DataSetException("Type [" + paramValue.getClass().getName() + "] for [" + DataType.INTEGER + + "] is not supported"); + } + else if (DataType.DECIMAL.equals(dataType)) + { + if (paramValue == null) + pst.setNull(parameterIndex, Types.DOUBLE); + else if (paramValue instanceof BigDecimal) + pst.setBigDecimal(parameterIndex, (BigDecimal) paramValue); + else if (paramValue instanceof BigInteger) + pst.setBigDecimal(parameterIndex, new BigDecimal((BigInteger) paramValue)); + else if (paramValue instanceof Double) + pst.setDouble(parameterIndex, (Double) paramValue); + else if (paramValue instanceof Float) + pst.setFloat(parameterIndex, (Float) paramValue); + else if (paramValue instanceof Number) + pst.setDouble(parameterIndex, ((Number) paramValue).doubleValue()); + else + throw new DataSetException("Type [" + paramValue.getClass().getName() + "] for [" + DataType.DECIMAL + + "] is not supported"); + } + else if (DataType.DATE.equals(dataType)) + { + if (paramValue == null) + pst.setNull(parameterIndex, Types.DATE); + else if (paramValue instanceof java.sql.Date) + pst.setDate(parameterIndex, (java.sql.Date) paramValue); + else if (paramValue instanceof java.util.Date) + pst.setDate(parameterIndex, new java.sql.Date(((java.util.Date) paramValue).getTime())); + else + throw new DataSetException( + "Type [" + paramValue.getClass().getName() + "] for [" + DataType.DATE + "] is not supported"); + } + else if (DataType.TIME.equals(dataType)) + { + if (paramValue == null) + pst.setNull(parameterIndex, Types.TIME); + else if (paramValue instanceof java.sql.Time) + pst.setTime(parameterIndex, (java.sql.Time) paramValue); + else if (paramValue instanceof java.util.Date) + pst.setTime(parameterIndex, new java.sql.Time(((java.util.Date) paramValue).getTime())); + else + throw new DataSetException( + "Type [" + paramValue.getClass().getName() + "] for [" + DataType.TIME + "] is not supported"); + } + else if (DataType.TIMESTAMP.equals(dataType)) + { + if (paramValue == null) + pst.setNull(parameterIndex, Types.TIMESTAMP); + else if (paramValue instanceof java.sql.Timestamp) + pst.setTimestamp(parameterIndex, (java.sql.Timestamp) paramValue); + else if (paramValue instanceof java.util.Date) + pst.setTimestamp(parameterIndex, new java.sql.Timestamp(((java.util.Date) paramValue).getTime())); + else + throw new DataSetException( + "Type [" + paramValue.getClass().getName() + "] for [" + DataType.TIME + "] is not supported"); + } + else + throw new UnsupportedOperationException(); + } + + /** + * 将{@linkplain ResultSet}转换为{@linkplain DataSet}。 + * + * @param cn + * @param rs + * @return + * @throws SQLException + */ + protected DataSet toDataSet(Connection cn, ResultSet rs) throws SQLException + { + DataSetMeta dataSetMeta = resolveDataSetMeta(cn, rs); + List> datas = resolveDatas(cn, rs, dataSetMeta); + + return new SimpleDataSet(dataSetMeta, datas); + } + + /** + * 解析数据。 + * + * @param cn + * @param rs + * @param dataSetMeta + * @return + * @throws SQLException + */ + protected List> resolveDatas(Connection cn, ResultSet rs, DataSetMeta dataSetMeta) + throws SQLException + { + List> datas = new ArrayList>(); + + List columnMetas = dataSetMeta.getColumnMetas(); + ResultSetMetaData metaData = rs.getMetaData(); + int columnCount = metaData.getColumnCount(); + + while (rs.next()) + { + Map row = new HashMap(); + + for (int i = 1; i <= columnCount; i++) + { + ColumnMeta columnMeta = columnMetas.get(i - 1); + Object value = resolveDataValue(cn, rs, i, metaData.getColumnType(i), columnMeta.getDataType()); + + row.put(columnMeta.getName(), value); + } + + datas.add(row); + } + + return datas; + } + + /** + * 解析数据值。 + * + * @param cn + * @param rs + * @param column + * @param sqlType + * @param dataType + * @return + * @throws SQLException + */ + protected Object resolveDataValue(Connection cn, ResultSet rs, int column, int sqlType, DataType dataType) + throws SQLException + { + Object value = null; + + if (DataType.STRING.equals(dataType)) + { + switch (sqlType) + { + case Types.CHAR: + case Types.NCHAR: + case Types.NVARCHAR: + case Types.VARCHAR: + { + value = rs.getString(column); + break; + } + + default: + throw new UnsupportedSqlTypeException(sqlType); + } + } + else if (DataType.BOOLEAN.equals(dataType)) + { + switch (sqlType) + { + case Types.BIT: + case Types.BIGINT: + case Types.INTEGER: + case Types.SMALLINT: + case Types.TINYINT: + { + value = (rs.getInt(column) > 0); + break; + } + + case Types.BOOLEAN: + { + value = rs.getBoolean(column); + break; + } + + default: + throw new UnsupportedSqlTypeException(sqlType); + } + } + else if (DataType.INTEGER.equals(dataType)) + { + switch (sqlType) + { + case Types.BIGINT: + { + value = rs.getLong(column); + break; + } + + case Types.BIT: + case Types.INTEGER: + case Types.SMALLINT: + case Types.TINYINT: + { + value = rs.getInt(column); + break; + } + + case Types.DECIMAL: + case Types.NUMERIC: + { + value = rs.getBigDecimal(column).toBigInteger(); + break; + } + + case Types.DOUBLE: + { + value = new Double(rs.getDouble(column)).longValue(); + break; + } + + case Types.FLOAT: + case Types.REAL: + { + value = new Float(rs.getFloat(column)).longValue(); + break; + } + + default: + throw new UnsupportedSqlTypeException(sqlType); + } + } + else if (DataType.DECIMAL.equals(dataType)) + { + switch (sqlType) + { + case Types.BIGINT: + { + value = rs.getLong(column); + break; + } + + case Types.BIT: + case Types.INTEGER: + case Types.SMALLINT: + case Types.TINYINT: + { + value = rs.getInt(column); + break; + } + + case Types.DECIMAL: + case Types.NUMERIC: + { + value = rs.getBigDecimal(column); + break; + } + + case Types.DOUBLE: + { + value = rs.getDouble(column); + break; + } + + case Types.FLOAT: + case Types.REAL: + { + value = rs.getFloat(column); + break; + } + + default: + throw new UnsupportedSqlTypeException(sqlType); + } + } + else if (DataType.DATE.equals(dataType)) + { + switch (sqlType) + { + case Types.DATE: + { + value = rs.getDate(column); + break; + } + + default: + throw new UnsupportedSqlTypeException(sqlType); + } + } + else if (DataType.TIME.equals(dataType)) + { + switch (sqlType) + { + case Types.TIME: + { + value = rs.getTime(column); + break; + } + + default: + throw new UnsupportedSqlTypeException(sqlType); + } + } + else if (DataType.TIMESTAMP.equals(dataType)) + { + switch (sqlType) + { + case Types.TIMESTAMP: + { + value = rs.getTimestamp(column); + break; + } + + default: + throw new UnsupportedSqlTypeException(sqlType); + } + } + else + throw new UnsupportedOperationException(); + + return value; + } + + /** + * 解析{@linkplain DataSetMeta}。 + * + * @param cn + * @param rs + * @return + * @throws SQLException + */ + protected DataSetMeta resolveDataSetMeta(Connection cn, ResultSet rs) throws SQLException + { + ResultSetMetaData metaData = rs.getMetaData(); + int columnCount = metaData.getColumnCount(); + + List columnMetas = new ArrayList(columnCount); + + for (int i = 1; i <= columnCount; i++) + { + String columnName = metaData.getColumnLabel(i); + if (StringUtil.isEmpty(columnName)) + columnName = metaData.getColumnName(i); + + DataType dataType = toDataType(metaData, i); + + columnMetas.add(new ColumnMeta(columnName, dataType)); + } + + return new DataSetMeta(columnMetas); + } + + /** + * 由SQL类型转换为{@linkplain DataType}。 + * + * @param metaData + * @param column + * @return + * @throws SQLException + */ + protected DataType toDataType(ResultSetMetaData metaData, int column) throws SQLException + { + DataType dataType = null; + + int sqlType = metaData.getColumnType(column); + + switch (sqlType) + { + case Types.CHAR: + case Types.NCHAR: + case Types.NVARCHAR: + case Types.VARCHAR: + { + dataType = DataType.STRING; + break; + } + + case Types.BOOLEAN: + { + dataType = DataType.BOOLEAN; + break; + } + + case Types.BIGINT: + case Types.BIT: + case Types.INTEGER: + case Types.SMALLINT: + case Types.TINYINT: + { + dataType = DataType.INTEGER; + break; + } + + case Types.DECIMAL: + case Types.DOUBLE: + case Types.FLOAT: + case Types.NUMERIC: + case Types.REAL: + { + int scale = metaData.getScale(column); + + dataType = (scale > 0 ? DataType.DECIMAL : DataType.INTEGER); + break; + } + + case Types.DATE: + { + dataType = DataType.DATE; + break; + } + + case Types.TIME: + { + dataType = DataType.TIME; + break; + } + + case Types.TIMESTAMP: + { + dataType = DataType.TIMESTAMP; + break; + } + + default: + throw new UnsupportedSqlTypeException(sqlType); + } + + return dataType; + } + + protected ParameterSql resolveParameterSql(String sql) + { + return PARAMETER_SQL_RESOLVER.resolve(sql); + } +} diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/support/UnsupportedSqlTypeException.java b/datagear-analysis/src/main/java/org/datagear/analysis/support/UnsupportedSqlTypeException.java new file mode 100644 index 00000000..b310ddba --- /dev/null +++ b/datagear-analysis/src/main/java/org/datagear/analysis/support/UnsupportedSqlTypeException.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018 datagear.tech. All Rights Reserved. + */ + +/** + * + */ +package org.datagear.analysis.support; + +import org.datagear.analysis.DataSetException; + +/** + * 不支持指定SQL类型异常。 + * + * @author datagear@163.com + * + */ +public class UnsupportedSqlTypeException extends DataSetException +{ + private static final long serialVersionUID = 1L; + + private int sqlType; + + public UnsupportedSqlTypeException(int sqlType) + { + super(); + this.sqlType = sqlType; + } + + public UnsupportedSqlTypeException(int sqlType, String message) + { + super(message); + this.sqlType = sqlType; + } + + public UnsupportedSqlTypeException(int sqlType, Throwable cause) + { + super(cause); + this.sqlType = sqlType; + } + + public UnsupportedSqlTypeException(int sqlType, String message, Throwable cause) + { + super(message, cause); + this.sqlType = sqlType; + } + + public int getSqlType() + { + return sqlType; + } + + protected void setSqlType(int sqlType) + { + this.sqlType = sqlType; + } +} diff --git a/datagear-analysis/src/main/java/org/datagear/analysis/support/html/HtmlFreemarkerDashboardWidgetRenderer.java b/datagear-analysis/src/main/java/org/datagear/analysis/support/html/HtmlFreemarkerDashboardWidgetRenderer.java index 9e75ba0a..3c8913a6 100644 --- a/datagear-analysis/src/main/java/org/datagear/analysis/support/html/HtmlFreemarkerDashboardWidgetRenderer.java +++ b/datagear-analysis/src/main/java/org/datagear/analysis/support/html/HtmlFreemarkerDashboardWidgetRenderer.java @@ -383,10 +383,10 @@ public class HtmlFreemarkerDashboardWidgetRenderer * @param id * @return */ - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) protected HtmlChartWidget getHtmlChartWidget(String id) { - return (HtmlChartWidget) this.chartWidgetSource.getChartWidget(id); + return (HtmlChartWidget) ((ChartWidget) this.chartWidgetSource.getChartWidget(id)); } protected Object buildHtmlDashboardRenderDataModel(HtmlDashboardRenderDataModel dataModel) @@ -791,16 +791,14 @@ public class HtmlFreemarkerDashboardWidgetRenderer } } - out.write(varName - + ".render = function(){"); + out.write(varName + ".render = function(){"); writeNewLine(out); out.write(" for(var i=0; i columnMetas = dataSetMeta.getColumnMetas(); + + Assert.assertEquals(2, columnMetas.size()); + + { + ColumnMeta columnMeta = columnMetas.get(0); + + Assert.assertEquals("ID", columnMeta.getName()); + Assert.assertEquals(DataType.INTEGER, columnMeta.getDataType()); + } + + { + ColumnMeta columnMeta = columnMetas.get(1); + + Assert.assertEquals("NAME", columnMeta.getName()); + Assert.assertEquals(DataType.STRING, columnMeta.getDataType()); + } + + List> datas = dataSet.getDatas(); + + Assert.assertEquals(1, datas.size()); + + { + Map row = datas.get(0); + + Assert.assertEquals(2, row.size()); + Assert.assertEquals(Long.toString(recordId), row.get("ID").toString()); + Assert.assertEquals(recordName, row.get("NAME")); + } + } + finally + { + { + String insertSql = "DELETE FROM T_ACCOUNT WHERE ID=" + recordId; + Statement st = null; + + try + { + st = cn.createStatement(); + st.executeUpdate(insertSql); + } + finally + { + JdbcUtil.closeStatement(st); + } + } + + JdbcUtil.closeConnection(cn); + } + } +}