重构[analysis]模块,添加ChartQuery、ChartResult、DashboardQuery、DashboardResult等新类,并修改相关API

This commit is contained in:
datagear 2021-06-25 21:45:30 +08:00
parent ceedda2f5b
commit 6f870ac34d
25 changed files with 834 additions and 366 deletions

View File

@ -2,7 +2,7 @@
添加更多内置图表插件:嵌套饼图、盒须图、地图热力图、路径图;
数据管理高级查询功能、SQL数据集添加防注入支持
图表列表页支持展示其包含的数据集并支持关键字查询
看板新增加载数据异常处理API
ok 仪表盘图表支持多指标;
ok 看板JS对象添加获取服务端当前日期时间的API
ok 升级ECharts版本4.9.0至5.1.2注意5.0.2版本的关系图graph在使用geo坐标系统时报错
@ -10,6 +10,7 @@
待定:
图表列表页支持展示其包含的数据集并支持关键字查询需要列转行SQL支持可能会无法兼容某些部署数据库
看板图表新增导出数据功能;
系统添加缓存支持;
共享看板支持设置密码;

View File

@ -121,48 +121,24 @@ public class ChartDataSet
}
/**
* {@linkplain #getResult()}是否可用
* 使用{@linkplain #getQuery()}获取{@linkplain #getDataSet()}{@linkplain DataSetResult}
*
* @return
* @throws DataSetException
*/
public boolean isResultReady()
{
return this.dataSet.isReady(this.query);
}
/**
* 获取{@linkplain #getDataSet()}{@linkplain DataSetResult}
* </p>
* 调用此方法前应该确保{@linkplain #isResultReady()}返回{@code true}
* </p>
*
* @return
*/
public DataSetResult getResult()
public DataSetResult getResult() throws DataSetException
{
return this.dataSet.getResult(this.query);
}
/**
* {@linkplain #getResult(DataSetQuery)}是否可用
* @param query
* @return
*/
public boolean isResultReady(DataSetQuery query)
{
return this.dataSet.isReady(query);
}
/**
* 获取{@linkplain #getDataSet()}{@linkplain DataSetResult}
* </p>
* 调用此方法前应该确保{@linkplain #isResultReady(DataSetQuery)}返回{@code true}
* </p>
*
* @param query
* @return
* @throws DataSetException
*/
public DataSetResult getResult(DataSetQuery query)
public DataSetResult getResult(DataSetQuery query) throws DataSetException
{
return this.dataSet.getResult(query);
}

View File

@ -7,6 +7,7 @@
package org.datagear.analysis;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -18,7 +19,7 @@ import java.util.Map;
* @author datagear@163.com
*
*/
public class ChartDefinition extends AbstractIdentifiable
public class ChartDefinition extends AbstractIdentifiable implements ResultDataFormatAware
{
public static final String PROPERTY_ID = "id";
public static final String PROPERTY_NAME = "name";
@ -150,8 +151,9 @@ public class ChartDefinition extends AbstractIdentifiable
/**
* 获取图表数据集结果数据格式
*
* @return 返回{@code null}表示未设置
* @return
*/
@Override
public ResultDataFormat getResultDataFormat()
{
return resultDataFormat;
@ -162,108 +164,79 @@ public class ChartDefinition extends AbstractIdentifiable
*
* @param dataFormat
*/
@Override
public void setResultDataFormat(ResultDataFormat resultDataFormat)
{
this.resultDataFormat = resultDataFormat;
}
/**
* 获取指定索引的默认{@linkplain DataSetResult}
* 获取{@linkplain ChartResult}
* <p>
* 如果{@linkplain ChartQuery#getDataSetQuery(int)}{@code null}此方法将使用{@linkplain ChartDataSet#getQuery()}
* </p>
*
* @param index
* @return 如果{@linkplain ChartDataSet#isResultReady()}{@code false}将返回{@code null}
* @param query
* @return
* @throws DataSetException
*/
public DataSetResult getDataSetResult(int index) throws DataSetException
{
ChartDataSet chartDataSet = this.chartDataSets[index];
if (!chartDataSet.isResultReady())
return null;
if(this.resultDataFormat == null)
{
return chartDataSet.getResult();
}
else
{
DataSetQuery query = DataSetQuery.copy(chartDataSet.getQuery());
query.setResultDataFormat(this.resultDataFormat);
return chartDataSet.getResult(query);
}
}
/**
* 获取所有默认{@linkplain DataSetResult}数组
*
* @return 如果{@linkplain #getChartDataSets()}指定索引的{@linkplain ChartDataSet#isResultReady()}{@code false}
* 返回数组对应元素将为{@code null}
* @throws DataSetException
*/
public DataSetResult[] getDataSetResults() throws DataSetException
public ChartResult getResult(ChartQuery query) throws DataSetException
{
if (this.chartDataSets == null || this.chartDataSets.length == 0)
return new DataSetResult[0];
return new ChartResult(Collections.emptyList());
DataSetResult[] results = new DataSetResult[this.chartDataSets.length];
ChartResult chartResult = new ChartResult();
for (int i = 0; i < this.chartDataSets.length; i++)
results[i] = getDataSetResult(i);
return results;
}
/**
* 获取指定索引的{@linkplain DataSetResult}
*
* @param index
* @param query 允许为{@code null}
* @return 如果{@linkplain ChartDataSet#isResultReady(DataSetQuery)}{@code false}将返回{@code null}
* @throws DataSetException
*/
public DataSetResult getDataSetResult(int index, DataSetQuery query) throws DataSetException
{
if (query == null)
query = DataSetQuery.valueOf();
if(query.getResultDataFormat() == null && this.resultDataFormat != null)
{
query = query.copy();
query.setResultDataFormat(this.resultDataFormat);
}
ChartDataSet chartDataSet = this.chartDataSets[index];
if (!chartDataSet.isResultReady(query))
return null;
return chartDataSet.getResult(query);
}
/**
* 获取所有{@linkplain DataSetResult}数组
*
* @param queries 允许为{@code null}或者元素为{@code null}
* @return 如果{@linkplain #getChartDataSets()}指定索引的{@linkplain ChartDataSet#isResultReady(DataSetQuery)}{@code false}返回数组对应元素将为{@code null}
* @throws DataSetException
*/
public DataSetResult[] getDataSetResults(List<? extends DataSetQuery> queries) throws DataSetException
{
if (this.chartDataSets == null || this.chartDataSets.length == 0)
return new DataSetResult[0];
DataSetResult[] results = new DataSetResult[this.chartDataSets.length];
int pvSize = (queries == null ? 0 : queries.size());
List<DataSetResult> dataSetResults = new ArrayList<DataSetResult>(this.chartDataSets.length);
for (int i = 0; i < this.chartDataSets.length; i++)
{
DataSetQuery query = (i >= pvSize ? null : queries.get(i));
results[i] = getDataSetResult(i, query);
ChartDataSet chartDataSet = this.chartDataSets[i];
DataSetQuery dataSetQuery = getDataSetQuery(query, chartDataSet, i);
DataSetResult dataSetResult = chartDataSet.getResult(dataSetQuery);
dataSetResults.add(dataSetResult);
}
return results;
chartResult.setDataSetResults(dataSetResults);
return chartResult;
}
/**
* 获取指定{@linkplain DataSetQuery}
*
* @param chartQuery
* @param chartDataSet
* @param chartDataSetIdx
* @return
*/
protected DataSetQuery getDataSetQuery(ChartQuery chartQuery, ChartDataSet chartDataSet, int chartDataSetIdx)
{
DataSetQuery dataSetQuery = chartQuery.getDataSetQuery(chartDataSetIdx);
if (dataSetQuery == null)
dataSetQuery = chartDataSet.getQuery();
if (dataSetQuery == null)
dataSetQuery = DataSetQuery.valueOf();
if (dataSetQuery.getResultDataFormat() == null)
{
ResultDataFormat cqrds = chartQuery.getResultDataFormat();
ResultDataFormat crds = getResultDataFormat();
if (cqrds != null || crds != null)
{
dataSetQuery = dataSetQuery.copy();
dataSetQuery.setResultDataFormat(cqrds);
if (dataSetQuery.getResultDataFormat() == null)
dataSetQuery.setResultDataFormat(crds);
}
}
return dataSetQuery;
}
@Override

View File

@ -0,0 +1,89 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis;
import java.util.Collections;
import java.util.List;
/**
* 图表查询
*
* @author datagear@163.com
*
*/
public class ChartQuery implements ResultDataFormatAware
{
private List<DataSetQuery> dataSetQueries = Collections.emptyList();
/** 图表结果数格式 */
private ResultDataFormat resultDataFormat = null;
public ChartQuery()
{
super();
}
public ChartQuery(List<DataSetQuery> dataSetQueries)
{
super();
this.dataSetQueries = dataSetQueries;
}
public ChartQuery(ChartQuery chartQuery)
{
super();
this.dataSetQueries = chartQuery.dataSetQueries;
this.resultDataFormat = chartQuery.resultDataFormat;
}
public List<DataSetQuery> getDataSetQueries()
{
return dataSetQueries;
}
public void setDataSetQueries(List<DataSetQuery> dataSetQueries)
{
this.dataSetQueries = dataSetQueries;
}
@Override
public ResultDataFormat getResultDataFormat()
{
return resultDataFormat;
}
@Override
public void setResultDataFormat(ResultDataFormat resultDataFormat)
{
this.resultDataFormat = resultDataFormat;
}
/**
* 获取指定索引的{@linkplain DataSetQuery}
* <p>
* 此方法不会抛出索引越界异常如果索引越界将直接返回{@code null}
* </p>
*
* @param index
* @return 返回{@code null}表示无对应的{@linkplain DataSetQuery}
*/
public DataSetQuery getDataSetQuery(int index)
{
int size = (this.dataSetQueries == null ? 0 : this.dataSetQueries.size());
if (index >= size)
return null;
return this.dataSetQueries.get(index);
}
public ChartQuery copy()
{
return new ChartQuery(this);
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis;
import java.util.Collections;
import java.util.List;
/**
* 图表结果
*
* @author datagear@163.com
*
*/
public class ChartResult
{
private List<DataSetResult> dataSetResults = Collections.emptyList();
public ChartResult()
{
super();
}
public ChartResult(List<DataSetResult> dataSetResults)
{
super();
this.dataSetResults = dataSetResults;
}
/**
* 获取{@linkplain DataSetResult}列表
* <p>
* 返回列表的元素与{@linkplain ChartDefinition#getChartDataSets()}元素一一对应
* </p>
*
* @return 返回{@code null}或空列表表示无结果
*/
public List<DataSetResult> getDataSetResults()
{
return dataSetResults;
}
public void setDataSetResults(List<DataSetResult> dataSetResults)
{
this.dataSetResults = dataSetResults;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis;
/**
* 获取图表结果错误信息
*
* @author datagear@163.com
*
*/
public class ChartResultError
{
private Throwable throwable;
public ChartResultError()
{
super();
}
public ChartResultError(Throwable throwable)
{
super();
this.throwable = throwable;
}
public Throwable getThrowable()
{
return throwable;
}
public void setThrowable(Throwable throwable)
{
this.throwable = throwable;
}
}

View File

@ -7,11 +7,9 @@
package org.datagear.analysis;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 看板
@ -30,7 +28,7 @@ public class Dashboard extends AbstractIdentifiable
private DashboardWidget widget;
private List<Chart> charts;
private List<Chart> charts = null;
public Dashboard()
{
@ -84,6 +82,12 @@ public class Dashboard extends AbstractIdentifiable
this.charts = charts;
}
/**
* 获取指定ID的{@linkplain Chart}
*
* @param id
* @return 返回{@code null}表示没有找到
*/
public Chart getChart(String id)
{
if (this.charts == null)
@ -99,52 +103,59 @@ public class Dashboard extends AbstractIdentifiable
}
/**
* 获取此看板所有图表的默认数据集结果
* 获取{@linkplain DashboardResult}
*
* @return 返回映射表的值数组元素可能为{@code null}具体参考{@linkplain ChartDefinition#getDataSetResults()}
* @throws DataSetException
*/
@SuppressWarnings("unchecked")
public Map<String, DataSetResult[]> getDataSetResults() throws DataSetException
{
if (this.charts == null || this.charts.isEmpty())
return Collections.EMPTY_MAP;
Map<String, DataSetResult[]> resultsMap = new HashMap<>();
for (Chart chart : this.charts)
resultsMap.put(chart.getId(), chart.getDataSetResults());
return resultsMap;
}
/**
* 获取此看板指定图表ID集的数据集结果
*
* @param chartIds
* @param dataSetQueries
* @param query
* @return
* @throws DataSetException
*/
public Map<String, DataSetResult[]> getDataSetResults(Set<String> chartIds,
Map<String, ? extends List<? extends DataSetQuery>> dataSetQueries) throws DataSetException
public DashboardResult getResult(DashboardQuery query) throws DataSetException
{
Map<String, DataSetResult[]> resultsMap = new HashMap<>();
Map<String, ChartQuery> chartQueries = query.getChartQueries();
boolean suppressChartError = query.isSuppressChartError();
if (this.charts == null || this.charts.isEmpty())
return resultsMap;
Map<String, ChartResult> chartResults = new HashMap<String, ChartResult>(chartQueries.size());
Map<String, ChartResultError> chartResultErrors = new HashMap<String, ChartResultError>();
for (Chart chart : this.charts)
for (Map.Entry<String, ChartQuery> entry : chartQueries.entrySet())
{
if (!chartIds.contains(chart.getId()))
continue;
String chartId = entry.getKey();
ChartQuery chartQuery = entry.getValue();
Chart chart = getChart(chartId);
List<? extends DataSetQuery> myQuery = dataSetQueries.get(chart.getId());
if (chart == null)
throw new IllegalArgumentException("Chart '" + chartId + "' not found");
DataSetResult[] results = chart.getDataSetResults(myQuery);
resultsMap.put(chart.getId(), results);
if (chartQuery.getResultDataFormat() == null && query.getResultDataFormat() != null)
{
chartQuery = chartQuery.copy();
chartQuery.setResultDataFormat(query.getResultDataFormat());
}
ChartResult chartResult = null;
if (suppressChartError)
{
try
{
chartResult = chart.getResult(chartQuery);
chartResults.put(chartId, chartResult);
}
catch (Throwable t)
{
chartResultErrors.put(chartId, new ChartResultError(t));
}
}
else
{
chartResult = chart.getResult(chartQuery);
chartResults.put(chartId, chartResult);
}
}
return resultsMap;
DashboardResult dashboardResult = new DashboardResult(chartResults);
dashboardResult.setChartResultErrors(chartResultErrors);
return dashboardResult;
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis;
import java.util.Collections;
import java.util.Map;
/**
* 看板查询
*
* @author datagear@163.com
*
*/
public class DashboardQuery implements ResultDataFormatAware
{
/** 图表ID-查询映射表 */
private Map<String, ChartQuery> chartQueries = Collections.emptyMap();
/** 图表结果数格式 */
private ResultDataFormat resultDataFormat = null;
/** 单个图表查询出错时是否不抛出异常,而仅记录错误信息 */
private boolean suppressChartError = false;
public DashboardQuery()
{
super();
}
public DashboardQuery(Map<String, ChartQuery> chartQueries)
{
super();
this.chartQueries = chartQueries;
}
public DashboardQuery(DashboardQuery query)
{
super();
this.chartQueries = query.chartQueries;
this.suppressChartError = query.suppressChartError;
}
public Map<String, ChartQuery> getChartQueries()
{
return chartQueries;
}
public void setChartQueries(Map<String, ChartQuery> chartQueries)
{
this.chartQueries = chartQueries;
}
@Override
public ResultDataFormat getResultDataFormat()
{
return resultDataFormat;
}
@Override
public void setResultDataFormat(ResultDataFormat resultDataFormat)
{
this.resultDataFormat = resultDataFormat;
}
public boolean isSuppressChartError()
{
return suppressChartError;
}
public void setSuppressChartError(boolean suppressChartError)
{
this.suppressChartError = suppressChartError;
}
public DashboardQuery copy()
{
return new DashboardQuery(this);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis;
import java.util.Collections;
import java.util.Map;
/**
* 看板结果
*
* @author datagear@163.com
*
*/
public class DashboardResult
{
/** 图表ID-图表结果映射表 */
private Map<String, ChartResult> chartResults = Collections.emptyMap();
/** 图表ID-图表结果异常映射表 */
private Map<String, ChartResultError> chartResultErrors = Collections.emptyMap();
public DashboardResult()
{
super();
}
public DashboardResult(Map<String, ChartResult> chartResults)
{
super();
this.chartResults = chartResults;
}
/**
* 获取[图表ID-图表结果]映射表
*
* @return
*/
public Map<String, ChartResult> getChartResults()
{
return chartResults;
}
public void setChartResults(Map<String, ChartResult> chartResults)
{
this.chartResults = chartResults;
}
/**
* 获取[图表ID-{@linkplain ChartResultError}]映射表
*
* @return
*/
public Map<String, ChartResultError> getChartResultErrors()
{
return chartResultErrors;
}
public void setChartResultErrors(Map<String, ChartResultError> chartResultErrors)
{
this.chartResultErrors = chartResultErrors;
}
}

View File

@ -64,24 +64,13 @@ public interface DataSet extends Identifiable
*/
DataSetParam getParam(String name);
/**
* 给定的{@linkplain DataSetQuery}是否可用于{@linkplain #getResult(DataSetQuery)}
* <p>
* 通常是{@linkplain DataSetQuery#getParamValues()}包含{@linkplain #getParams()}中的所有{@linkplain DataSetParam#isRequired()}参数值
* </p>
*
* @param query 允许为{@code null}
* @return
*/
boolean isReady(DataSetQuery query);
/**
* 获取{@linkplain DataSetResult}
* <p>
* 返回结果中的数据项应已转换为与{@linkplain #getProperties()}{@linkplain DataSetProperty#getType()}类型一致
* </p>
*
* @param query 应是已通过{@linkplain #isReady(DataSetQuery)}校验的可能为{@code null}
* @param query
* @return
* @throws DataSetException
*/

View File

@ -19,7 +19,7 @@ import java.util.Map;
* @author datagear@163.com
*
*/
public class DataSetQuery
public class DataSetQuery implements ResultDataFormatAware
{
/** 参数值映射表 */
private Map<String, ?> paramValues = Collections.emptyMap();
@ -62,11 +62,7 @@ public class DataSetQuery
this.paramValues = paramValues;
}
/**
* 获取结果数据格式
*
* @return 返回{@code null}表示未设置
*/
@Override
public ResultDataFormat getResultDataFormat()
{
return resultDataFormat;
@ -80,6 +76,7 @@ public class DataSetQuery
*
* @param dataFormat
*/
@Override
public void setResultDataFormat(ResultDataFormat resultDataFormat)
{
this.resultDataFormat = resultDataFormat;

View File

@ -0,0 +1,31 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis;
/**
* {@linkplain ResultDataFormat}引用类
*
* @author datagear@163.com
*
*/
public interface ResultDataFormatAware
{
/**
* 获取{@linkplain ResultDataFormat}
*
* @return 返回{@code null}表示没有设置
*/
ResultDataFormat getResultDataFormat();
/**
* 设置{@linkplain ResultDataFormat}
*
* @param format
*/
void setResultDataFormat(ResultDataFormat format);
}

View File

@ -132,13 +132,16 @@ public abstract class AbstractDataSet extends AbstractIdentifiable implements Da
this.dataFormat = dataFormat;
}
@Override
public boolean isReady(DataSetQuery query)
/**
* 校验{@linkplain DataSetQuery#getParamValues()}是否有缺失的必填项
*
* @param query
* @throws DataSetParamValueRequiredException
*/
protected void checkRequiredParamValues(DataSetQuery query) throws DataSetParamValueRequiredException
{
if (!hasParam())
return true;
query = toNonNullDataSetQuery(query);
return;
List<DataSetParam> params = getParams();
Map<String, ?> paramValues = query.getParamValues();
@ -146,22 +149,11 @@ public abstract class AbstractDataSet extends AbstractIdentifiable implements Da
for (DataSetParam param : params)
{
if (param.isRequired() && !paramValues.containsKey(param.getName()))
return false;
throw new DataSetParamValueRequiredException(
"Parameter [" + param.getName() + "] 's value is required");
}
return true;
}
/**
* 转换为非{@code null}{@linkplain DataSetQuery}
* @param query
* @return
*/
protected DataSetQuery toNonNullDataSetQuery(DataSetQuery query)
{
return (query == null ? DataSetQuery.valueOf() : query);
}
/**
* 解析结果数据
*

View File

@ -45,7 +45,8 @@ public abstract class AbstractResolvableDataSet extends AbstractDataSet implemen
@Override
public DataSetResult getResult(DataSetQuery query) throws DataSetException
{
query = toNonNullDataSetQuery(query);
checkRequiredParamValues(query);
List<DataSetProperty> properties = getProperties();
if (properties == null || properties.isEmpty())
@ -57,10 +58,10 @@ public abstract class AbstractResolvableDataSet extends AbstractDataSet implemen
}
@Override
public ResolvedDataSetResult resolve(DataSetQuery query)
throws DataSetException
public ResolvedDataSetResult resolve(DataSetQuery query) throws DataSetException
{
query = toNonNullDataSetQuery(query);
checkRequiredParamValues(query);
List<DataSetProperty> properties = getProperties();
return resolveResult(query, properties, true);

View File

@ -0,0 +1,41 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
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;
public DataSetParamValueRequiredException()
{
super();
}
public DataSetParamValueRequiredException(String message)
{
super(message);
}
public DataSetParamValueRequiredException(Throwable cause)
{
super(cause);
}
public DataSetParamValueRequiredException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -0,0 +1,129 @@
/*
* Copyright 2018 datagear.tech
*
* Licensed under the LGPLv3 license:
* http://www.gnu.org/licenses/lgpl-3.0.html
*/
package org.datagear.analysis.support;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.datagear.analysis.ChartResultError;
import org.datagear.analysis.DashboardResult;
/**
* 错误消息的{@linkplain DashboardResult}
* <p>
* 它的{@linkplain #getChartResultErrors()}始终返回空映射表
* {@linkplain #getChartResultErrorMessages()}则是由{@linkplain DashboardResult#getChartResultErrors()}转换而得
* </p>
*
* @author datagear@163.com
*
*/
public class ErrorMessageDashboardResult extends DashboardResult
{
private Map<String, ChartResultErrorMessage> chartResultErrorMessages = Collections.emptyMap();
public ErrorMessageDashboardResult(DashboardResult result)
{
super.setChartResults(result.getChartResults());
setChartResultErrorMessages(toChartResultErrorMessages(result.getChartResultErrors()));
}
public Map<String, ChartResultErrorMessage> getChartResultErrorMessages()
{
return chartResultErrorMessages;
}
protected void setChartResultErrorMessages(Map<String, ChartResultErrorMessage> chartResultErrorMessages)
{
this.chartResultErrorMessages = chartResultErrorMessages;
}
@Override
public Map<String, ChartResultError> getChartResultErrors()
{
return Collections.emptyMap();
}
@Override
public void setChartResultErrors(Map<String, ChartResultError> chartResultErrors)
{
throw new UnsupportedOperationException();
}
protected Map<String, ChartResultErrorMessage> toChartResultErrorMessages(
Map<String, ChartResultError> chartResultErrors)
{
if (chartResultErrors == null)
return Collections.emptyMap();
Map<String, ChartResultErrorMessage> re = new HashMap<String, ErrorMessageDashboardResult.ChartResultErrorMessage>(
chartResultErrors.size());
for (Map.Entry<String, ChartResultError> entry : chartResultErrors.entrySet())
{
ChartResultErrorMessage em = new ChartResultErrorMessage(entry.getValue());
re.put(entry.getKey(), em);
}
return re;
}
public static class ChartResultErrorMessage
{
/** 错误类型 */
private String type = "";
/** 错误消息 */
private String message = "";
public ChartResultErrorMessage()
{
super();
}
public ChartResultErrorMessage(String type, String message)
{
super();
this.type = type;
this.message = message;
}
public ChartResultErrorMessage(ChartResultError error)
{
super();
Throwable throwable = error.getThrowable();
if (throwable != null)
{
this.type = throwable.getClass().getSimpleName();
this.message = throwable.getMessage();
}
}
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
}
}

View File

@ -111,13 +111,6 @@ public class HtmlChartScriptObjectWriter extends AbstractHtmlScriptObjectWriter
setPlugin(new RefHtmlChartPlugin(pluginVarName));
setRenderContext(new RefRenderContext(renderContextVarName));
}
@JsonIgnore
@Override
public DataSetResult[] getDataSetResults() throws DataSetException
{
throw new UnsupportedOperationException();
}
}
/**
@ -137,13 +130,6 @@ public class HtmlChartScriptObjectWriter extends AbstractHtmlScriptObjectWriter
setQuery(chartDataSet.getQuery());
}
@JsonIgnore
@Override
public boolean isResultReady()
{
throw new UnsupportedOperationException();
}
@JsonIgnore
@Override
public DataSetResult getResult()

View File

@ -10,10 +10,7 @@ package org.datagear.analysis.support.html;
import java.io.IOException;
import java.io.Writer;
import java.util.Collections;
import java.util.Map;
import org.datagear.analysis.DataSetException;
import org.datagear.analysis.DataSetResult;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.RenderException;
@ -82,13 +79,6 @@ public class HtmlTplDashboardScriptObjectWriter extends AbstractHtmlScriptObject
setCharts(Collections.EMPTY_LIST);
}
@JsonIgnore
@Override
public Map<String, DataSetResult[]> getDataSetResults() throws DataSetException
{
throw new UnsupportedOperationException();
}
}
/**

View File

@ -41,13 +41,6 @@ public class ChartDataSetVO extends ChartDataSet
super.setDataSet(dataSetEntity);
}
@JsonIgnore
@Override
public boolean isResultReady()
{
return super.isResultReady();
}
@JsonIgnore
@Override
public DataSetResult getResult()

View File

@ -9,14 +9,10 @@ package org.datagear.management.domain;
import java.util.Date;
import org.datagear.analysis.DataSetException;
import org.datagear.analysis.DataSetResult;
import org.datagear.analysis.support.ChartWidget;
import org.datagear.analysis.support.html.HtmlChartPlugin;
import org.datagear.analysis.support.html.HtmlChartWidget;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* HTML {@linkplain ChartWidget}实体
*
@ -125,11 +121,4 @@ public class HtmlChartWidgetEntity extends HtmlChartWidget
{
this.analysisProject = analysisProject;
}
@JsonIgnore
@Override
public DataSetResult[] getDataSetResults() throws DataSetException
{
return super.getDataSetResults();
}
}

View File

@ -308,13 +308,6 @@ public class AbstractChartPluginAwareController extends AbstractDataAnalysisCont
setQuery(chartDataSet.getQuery());
}
@JsonIgnore
@Override
public boolean isResultReady()
{
return false;
}
@JsonIgnore
@Override
public DataSetResult getResult()

View File

@ -12,12 +12,9 @@ import java.io.Serializable;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -25,11 +22,13 @@ import javax.servlet.http.HttpSession;
import org.datagear.analysis.Chart;
import org.datagear.analysis.ChartDataSet;
import org.datagear.analysis.ChartQuery;
import org.datagear.analysis.Dashboard;
import org.datagear.analysis.DashboardQuery;
import org.datagear.analysis.DashboardResult;
import org.datagear.analysis.DashboardTheme;
import org.datagear.analysis.DashboardThemeSource;
import org.datagear.analysis.DataSetQuery;
import org.datagear.analysis.DataSetResult;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.support.DataSetParamValueConverter;
import org.datagear.analysis.support.DefaultRenderContext;
@ -165,7 +164,7 @@ public abstract class AbstractDataAnalysisController extends AbstractController
}
/**
* 获取看板数据
* 获取看板结果
*
* @param request
* @param response
@ -175,12 +174,11 @@ public abstract class AbstractDataAnalysisController extends AbstractController
* @return
* @throws Exception
*/
protected Map<String, DataSetResult[]> getDashboardData(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, WebContext webContext, DashboardUpdateDataForm form) throws Exception
protected DashboardResult getDashboardResult(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, WebContext webContext, DashboardQueryForm form) throws Exception
{
String dashboardId = form.getDashboardId();
List<String> chartIds = form.getChartIds();
Map<String, List<DataSetQuery>> chartsQueries = form.getChartQueries();
DashboardQuery dashboardQuery = form.getDashboardQuery();
if (StringUtil.isEmpty(dashboardId))
throw new IllegalInputException();
@ -191,59 +189,60 @@ public abstract class AbstractDataAnalysisController extends AbstractController
if (dashboard == null)
throw new RecordNotFoundException();
if (chartIds == null || chartIds.isEmpty())
return dashboard.getDataSetResults();
else
{
Set<String> chartIdSet = new HashSet<>(chartIds.size());
chartIdSet.addAll(chartIds);
DashboardQuery queriesConverted = convertDashboardQuery(dashboard, dashboardQuery);
return dashboard.getDataSetResults(chartIdSet, convertChartDataSetQueries(dashboard, chartsQueries));
}
return dashboard.getResult(queriesConverted);
}
protected Map<String, List<DataSetQuery>> convertChartDataSetQueries(Dashboard dashboard,
Map<String, ? extends List<? extends DataSetQuery>> chartsQueries)
protected DashboardQuery convertDashboardQuery(Dashboard dashboard, DashboardQuery query)
{
if(chartsQueries == null)
return Collections.emptyMap();
if (query == null)
return new DashboardQuery();
Map<String, List<DataSetQuery>> re = new HashMap<String, List<DataSetQuery>>();
for (Map.Entry<String, ? extends List<? extends DataSetQuery>> entry : chartsQueries.entrySet())
Map<String, ChartQuery> chartQueries = query.getChartQueries();
Map<String, ChartQuery> chartQueriesRe = new HashMap<String, ChartQuery>(chartQueries.size());
for (Map.Entry<String, ChartQuery> entry : chartQueries.entrySet())
{
String chartId = entry.getKey();
ChartQuery chartQuery = entry.getValue();
Chart chart = dashboard.getChart(chartId);
if(chart == null)
continue;
ChartDataSet[] chartDataSets = chart.getChartDataSets();
if (chartDataSets == null || chartDataSets.length == 0)
if (chart == null)
throw new IllegalInputException("Chart '" + chartId + "' not found");
ChartDataSet[] chartDataSets = chart.getChartDataSets();
List<DataSetQuery> dataSetQueries = chartQuery.getDataSetQueries();
ChartQuery chartQueryRe = null;
if (chartDataSets == null || chartDataSets.length == 0 || dataSetQueries == null
|| dataSetQueries.isEmpty())
{
re.put(entry.getKey(), Collections.emptyList());
chartQueryRe = chartQuery;
}
else
{
List<? extends DataSetQuery> rawQueries = chartsQueries.get(chartId);
List<DataSetQuery> reQueries = new ArrayList<DataSetQuery>();
if (chartDataSets != null && chartDataSets.length > 0)
List<DataSetQuery> dataSetQueriesRe = new ArrayList<DataSetQuery>(dataSetQueries.size());
for (int j = 0; j < chartDataSets.length; j++)
{
for(int j = 0; j<chartDataSets.length; j++)
{
DataSetQuery reQuery = rawQueries.get(j);
reQuery = getDataSetParamValueConverter().convert(reQuery, chartDataSets[j].getDataSet(), true);
reQueries.add(reQuery);
}
DataSetQuery dataSetQueryRe = dataSetQueries.get(j);
dataSetQueryRe = getDataSetParamValueConverter().convert(dataSetQueryRe, chartDataSets[j].getDataSet(), true);
dataSetQueriesRe.add(dataSetQueryRe);
}
re.put(chartId, reQueries);
chartQueryRe = chartQuery.copy();
chartQueryRe.setDataSetQueries(dataSetQueriesRe);
}
chartQueriesRe.put(chartId, chartQueryRe);
}
return re;
DashboardQuery queryRe = query.copy();
queryRe.setChartQueries(chartQueriesRe);
return queryRe;
}
protected SessionHtmlTplDashboardManager getSessionHtmlTplDashboardManagerNotNull(HttpServletRequest request)
@ -317,18 +316,19 @@ public abstract class AbstractDataAnalysisController extends AbstractController
}
}
public static class DashboardUpdateDataForm
/**
* 看板查询表单
*
*/
public static class DashboardQueryForm
{
/**更新数据的看板ID*/
private String dashboardId;
/**更新数据的图表ID*/
private List<String> chartIds;
/**更新数据的图表查询*/
private Map<String, List<DataSetQuery>> chartQueries;
/** 看板查询 */
private DashboardQuery dashboardQuery;
public DashboardUpdateDataForm()
public DashboardQueryForm()
{
super();
}
@ -343,24 +343,14 @@ public abstract class AbstractDataAnalysisController extends AbstractController
this.dashboardId = dashboardId;
}
public List<String> getChartIds()
public DashboardQuery getDashboardQuery()
{
return chartIds;
return dashboardQuery;
}
public void setChartIds(List<String> chartIds)
public void setDashboardQuery(DashboardQuery dashboardQuery)
{
this.chartIds = chartIds;
}
public Map<String, List<DataSetQuery>> getChartQueries()
{
return chartQueries;
}
public void setChartQueries(Map<String, List<DataSetQuery>> chartQueries)
{
this.chartQueries = chartQueries;
this.dashboardQuery = dashboardQuery;
}
}
}

View File

@ -12,7 +12,6 @@ import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@ -20,11 +19,12 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.datagear.analysis.ChartPluginManager;
import org.datagear.analysis.DashboardResult;
import org.datagear.analysis.DataSetQuery;
import org.datagear.analysis.DataSetResult;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.ResultDataFormat;
import org.datagear.analysis.TemplateDashboardWidgetResManager;
import org.datagear.analysis.support.ErrorMessageDashboardResult;
import org.datagear.analysis.support.html.HtmlChartPlugin;
import org.datagear.analysis.support.html.HtmlTplDashboard;
import org.datagear.analysis.support.html.HtmlTplDashboardRenderAttr;
@ -392,11 +392,13 @@ public class ChartController extends AbstractChartPluginAwareController implemen
*/
@RequestMapping(value = "/showData", produces = CONTENT_TYPE_JSON)
@ResponseBody
public Map<String, DataSetResult[]> showData(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, @RequestBody DashboardUpdateDataForm form) throws Exception
public ErrorMessageDashboardResult showData(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, @RequestBody DashboardQueryForm form) throws Exception
{
WebContext webContext = createWebContext(request);
return getDashboardData(request, response, model, webContext, form);
DashboardResult dashboardResult = getDashboardResult(request, response, model, webContext, form);
return new ErrorMessageDashboardResult(dashboardResult);
}
/**

View File

@ -29,9 +29,10 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.datagear.analysis.Chart;
import org.datagear.analysis.DataSetResult;
import org.datagear.analysis.DashboardResult;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.TemplateDashboardWidgetResManager;
import org.datagear.analysis.support.ErrorMessageDashboardResult;
import org.datagear.analysis.support.html.HtmlChart;
import org.datagear.analysis.support.html.HtmlChartWidget;
import org.datagear.analysis.support.html.HtmlChartWidgetJsonWriter;
@ -999,11 +1000,13 @@ public class DashboardController extends AbstractDataAnalysisController implemen
*/
@RequestMapping(value = "/showData", produces = CONTENT_TYPE_JSON)
@ResponseBody
public Map<String, DataSetResult[]> showData(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, @RequestBody DashboardUpdateDataForm form) throws Exception
public ErrorMessageDashboardResult showData(HttpServletRequest request, HttpServletResponse response,
org.springframework.ui.Model model, @RequestBody DashboardQueryForm form) throws Exception
{
WebContext webContext = createWebContext(request);
return getDashboardData(request, response, model, webContext, form);
DashboardResult dashboardResult = getDashboardResult(request, response, model, webContext, form);
return new ErrorMessageDashboardResult(dashboardResult);
}
/**

View File

@ -94,13 +94,12 @@
/**
* 更新看板数据配置需与后台保持一致具体参考
* org.datagear.web.controller.AbstractDataAnalysisController.DashboardUpdateDataForm
* org.datagear.web.controller.AbstractDataAnalysisController.DashboardQueryForm
*/
dashboardFactory.updateDashboardConfig = (dashboardFactory.updateDashboardConfig ||
{
dashboardIdParamName: "dashboardId",
chartIdsParamName: "chartIds",
chartQueriesParamName: "chartQueries"
dashboardQueryParamName: "dashboardQuery",
});
/**
@ -1320,23 +1319,28 @@
type : "POST",
url : url,
data : JSON.stringify(data),
success : function(resultsMap)
success : function(dashboardResult)
{
var chartResults = (dashboardResult.chartResults || {});
var chartResultErrorMessages = (dashboardResult.chartResultErrorMessages || {});
// < @deprecated 用于兼容1.10.1版本的DataSetResult.datas结构未来版本会移除
if(resultsMap)
if(chartResults)
{
for(var chartId in resultsMap)
for(var chartId in chartResults)
{
var results = (resultsMap[chartId] || []);
for(var i=0; i<results.length; i++)
var chartResult = (chartResults[chartId] || {});
var dataSetResults = (chartResult ? chartResult.dataSetResults : []);
for(var i=0; i<dataSetResults.length; i++)
{
if(results[i] && results[i].data != null)
if(dataSetResults[i] && dataSetResults[i].data != null)
{
var resultDatas = results[i].data;
var resultDatas = dataSetResults[i].data;
if(resultDatas != null && !$.isArray(resultDatas))
resultDatas = [ resultDatas ];
results[i].datas = resultDatas;
dataSetResults[i].datas = resultDatas;
}
}
}
@ -1345,10 +1349,20 @@
var updateTime = new Date().getTime();
dashboard._setUpdateTime(preUpdateCharts, updateTime);
try
{
dashboard._setUpdateTime(preUpdateCharts, updateTime);
dashboard._updateCharts(resultsMap);
dashboard._updateCharts(chartResults);
}
catch(e)
{
chartFactory.logException(e);
}
try
{
dashboard._handleChartResultErrors(chartResultErrorMessages);
}
catch(e)
{
@ -1407,21 +1421,68 @@
};
/**
* 更新看板的图表数据
* 处理看板图表结果错误
*
* @param resultsMap 图表ID - 图表数据集结果数组
* @param chartResultErrorMessages [图表ID-图表结果错误]映射表
*/
dashboardBase._updateCharts = function(resultsMap)
dashboardBase._handleChartResultErrors = function(chartResultErrorMessages)
{
for(var chartId in resultsMap)
if(!chartResultErrorMessages)
return;
for(var chartId in chartResultErrorMessages)
{
var chart = this.chartOf(chartId);
if(!chart)
continue;
var results = resultsMap[chartId];
this._updateChart(chart, results);
this._handleChartResultError(chart, chartResultErrorMessages[chartId]);
}
};
/**
* 处理看板图表结果错误
*
* @param chart 图表对象
* @param chartResultErrorMessage 图表结果错误信息对象
*/
dashboardBase._handleChartResultError = function(chart, chartResultErrorMessage)
{
//设置为更新出错状态避免更新失败后会_doHandleCharts中会无限尝试更新
chart.status(chartStatusConst.UPDATE_ERROR);
var errorType = (chartResultErrorMessage ? chartResultErrorMessage.type : "Error");
var errorMessage = (chartResultErrorMessage ? chartResultErrorMessage.message : "Chart result error");
try
{
chartFactory.logException(errorType + " : " + errorMessage);
}
catch(e)
{
chartFactory.logException(e);
}
};
/**
* 更新看板的图表数据
*
* @param chartResults [图表ID-图表结果]映射表
*/
dashboardBase._updateCharts = function(chartResults)
{
if(!chartResults)
return;
for(var chartId in chartResults)
{
var chart = this.chartOf(chartId);
if(!chart)
continue;
this._updateChart(chart, chartResults[chartId]);
}
};
@ -1429,13 +1490,15 @@
* 更新指定图表
*
* @param chart 图表对象
* @param results 图表数据集结果数组
* @param chartResult 图表结果对象
*/
dashboardBase._updateChart = function(chart, results)
dashboardBase._updateChart = function(chart, chartResult)
{
var dataSetResults = (chartResult ? chartResult.dataSetResults : []);
try
{
this._doUpdateChart(chart, results);
this._doUpdateChart(chart, dataSetResults);
}
catch(e)
{
@ -1488,50 +1551,37 @@
{
var updateDashboardConfig = dashboardFactory.updateDashboardConfig;
var data = {};
data[updateDashboardConfig.dashboardIdParamName] = this.id;
var dashboardQueryForm = {};
var dashboardQuery = { chartQueries: {}, resultDataFormat: this.resultDataFormat(), suppressChartError: true };
dashboardQueryForm[updateDashboardConfig.dashboardIdParamName] = this.id;
dashboardQueryForm[updateDashboardConfig.dashboardQueryParamName] = dashboardQuery;
if(charts && charts.length)
{
var chartIds = [];
var chartQueries = {};
for(var i=0; i<charts.length; i++)
{
var chart = charts[i];
var chartId = chart.id;
var chartQuery = { dataSetQueries: [], resultDataFormat: chart.resultDataFormat() };
if(chartQuery.resultDataFormat == null)
chartQuery.resultDataFormat = this.resultDataFormat();
var chartDataSets = (chart.chartDataSets || []);
var myQueries = [];
for(var j=0; j<chartDataSets.length; j++)
{
var myQuery = (chartDataSets[j].query || {});
//结果数据格式优先级:查询级 > 图表级 > 看板级
var myRdf = myQuery.resultDataFormat;
if(myRdf == null)
myRdf = chart.resultDataFormat();
if(myRdf == null)
myRdf = this.resultDataFormat();
if(myRdf != null)
{
myQuery = $.extend({}, myQuery);
myQuery.resultDataFormat = myRdf;
}
myQueries.push(myQuery);
var dataSetQuery = (chartDataSets[j].query || {});
chartQuery.dataSetQueries.push(dataSetQuery);
}
chartIds[i] = chartId;
chartQueries[chartId] = myQueries;
dashboardQuery.chartQueries[chartId] = chartQuery;
}
data[updateDashboardConfig.chartIdsParamName] = chartIds;
data[updateDashboardConfig.chartQueriesParamName] = chartQueries;
}
return data;
return dashboardQueryForm;
};
/**