forked from p85126437/datagear
[analysis]完善DataSetFactory及相关API,添加SqlDataSetFactory
This commit is contained in:
parent
8a7798b8bf
commit
0c57376d2e
|
@ -22,5 +22,5 @@ public interface DashboardWidget<T extends RenderContext> extends Identifiable
|
|||
* @return
|
||||
* @throws RenderException
|
||||
*/
|
||||
public abstract Dashboard render(T renderContext) throws RenderException;
|
||||
Dashboard render(T renderContext) throws RenderException;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ public interface DataSetFactory extends Identifiable
|
|||
*
|
||||
* @param dataSetParamValues
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
DataSet getDataSet(DataSetParamValues dataSetParamValues);
|
||||
DataSet getDataSet(DataSetParamValues dataSetParamValues) throws DataSetException;
|
||||
}
|
||||
|
|
|
@ -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<DataSetParam> getDataSetParam(List<String> names) throws DataSetParamNotFountException
|
||||
{
|
||||
List<DataSetParam> dataSetParams = new ArrayList<DataSetParam>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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解析器。
|
||||
* <p>
|
||||
* 它解析包含<code>...${parameter0}...${parameter1}</code>的SQL语句,并将它们替换为JDBC规范的<code>?</code>占位符。
|
||||
* </p>
|
||||
*
|
||||
* @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<Expression> expressions = this.expressionResolver.resolve(parameterSql);
|
||||
|
||||
if (expressions == null || expressions.isEmpty())
|
||||
return new ParameterSql(parameterSql);
|
||||
|
||||
List<String> parameters = new ArrayList<String>(expressions.size());
|
||||
|
||||
List<String> values = new ArrayList<String>(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解析结果。
|
||||
* <p>
|
||||
* 它的{@linkplain #getSql()}中的<code>...${parameter}...</code>已被替换为<code>?</code>。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public static class ParameterSql
|
||||
{
|
||||
private String sql;
|
||||
|
||||
private List<String> parameters;
|
||||
|
||||
public ParameterSql()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ParameterSql(String sql)
|
||||
{
|
||||
super();
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public ParameterSql(String sql, List<String> 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<String> getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(List<String> parameters)
|
||||
{
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [sql=" + sql + ", parameters=" + parameters + "]";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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}。
|
||||
* <p>
|
||||
* 它的{@linkplain #setSql(String)}中可以包含<code>${parameter}</code>格式的参数(<code>parameter</code>必须是在{@linkplain #getDataSetParams()}中预定义的),
|
||||
* 在{@linkplain #getDataSet(DataSetParamValues)}中会被替换为具体的参数值。
|
||||
* </p>
|
||||
*
|
||||
* @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<DataSetParam> 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<DataSetParam> 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<Map<String, ?>> datas = resolveDatas(cn, rs, dataSetMeta);
|
||||
|
||||
return new SimpleDataSet(dataSetMeta, datas);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析数据。
|
||||
*
|
||||
* @param cn
|
||||
* @param rs
|
||||
* @param dataSetMeta
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected List<Map<String, ?>> resolveDatas(Connection cn, ResultSet rs, DataSetMeta dataSetMeta)
|
||||
throws SQLException
|
||||
{
|
||||
List<Map<String, ?>> datas = new ArrayList<Map<String, ?>>();
|
||||
|
||||
List<ColumnMeta> columnMetas = dataSetMeta.getColumnMetas();
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
Map<String, Object> row = new HashMap<String, Object>();
|
||||
|
||||
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<ColumnMeta> columnMetas = new ArrayList<ColumnMeta>(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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -383,10 +383,10 @@ public class HtmlFreemarkerDashboardWidgetRenderer<T extends HtmlRenderContext>
|
|||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected HtmlChartWidget<T> getHtmlChartWidget(String id)
|
||||
{
|
||||
return (HtmlChartWidget<T>) this.chartWidgetSource.getChartWidget(id);
|
||||
return (HtmlChartWidget<T>) ((ChartWidget) this.chartWidgetSource.getChartWidget(id));
|
||||
}
|
||||
|
||||
protected Object buildHtmlDashboardRenderDataModel(HtmlDashboardRenderDataModel dataModel)
|
||||
|
@ -791,16 +791,14 @@ public class HtmlFreemarkerDashboardWidgetRenderer<T extends HtmlRenderContext>
|
|||
}
|
||||
}
|
||||
|
||||
out.write(varName
|
||||
+ ".render = function(){");
|
||||
out.write(varName + ".render = function(){");
|
||||
writeNewLine(out);
|
||||
out.write(" for(var i=0; i<this.charts.length; i++){ this.charts[i].render(); }");
|
||||
writeNewLine(out);
|
||||
out.write("};");
|
||||
writeNewLine(out);
|
||||
|
||||
out.write(varName
|
||||
+ ".update = function(){");
|
||||
out.write(varName + ".update = function(){");
|
||||
writeNewLine(out);
|
||||
out.write(" for(var i=0; i<this.charts.length; i++){ this.charts[i].update(); }");
|
||||
writeNewLine(out);
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.org. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.Reader;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 数据库测试支持类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class DBTestSupport
|
||||
{
|
||||
private static final Properties JDBC_PROPERTIES = new Properties();
|
||||
|
||||
static
|
||||
{
|
||||
File jdbcConfigFile = new File("test/config/jdbc.properties");
|
||||
if (!jdbcConfigFile.exists())
|
||||
jdbcConfigFile = new File("../test/config/jdbc.properties");
|
||||
|
||||
try
|
||||
{
|
||||
Reader reader = new FileReader(jdbcConfigFile);
|
||||
JDBC_PROPERTIES.load(reader);
|
||||
reader.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException) e;
|
||||
else
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Connection getConnection() throws SQLException
|
||||
{
|
||||
return DriverManager.getConnection(JDBC_PROPERTIES.getProperty("jdbc.url"),
|
||||
JDBC_PROPERTIES.getProperty("jdbc.user"), JDBC_PROPERTIES.getProperty("jdbc.password"));
|
||||
}
|
||||
|
||||
protected Connection getConnection(Properties properties) throws Exception
|
||||
{
|
||||
properties.setProperty("user", JDBC_PROPERTIES.getProperty("jdbc.user"));
|
||||
properties.setProperty("password", JDBC_PROPERTIES.getProperty("jdbc.password"));
|
||||
|
||||
return DriverManager.getConnection(JDBC_PROPERTIES.getProperty("jdbc.url"), properties);
|
||||
}
|
||||
|
||||
protected void println()
|
||||
{
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
protected void println(Object o)
|
||||
{
|
||||
System.out.println((o == null ? "null" : o.toString()));
|
||||
}
|
||||
|
||||
protected void print(Object o)
|
||||
{
|
||||
System.out.print((o == null ? "null" : o.toString()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.Statement;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.ColumnMeta;
|
||||
import org.datagear.analysis.DataSet;
|
||||
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.util.JdbcUtil;
|
||||
import org.datagear.util.resource.SimpleConnectionFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain SqlDataSetFactory}单元测试类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class SqlDataSetFactoryTest extends DBTestSupport
|
||||
{
|
||||
@Test
|
||||
public void getDataSetTest() throws Exception
|
||||
{
|
||||
Connection cn = null;
|
||||
|
||||
long recordId = 999999999;
|
||||
String recordName = SqlDataSetFactory.class.getSimpleName();
|
||||
|
||||
try
|
||||
{
|
||||
cn = getConnection();
|
||||
SimpleConnectionFactory connectionFactory = new SimpleConnectionFactory(cn, false);
|
||||
|
||||
{
|
||||
String insertSql = "INSERT INTO T_ACCOUNT(ID, NAME) VALUES(" + recordId + ", '" + recordName + "')";
|
||||
Statement st = null;
|
||||
|
||||
try
|
||||
{
|
||||
st = cn.createStatement();
|
||||
st.executeUpdate(insertSql);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JdbcUtil.closeStatement(st);
|
||||
}
|
||||
}
|
||||
|
||||
String sql = "SELECT ID, NAME FROM T_ACCOUNT WHERE ID = ${id} AND NAME != ${name}";
|
||||
|
||||
DataSetParams dataSetParams = new DataSetParams();
|
||||
dataSetParams.add(new DataSetParam("id", DataType.INTEGER, true));
|
||||
dataSetParams.add(new DataSetParam("name", DataType.STRING, true));
|
||||
|
||||
SqlDataSetFactory sqlDataSetFactory = new SqlDataSetFactory("1", dataSetParams, connectionFactory, sql);
|
||||
|
||||
DataSetParamValues dataSetParamValues = new DataSetParamValues();
|
||||
dataSetParamValues.put("id", recordId);
|
||||
dataSetParamValues.put("name", "name-for-test");
|
||||
|
||||
DataSet dataSet = sqlDataSetFactory.getDataSet(dataSetParamValues);
|
||||
|
||||
DataSetMeta dataSetMeta = dataSet.getMeta();
|
||||
List<ColumnMeta> 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<Map<String, ?>> datas = dataSet.getDatas();
|
||||
|
||||
Assert.assertEquals(1, datas.size());
|
||||
|
||||
{
|
||||
Map<String, ?> 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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue