forked from p81075629/datagear
Merge remote-tracking branch 'origin/dev-1.12.0'
This commit is contained in:
commit
104c81a3f4
12
README.md
12
README.md
|
@ -8,16 +8,16 @@ DataGear是一款数据可视化分析平台,使用Java语言开发,采用
|
|||
## 系统特点
|
||||
|
||||
- 可管理数据库驱动
|
||||
<br>管理员可通过驱动程序管理功能添加数据库驱动程序,无需重启,即可支持连接新数据库。
|
||||
<br>可通过驱动程序管理功能添加数据库驱动程序,无需重启,即可支持连接新数据库。
|
||||
|
||||
- 参数化数据集
|
||||
<br>可编写动态SQL语句数据集,为其添加参数,构建可交互式图表。
|
||||
- 多种格式的数据集
|
||||
<br>支持SQL、CSV、Excel、HTTP接口、JSON等多种格式的数据集。
|
||||
|
||||
- 多数据源聚合图表
|
||||
<br>一个图表可添加多个不同数据源的数据集,将它们聚合展示于同一图表。
|
||||
- 多数据集聚合图表
|
||||
<br>一个图表可添加多个不同格式的数据集,将它们聚合展示。
|
||||
|
||||
- 插件式图表类型
|
||||
<br>每一种类型的图表都以图表插件形式提供支持,并内置了大量图表插件,管理员也可上传自定义图表插件,丰富系统图表类型。
|
||||
<br>每一种类型的图表都以图表插件形式提供,并内置了大量图表插件,管理员也可上传自定义图表插件,丰富系统图表类型。
|
||||
|
||||
- 可自由编辑的HTML看板模板
|
||||
<br>看板使用原生的HTML网页作为模板,可自由编辑、绑定、异步加载图表,并支持将任意HTML网页导入为看板。
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
下一主版本:
|
||||
|
||||
扩展数据集功能,支持Excel、HTTP API数据集;
|
||||
|
||||
|
||||
下一修订版本:
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
|||
|
||||
待定:
|
||||
|
||||
数据分析添加项目概念,用于分组管理数据集、图表、看板;
|
||||
组合数据集:新建组合数据集(CombineDataSet),选定多个其他数据集,通过SQL语句连接、选取它们,生成新的数据;
|
||||
全局看板资源管理功能;
|
||||
图表参数;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<version>1.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-analysis</artifactId>
|
||||
|
@ -44,6 +44,31 @@
|
|||
<artifactId>freemarker</artifactId>
|
||||
<version>${freemarker.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-csv</artifactId>
|
||||
<version>${commons-csv.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${poi-ooxml.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
<version>5.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path</artifactId>
|
||||
<version>2.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -72,6 +72,9 @@ public interface DataSet extends Identifiable
|
|||
|
||||
/**
|
||||
* 获取{@linkplain DataSetResult}。
|
||||
* <p>
|
||||
* 返回结果中的数据项应已转换为与{@linkplain #getProperties()}的{@linkplain DataSetProperty#getType()}类型一致。
|
||||
* </p>
|
||||
*
|
||||
* @param paramValues
|
||||
* 由{@linkplain #getParams()}所描述的参数值映射表,其关键字是{@linkplain DataSetParam#getName()}
|
||||
|
|
|
@ -11,14 +11,8 @@ package org.datagear.analysis;
|
|||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.util.StringUtil;
|
||||
|
||||
/**
|
||||
* 数据集属性信息。
|
||||
* <p>
|
||||
|
@ -67,53 +61,11 @@ public class DataSetProperty extends AbstractDataNameType implements Serializabl
|
|||
}
|
||||
|
||||
/**
|
||||
* 连接给定列表的{@linkplain #getLabel()}。
|
||||
* <p>
|
||||
* 如果{@code dataSetProperties}为{@code null},将返回空字符串。
|
||||
* </p>
|
||||
* {@linkplain DataSetProperty#getType()}类型枚举。
|
||||
*
|
||||
* @param dataSetProperties
|
||||
* @param splitter
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public static String concatLabels(List<DataSetProperty> dataSetProperties, String splitter)
|
||||
{
|
||||
if (dataSetProperties == null)
|
||||
return "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < dataSetProperties.size(); i++)
|
||||
{
|
||||
DataSetProperty dataSetProperty = dataSetProperties.get(i);
|
||||
|
||||
String label = dataSetProperty.getLabel();
|
||||
if (!StringUtil.isEmpty(label))
|
||||
{
|
||||
if (sb.length() > 0)
|
||||
sb.append(splitter);
|
||||
|
||||
sb.append(label);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拆分由{@linkplain #concatLabels(List, String)}连接的字符串。
|
||||
*
|
||||
* @param labelText
|
||||
* @param splitter
|
||||
* @return
|
||||
*/
|
||||
public static String[] splitLabels(String labelText, String splitter)
|
||||
{
|
||||
if (labelText == null)
|
||||
return new String[0];
|
||||
|
||||
return StringUtil.split(labelText, splitter, true);
|
||||
}
|
||||
|
||||
public static class DataType
|
||||
{
|
||||
/** 字符串 */
|
||||
|
@ -143,270 +95,6 @@ public class DataSetProperty extends AbstractDataNameType implements Serializabl
|
|||
/** 未知类型 */
|
||||
public static final String UNKNOWN = "UNKNOWN";
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #STRING}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isString(String dataType)
|
||||
{
|
||||
return STRING.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #BOOLEAN}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isBoolean(String dataType)
|
||||
{
|
||||
return BOOLEAN.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #NUMBER}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNumber(String dataType)
|
||||
{
|
||||
return NUMBER.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #INTEGER}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isInteger(String dataType)
|
||||
{
|
||||
return INTEGER.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #DECIMAL}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDecimal(String dataType)
|
||||
{
|
||||
return DECIMAL.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是数值型的。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNumberic(String dataType)
|
||||
{
|
||||
return (isNumber(dataType) || isInteger(dataType) || isDecimal(dataType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #DATE}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDate(String dataType)
|
||||
{
|
||||
return DATE.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #TIME}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isTime(String dataType)
|
||||
{
|
||||
return TIME.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #TIMESTAMP}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isTimestamp(String dataType)
|
||||
{
|
||||
return TIMESTAMP.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是{@linkplain #UNKNOWN}。
|
||||
*
|
||||
* @param dataType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isUnknown(String dataType)
|
||||
{
|
||||
return UNKNOWN.equals(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #STRING}类型的值转换为{@linkplain String}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain String}类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static String castString(Object value)
|
||||
{
|
||||
return (String) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #BOOLEAN}类型的值转换为{@linkplain Boolean}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain Boolean}类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static Boolean castBoolean(Object value)
|
||||
{
|
||||
return (Boolean) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #INTEGER}类型的值转换为{@linkplain Number}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain Number}或其子类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static Number castInteger(Object value)
|
||||
{
|
||||
return (Number) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #INTEGER}类型的值转换为{@linkplain BigInteger}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain Number}或其子类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static BigInteger castBigInteger(Object value)
|
||||
{
|
||||
Number number = castInteger(value);
|
||||
|
||||
if (number == null)
|
||||
return null;
|
||||
else if (number instanceof BigInteger)
|
||||
return (BigInteger) number;
|
||||
else
|
||||
return BigInteger.valueOf(number.longValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #DECIMAL}类型的值转换为{@linkplain Number}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain Number}或其子类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static Number castDecimal(Object value)
|
||||
{
|
||||
return (Number) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #DECIMAL}类型的值转换为{@linkplain BigDecimal}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain Number}或其子类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static BigDecimal castBigDecimal(Object value)
|
||||
{
|
||||
Number number = castInteger(value);
|
||||
|
||||
if (number == null)
|
||||
return null;
|
||||
else if (number instanceof BigDecimal)
|
||||
return (BigDecimal) number;
|
||||
else
|
||||
return BigDecimal.valueOf(number.doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #DATE}类型的值转换为{@linkplain Date}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain Date}或其子类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static Date castDate(Object value)
|
||||
{
|
||||
return (Date) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #TIME}类型的值转换为{@linkplain Time}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain Date}或其子类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static Time castTime(Object value)
|
||||
{
|
||||
Date date = castDate(value);
|
||||
|
||||
if (date == null)
|
||||
return null;
|
||||
else if (date instanceof Time)
|
||||
return (Time) value;
|
||||
else
|
||||
return new Time(date.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain #TIME}类型的值转换为{@linkplain Timestamp}值。
|
||||
* <p>
|
||||
* {@code value}参数必须是{@linkplain Date}或其子类型。
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static Timestamp castTimestamp(Object value)
|
||||
{
|
||||
Date date = castDate(value);
|
||||
|
||||
if (date == null)
|
||||
return null;
|
||||
else if (date instanceof Timestamp)
|
||||
return (Timestamp) value;
|
||||
else
|
||||
return new Timestamp(date.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析对象的数据类型。
|
||||
*
|
||||
|
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvableDataSet;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.datagear.util.IOUtil;
|
||||
|
||||
/**
|
||||
* 抽象CSV数据集。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractCsvDataSet extends AbstractResolvableDataSet implements ResolvableDataSet
|
||||
{
|
||||
/** 作为名称行的行号 */
|
||||
private int nameRow = -1;
|
||||
|
||||
public AbstractCsvDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AbstractCsvDataSet(String id, String name)
|
||||
{
|
||||
super(id, name);
|
||||
}
|
||||
|
||||
public AbstractCsvDataSet(String id, String name, List<DataSetProperty> properties)
|
||||
{
|
||||
super(id, name, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有名称行。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasNameRow()
|
||||
{
|
||||
return (this.nameRow > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取作为名称行的行号。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getNameRow()
|
||||
{
|
||||
return nameRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置作为名称行的行号。
|
||||
*
|
||||
* @param nameRow
|
||||
* 行号,小于{@code 1}则表示无名称行。
|
||||
*/
|
||||
public void setNameRow(int nameRow)
|
||||
{
|
||||
this.nameRow = nameRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析结果。
|
||||
* <p>
|
||||
* 如果{@linkplain #getCsvReader(Map)}返回的{@linkplain TemplateResolvedSource#hasResolvedTemplate()},
|
||||
* 此方法将返回{@linkplain TemplateResolvedDataSetResult}。
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
protected ResolvedDataSetResult resolveResult(Map<String, ?> paramValues, List<DataSetProperty> properties)
|
||||
throws DataSetException
|
||||
{
|
||||
TemplateResolvedSource<Reader> reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
reader = getCsvReader(paramValues);
|
||||
|
||||
ResolvedDataSetResult result = resolveResult(reader.getSource(), properties);
|
||||
|
||||
if (reader.hasResolvedTemplate())
|
||||
result = new TemplateResolvedDataSetResult(result.getResult(), result.getProperties(),
|
||||
reader.getResolvedTemplate());
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (reader != null)
|
||||
IOUtil.close(reader.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取CSV输入流。
|
||||
* <p>
|
||||
* 实现方法应该返回实例级不变的输入流。
|
||||
* </p>
|
||||
*
|
||||
* @param paramValues
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected abstract TemplateResolvedSource<Reader> getCsvReader(Map<String, ?> paramValues) throws Throwable;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected ResolvedDataSetResult resolveResult(Reader csvReader, List<DataSetProperty> properties) throws Throwable
|
||||
{
|
||||
boolean resolveProperties = (properties == null || properties.isEmpty());
|
||||
|
||||
CSVParser csvParser = buildCSVParser(csvReader);
|
||||
|
||||
List<String> propertyNames = null;
|
||||
List<List<Object>> data = new ArrayList<>();
|
||||
|
||||
DataSetPropertyValueConverter converter = createDataSetPropertyValueConverter();
|
||||
|
||||
int rowIdx = 0;
|
||||
int dataRowIdx = 0;
|
||||
|
||||
for (CSVRecord csvRecord : csvParser)
|
||||
{
|
||||
if (isNameRow(rowIdx))
|
||||
{
|
||||
if (resolveProperties)
|
||||
propertyNames = resolveDataSetPropertyNames(csvRecord, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resolveProperties && dataRowIdx == 0 && propertyNames == null)
|
||||
propertyNames = resolveDataSetPropertyNames(csvRecord, true);
|
||||
|
||||
if (resolveProperties)
|
||||
data.add(resolveCSVRecordValues(csvRecord, null, converter));
|
||||
else
|
||||
data.add(resolveCSVRecordValues(csvRecord, properties, converter));
|
||||
|
||||
dataRowIdx++;
|
||||
}
|
||||
|
||||
rowIdx++;
|
||||
}
|
||||
|
||||
if (resolveProperties)
|
||||
return resolveResult(propertyNames, ((List) data));
|
||||
else
|
||||
{
|
||||
DataSetResult result = new DataSetResult(listRowsToMapRows(data, properties));
|
||||
return new ResolvedDataSetResult(result, properties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 由原始的字符串CSV数据解析{@linkplain ResolvedDataSetResult}。
|
||||
*
|
||||
* @param propertyNames
|
||||
* 允许为{@code null}
|
||||
* @param data
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected ResolvedDataSetResult resolveResult(List<String> propertyNames, List<List<String>> data) throws Throwable
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>((propertyNames == null ? 0 : propertyNames.size()));
|
||||
|
||||
if (propertyNames != null)
|
||||
{
|
||||
for (String name : propertyNames)
|
||||
properties.add(new DataSetProperty(name, DataSetProperty.DataType.STRING));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> resultData = Collections.EMPTY_LIST;
|
||||
|
||||
// 根据数据格式,修订可能的数值类型:只有某一列的所有字符串都是数值格式,才认为是数值类型
|
||||
if (data != null)
|
||||
{
|
||||
int plen = properties.size();
|
||||
|
||||
// 指定索引的字符串是否都是数值内容
|
||||
Map<Integer, Boolean> asNumberMap = new HashMap<>();
|
||||
|
||||
for (List<String> ele : data)
|
||||
{
|
||||
for (int i = 0; i < Math.min(plen, ele.size()); i++)
|
||||
{
|
||||
Boolean asNumber = asNumberMap.get(i);
|
||||
|
||||
if (Boolean.FALSE.equals(asNumber))
|
||||
continue;
|
||||
|
||||
String val = ele.get(i);
|
||||
asNumberMap.put(i, isNumberString(val));
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, Boolean> entry : asNumberMap.entrySet())
|
||||
{
|
||||
if (Boolean.TRUE.equals(entry.getValue()))
|
||||
properties.get(entry.getKey()).setType(DataSetProperty.DataType.NUMBER);
|
||||
}
|
||||
|
||||
List<List<Object>> newData = new ArrayList<>(data.size());
|
||||
|
||||
for (List<String> ele : data)
|
||||
{
|
||||
int size = Math.min(plen, ele.size());
|
||||
|
||||
List<Object> newEle = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
String val = ele.get(i);
|
||||
|
||||
if (Boolean.TRUE.equals(asNumberMap.get(i)))
|
||||
{
|
||||
Number num = parseNumberString(val);
|
||||
newEle.add(num);
|
||||
}
|
||||
else
|
||||
newEle.add(val);
|
||||
}
|
||||
|
||||
newData.add(newEle);
|
||||
}
|
||||
|
||||
resultData = listRowsToMapRows(newData, properties);
|
||||
}
|
||||
|
||||
DataSetResult result = new DataSetResult(resultData);
|
||||
|
||||
return new ResolvedDataSetResult(result, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定的CSV值是否可被当做数值类型。
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
protected boolean isNumberString(String value)
|
||||
{
|
||||
if (value == null || value.isEmpty())
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
parseNumberString(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析数值字符串,{@linkplain #isNumberString(String)}应为{@code true}。
|
||||
*
|
||||
* @param s
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected Number parseNumberString(String s) throws Throwable
|
||||
{
|
||||
return Double.parseDouble(s);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param csvRecord
|
||||
* @param forceIndex
|
||||
* 是否强制使用索引号,将返回:{@code ["1"、"2"、....]}
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected List<String> resolveDataSetPropertyNames(CSVRecord csvRecord, boolean forceIndex) throws Throwable
|
||||
{
|
||||
int size = csvRecord.size();
|
||||
List<String> list = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (forceIndex)
|
||||
list.add(Integer.toString(i + 1));
|
||||
else
|
||||
list.add(csvRecord.get(i));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析数据列表。
|
||||
* <p>
|
||||
* 如果{@code properties}为{@code null}或者对应元素为{@code null},则返回列表对应元素将是{@linkplain String}类型。
|
||||
* </p>
|
||||
*
|
||||
* @param csvRecord
|
||||
* @param properties
|
||||
* 允许为{@code null}、元素为{@code null}
|
||||
* @param converter
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected List<Object> resolveCSVRecordValues(CSVRecord csvRecord, List<DataSetProperty> properties,
|
||||
DataSetPropertyValueConverter converter) throws Throwable
|
||||
{
|
||||
int size = csvRecord.size();
|
||||
List<Object> list = new ArrayList<>(size);
|
||||
|
||||
int propertySize = (properties == null ? 0 : properties.size());
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
DataSetProperty property = (i < propertySize ? properties.get(i) : null);
|
||||
|
||||
String rawValue = csvRecord.get(i);
|
||||
|
||||
if (property == null)
|
||||
list.add(rawValue);
|
||||
else
|
||||
{
|
||||
Object value = convertToPropertyDataType(converter, rawValue, property);
|
||||
list.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否名称行
|
||||
*
|
||||
* @param rowIndex
|
||||
* 行索引(以{@code 0}计数)
|
||||
* @return
|
||||
*/
|
||||
protected boolean isNameRow(int rowIndex)
|
||||
{
|
||||
return ((rowIndex + 1) == this.nameRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建{@linkplain CSVParser}。
|
||||
*
|
||||
* @param reader
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected CSVParser buildCSVParser(Reader reader) throws Throwable
|
||||
{
|
||||
return CSVFormat.DEFAULT.withIgnoreSurroundingSpaces().parse(reader);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.util.IOUtil;
|
||||
|
||||
/**
|
||||
* 抽象CSV文件数据集。
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractCsvFileDataSet extends AbstractCsvDataSet
|
||||
{
|
||||
/** 文件编码 */
|
||||
private String encoding = IOUtil.CHARSET_UTF_8;
|
||||
|
||||
public AbstractCsvFileDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AbstractCsvFileDataSet(String id, String name)
|
||||
{
|
||||
super(id, name);
|
||||
}
|
||||
|
||||
public AbstractCsvFileDataSet(String id, String name, List<DataSetProperty> properties)
|
||||
{
|
||||
super(id, name, properties);
|
||||
}
|
||||
|
||||
public String getEncoding()
|
||||
{
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public void setEncoding(String encoding)
|
||||
{
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TemplateResolvedSource<Reader> getCsvReader(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
File file = getCsvFile(paramValues);
|
||||
return new TemplateResolvedSource<>(IOUtil.getReader(file, this.encoding));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取CSV文件。
|
||||
* <p>
|
||||
* 实现方法应该返回实例级不变的文件。
|
||||
* </p>
|
||||
*
|
||||
* @param paramValues
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected abstract File getCsvFile(Map<String, ?> paramValues) throws Throwable;
|
||||
}
|
|
@ -7,7 +7,9 @@
|
|||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -25,6 +27,9 @@ import org.datagear.analysis.DataSetProperty;
|
|||
*/
|
||||
public abstract class AbstractDataSet extends AbstractIdentifiable implements DataSet
|
||||
{
|
||||
/** 默认Freemarker模板解析器 */
|
||||
public static final DataSetFmkTemplateResolver FMK_TEMPLATE_RESOLVER = new DataSetFmkTemplateResolver();
|
||||
|
||||
private String name;
|
||||
|
||||
private List<DataSetProperty> properties;
|
||||
|
@ -32,9 +37,13 @@ public abstract class AbstractDataSet extends AbstractIdentifiable implements Da
|
|||
@SuppressWarnings("unchecked")
|
||||
private List<DataSetParam> params = Collections.EMPTY_LIST;
|
||||
|
||||
/** 属性数据转换格式 */
|
||||
private DataFormat propertyDataFormat = null;
|
||||
|
||||
public AbstractDataSet()
|
||||
{
|
||||
super();
|
||||
setPropertyDataFormat(new DataFormat());
|
||||
}
|
||||
|
||||
public AbstractDataSet(String id, String name, List<DataSetProperty> properties)
|
||||
|
@ -42,6 +51,7 @@ public abstract class AbstractDataSet extends AbstractIdentifiable implements Da
|
|||
super(id);
|
||||
this.name = name;
|
||||
this.properties = properties;
|
||||
setPropertyDataFormat(new DataFormat());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,6 +104,24 @@ public abstract class AbstractDataSet extends AbstractIdentifiable implements Da
|
|||
return getDataNameTypeByName(this.params, name);
|
||||
}
|
||||
|
||||
public DataFormat getPropertyDataFormat()
|
||||
{
|
||||
return propertyDataFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置属性数据转换格式。
|
||||
* <p>
|
||||
* 当{@linkplain DataSetProperty#getType()}不是结果数据的原始类型,而需要进行类型转换时,需要使用数据转换格式进行转换。
|
||||
* </p>
|
||||
*
|
||||
* @param propertyDataFormat
|
||||
*/
|
||||
public void setPropertyDataFormat(DataFormat propertyDataFormat)
|
||||
{
|
||||
this.propertyDataFormat = propertyDataFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady(Map<String, ?> paramValues)
|
||||
{
|
||||
|
@ -111,6 +139,76 @@ public abstract class AbstractDataSet extends AbstractIdentifiable implements Da
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将源对象转换为指定{@linkplain DataSetProperty.DataType}类型的对象。
|
||||
* <p>
|
||||
* 如果{@code property}为{@code null},则什么也不做直接返回。
|
||||
* </p>
|
||||
*
|
||||
* @param converter
|
||||
* @param source
|
||||
* @param property
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
*/
|
||||
protected Object convertToPropertyDataType(DataSetPropertyValueConverter converter, Object source,
|
||||
DataSetProperty property)
|
||||
{
|
||||
if (property == null)
|
||||
return source;
|
||||
|
||||
return convertToPropertyDataType(converter, source, property.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将源对象转换为指定{@linkplain DataSetProperty.DataType}类型的对象。
|
||||
* <p>
|
||||
* 如果{@code propertyType}为{@code null},则什么也不做直接返回。
|
||||
* </p>
|
||||
*
|
||||
* @param converter
|
||||
* @param source
|
||||
* @param propertyType
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
*/
|
||||
protected Object convertToPropertyDataType(DataSetPropertyValueConverter converter, Object source,
|
||||
String propertyType)
|
||||
{
|
||||
if (propertyType == null || DataSetProperty.DataType.UNKNOWN.equals(propertyType))
|
||||
return source;
|
||||
|
||||
return converter.convert(source, propertyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个{@linkplain DataSetPropertyValueConverter}实例。
|
||||
* <p>
|
||||
* 由于{@linkplain DataSetPropertyValueConverter}不是线程安全的,所以每次使用时要手动创建。
|
||||
* </p>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected DataSetPropertyValueConverter createDataSetPropertyValueConverter()
|
||||
{
|
||||
DataFormat dataFormat = this.propertyDataFormat;
|
||||
if (dataFormat == null)
|
||||
dataFormat = new DataFormat();
|
||||
|
||||
return new DataSetPropertyValueConverter(dataFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析{@linkplain DataSetProperty.DataType}类型。
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
protected String resolvePropertyDataType(Object value)
|
||||
{
|
||||
return DataSetProperty.DataType.resolveDataType(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定名称的{@linkplain DataNameType}对象,没找到则返回{@code null}。
|
||||
*
|
||||
|
@ -133,4 +231,60 @@ public abstract class AbstractDataSet extends AbstractIdentifiable implements Da
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<Map<String, Object>> listRowsToMapRows(List<List<Object>> data, List<DataSetProperty> properties)
|
||||
{
|
||||
if (data == null)
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
int plen = properties.size();
|
||||
|
||||
List<Map<String, Object>> maps = new ArrayList<>(data.size());
|
||||
|
||||
for (List<Object> row : data)
|
||||
{
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < Math.min(plen, row.size()); i++)
|
||||
{
|
||||
String name = properties.get(i).getName();
|
||||
map.put(name, row.get(i));
|
||||
}
|
||||
|
||||
maps.add(map);
|
||||
}
|
||||
|
||||
return maps;
|
||||
}
|
||||
|
||||
/**
|
||||
* 只有当{@linkplain #hasParam()}为{@code true}时才将指定文本作为Freemarker模板解析。
|
||||
*
|
||||
* @param text
|
||||
* @param paramValues
|
||||
* @return
|
||||
*/
|
||||
protected String resolveAsFmkTemplateIfHasParam(String text, Map<String, ?> paramValues)
|
||||
{
|
||||
if (!hasParam())
|
||||
return text;
|
||||
|
||||
return resolveAsFmkTemplate(text, paramValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定文本作为Freemarker模板解析。
|
||||
*
|
||||
* @param text
|
||||
* @param paramValues
|
||||
* @return
|
||||
*/
|
||||
protected String resolveAsFmkTemplate(String text, Map<String, ?> paramValues)
|
||||
{
|
||||
if (text == null)
|
||||
return null;
|
||||
|
||||
return FMK_TEMPLATE_RESOLVER.resolve(text, paramValues);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.openxml4j.opc.PackageAccess;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvableDataSet;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.datagear.analysis.support.RangeExpResolver.IndexRange;
|
||||
import org.datagear.analysis.support.RangeExpResolver.Range;
|
||||
import org.datagear.util.FileUtil;
|
||||
import org.datagear.util.IOUtil;
|
||||
import org.datagear.util.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 抽象Excel数据集。
|
||||
* <p>
|
||||
* 此类仅支持从Excel的单个sheet读取数据,具体参考{@linkplain #setSheetIndex(int)}。
|
||||
* </p>
|
||||
* <p>
|
||||
* 通过{@linkplain #setDataRowExp(String)}、{@linkplain #setDataColumnExp(String)}来设置读取行、列范围。
|
||||
* </p>
|
||||
* <p>
|
||||
* 通过{@linkplain #setNameRow(int)}可设置名称行。
|
||||
* </p>
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractExcelDataSet extends AbstractResolvableDataSet implements ResolvableDataSet
|
||||
{
|
||||
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractExcelDataSet.class);
|
||||
|
||||
public static final String EXTENSION_XLSX = "xlsx";
|
||||
|
||||
public static final String EXTENSION_XLS = "xls";
|
||||
|
||||
protected static final RangeExpResolver RANGE_EXP_RESOLVER = RangeExpResolver
|
||||
.valueOf(RangeExpResolver.RANGE_SPLITTER_CHAR, RangeExpResolver.RANGE_GROUP_SPLITTER_CHAR);
|
||||
|
||||
/** 此数据集所处的sheet索引号(以1计数) */
|
||||
private int sheetIndex = 1;
|
||||
|
||||
/** 作为名称行的行号 */
|
||||
private int nameRow = -1;
|
||||
|
||||
/** 数据行范围表达式 */
|
||||
private String dataRowExp = "";
|
||||
|
||||
/** 数据列范围表达式 */
|
||||
private String dataColumnExp = "";
|
||||
|
||||
/** 是否强制作为xls文件处理 */
|
||||
private boolean forceXls = false;
|
||||
|
||||
private transient List<IndexRange> _dataRowRanges = null;
|
||||
private transient List<IndexRange> _dataColumnRanges = null;
|
||||
|
||||
public AbstractExcelDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AbstractExcelDataSet(String id, String name)
|
||||
{
|
||||
super(id, name);
|
||||
}
|
||||
|
||||
public AbstractExcelDataSet(String id, String name, List<DataSetProperty> properties)
|
||||
{
|
||||
super(id, name, properties);
|
||||
}
|
||||
|
||||
public int getSheetIndex()
|
||||
{
|
||||
return sheetIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置此数据集所处的sheet号。
|
||||
*
|
||||
* @param sheetIndex
|
||||
* sheet号(以{@code 1}计数)
|
||||
*/
|
||||
public void setSheetIndex(int sheetIndex)
|
||||
{
|
||||
this.sheetIndex = sheetIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有名称行。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasNameRow()
|
||||
{
|
||||
return (this.nameRow > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取作为名称行的行号。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getNameRow()
|
||||
{
|
||||
return nameRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置作为名称行的行号。
|
||||
*
|
||||
* @param nameRow
|
||||
* 行号,小于{@code 1}则表示无名称行。
|
||||
*/
|
||||
public void setNameRow(int nameRow)
|
||||
{
|
||||
this.nameRow = nameRow;
|
||||
}
|
||||
|
||||
public String getDataRowExp()
|
||||
{
|
||||
return dataRowExp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据行范围表达式。
|
||||
* <p>
|
||||
* 表达式格式示例为:
|
||||
* </p>
|
||||
* <p>
|
||||
* {@code "6"} :第6行 <br>
|
||||
* {@code "3-15"} :第3至15行 <br>
|
||||
* {@code "1,4,8-15"}:第1、4、8至15行
|
||||
* </p>
|
||||
* <p>
|
||||
* 标题行({@linkplain #getNameRow()})将自动被排除。
|
||||
* </p>
|
||||
* <p>
|
||||
* 注意:行号以{@code 1}开始计数。
|
||||
* </p>
|
||||
*
|
||||
* @param dataRowExp
|
||||
* 表达式,为{@code null}、{@code ""}则不限定
|
||||
*/
|
||||
public void setDataRowExp(String dataRowExp)
|
||||
{
|
||||
this.dataRowExp = dataRowExp;
|
||||
this._dataRowRanges = getRangeExpResolver().resolveIndex(this.dataRowExp);
|
||||
}
|
||||
|
||||
public String getDataColumnExp()
|
||||
{
|
||||
return dataColumnExp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据列范围表达式。
|
||||
* <p>
|
||||
* 表达式格式为:
|
||||
* </p>
|
||||
* <p>
|
||||
* {@code "A"}:第A列 <br>
|
||||
* {@code "C-E"}:第C至E列 <br>
|
||||
* {@code "A,C,E-H"}:第A、C、E至H列
|
||||
* </p>
|
||||
*
|
||||
* @param dataColumnExp
|
||||
* 表达式,为{@code null}、{@code ""}则不限定
|
||||
*/
|
||||
public void setDataColumnExp(String dataColumnExp)
|
||||
{
|
||||
this.dataColumnExp = dataColumnExp;
|
||||
this._dataColumnRanges = resolveDataColumnRanges(dataColumnExp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否强制作为xls文件处理。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isForceXls()
|
||||
{
|
||||
return forceXls;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否强制作为xls文件处理,如果为{@code false},则根据文件扩展名判断。
|
||||
*
|
||||
* @param forceXls
|
||||
*/
|
||||
public void setForceXls(boolean forceXls)
|
||||
{
|
||||
this.forceXls = forceXls;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResolvedDataSetResult resolveResult(Map<String, ?> paramValues, List<DataSetProperty> properties)
|
||||
throws DataSetException
|
||||
{
|
||||
File file = getExcelFile(paramValues);
|
||||
|
||||
ResolvedDataSetResult result = null;
|
||||
|
||||
if (isXls(file))
|
||||
result = resolveResultForXls(paramValues, file, properties);
|
||||
else
|
||||
result = resolveResultForXlsx(paramValues, file, properties);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析{@code xls}结果。
|
||||
*
|
||||
* @param paramValues
|
||||
* @param file
|
||||
* @param properties
|
||||
* 允许为{@code null},此时会自动解析
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected ResolvedDataSetResult resolveResultForXls(Map<String, ?> paramValues, File file,
|
||||
List<DataSetProperty> properties) throws DataSetException
|
||||
{
|
||||
POIFSFileSystem poifs = null;
|
||||
HSSFWorkbook wb = null;
|
||||
|
||||
try
|
||||
{
|
||||
poifs = new POIFSFileSystem(file, true);
|
||||
wb = new HSSFWorkbook(poifs.getRoot(), true);
|
||||
|
||||
Sheet sheet = wb.getSheetAt(getSheetIndex() - 1);
|
||||
|
||||
return resolveResultForSheet(paramValues, sheet, properties);
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(wb);
|
||||
IOUtil.close(poifs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析{@code xlsx}结果。
|
||||
*
|
||||
* @param paramValues
|
||||
* @param file
|
||||
* @param properties
|
||||
* 允许为{@code null},此时会自动解析
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected ResolvedDataSetResult resolveResultForXlsx(Map<String, ?> paramValues, File file,
|
||||
List<DataSetProperty> properties) throws DataSetException
|
||||
{
|
||||
OPCPackage pkg = null;
|
||||
XSSFWorkbook wb = null;
|
||||
|
||||
try
|
||||
{
|
||||
pkg = OPCPackage.open(file, PackageAccess.READ);
|
||||
wb = new XSSFWorkbook(pkg);
|
||||
|
||||
Sheet sheet = wb.getSheetAt(getSheetIndex() - 1);
|
||||
|
||||
return resolveResultForSheet(paramValues, sheet, properties);
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(wb);
|
||||
IOUtil.close(pkg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析sheet结果。
|
||||
*
|
||||
* @param paramValues
|
||||
* @param sheet
|
||||
* @param properties
|
||||
* 允许为{@code null},此时会自动解析
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected ResolvedDataSetResult resolveResultForSheet(Map<String, ?> paramValues, Sheet sheet,
|
||||
List<DataSetProperty> properties) throws DataSetException
|
||||
{
|
||||
boolean resolveProperties = (properties == null || properties.isEmpty());
|
||||
|
||||
if (resolveProperties)
|
||||
properties = new ArrayList<>();
|
||||
|
||||
List<List<Object>> data = new ArrayList<>();
|
||||
|
||||
List<String> propertyNames = null;
|
||||
|
||||
DataSetPropertyValueConverter converter = createDataSetPropertyValueConverter();
|
||||
|
||||
try
|
||||
{
|
||||
int rowIdx = 0;
|
||||
int dataRowIdx = 0;
|
||||
|
||||
for (Row row : sheet)
|
||||
{
|
||||
if (isNameRow(rowIdx))
|
||||
{
|
||||
if (resolveProperties)
|
||||
propertyNames = resolveDataSetPropertyNames(row, false);
|
||||
}
|
||||
else if (isDataRow(rowIdx))
|
||||
{
|
||||
if (resolveProperties && dataRowIdx == 0 && propertyNames == null)
|
||||
propertyNames = resolveDataSetPropertyNames(row, true);
|
||||
|
||||
// 名称行不一定在数据行之前,此时可能还无法确定属性名,所以暂时采用列表存储
|
||||
List<Object> rowObj = new ArrayList<>();
|
||||
|
||||
int colIdx = 0;
|
||||
int dataColIdx = 0;
|
||||
|
||||
for (Cell cell : row)
|
||||
{
|
||||
if (isDataColumn(colIdx))
|
||||
{
|
||||
DataSetProperty property = null;
|
||||
|
||||
if (!resolveProperties)
|
||||
{
|
||||
if (dataColIdx >= properties.size())
|
||||
throw new DataSetSourceParseException(
|
||||
"No property defined for column index " + dataColIdx);
|
||||
|
||||
property = properties.get(dataColIdx);
|
||||
}
|
||||
|
||||
Object value = resolvePropertyValue(cell, property, converter);
|
||||
|
||||
if (resolveProperties)
|
||||
{
|
||||
property = resolveDataSetProperty(row, rowIdx, dataRowIdx, cell, colIdx, dataColIdx,
|
||||
value, properties);
|
||||
}
|
||||
|
||||
rowObj.add(value);
|
||||
|
||||
dataColIdx++;
|
||||
}
|
||||
|
||||
colIdx++;
|
||||
}
|
||||
|
||||
data.add(rowObj);
|
||||
|
||||
dataRowIdx++;
|
||||
}
|
||||
|
||||
rowIdx++;
|
||||
}
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
|
||||
if (resolveProperties)
|
||||
inflateDataSetProperties(properties, propertyNames);
|
||||
|
||||
DataSetResult result = new DataSetResult(listRowsToMapRows(data, properties));
|
||||
|
||||
return new ResolvedDataSetResult(result, properties);
|
||||
}
|
||||
|
||||
protected void inflateDataSetProperties(List<DataSetProperty> properties, List<String> propertyNames)
|
||||
{
|
||||
for (int i = 0; i < properties.size(); i++)
|
||||
{
|
||||
DataSetProperty property = properties.get(i);
|
||||
property.setName(propertyNames.get(i));
|
||||
|
||||
if (StringUtil.isEmpty(property.getType()))
|
||||
property.setType(DataSetProperty.DataType.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析{@linkplain DataSetProperty}并写入{@code properties}。
|
||||
*
|
||||
* @param row
|
||||
* @param rowIdx
|
||||
* @param dataRowIdx
|
||||
* @param cell
|
||||
* @param colIdx
|
||||
* @param dataColIdx
|
||||
* @param cellValue
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
protected DataSetProperty resolveDataSetProperty(Row row, int rowIdx, int dataRowIdx, Cell cell, int colIdx,
|
||||
int dataColIdx, Object cellValue, List<DataSetProperty> properties)
|
||||
{
|
||||
DataSetProperty property = null;
|
||||
|
||||
if (dataRowIdx == 0)
|
||||
{
|
||||
// 空单元格先不处理数据类型,等待后续有非空单元格再判断
|
||||
String dataType = (cellValue == null ? "" : resolvePropertyDataType(cellValue));
|
||||
|
||||
// 名称行不一定在数据行之前,所以此时可能无法确定属性名
|
||||
property = new DataSetProperty("should-be-set-later", dataType);
|
||||
properties.add(property);
|
||||
}
|
||||
else
|
||||
{
|
||||
property = properties.get(dataColIdx);
|
||||
|
||||
if (StringUtil.isEmpty(property.getType()) && cellValue != null)
|
||||
property.setType(resolvePropertyDataType(cellValue));
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析属性名。
|
||||
*
|
||||
* @param nameRow
|
||||
* @return
|
||||
*/
|
||||
protected List<String> resolveDataSetPropertyNames(Row nameRow, boolean forceColumnString)
|
||||
{
|
||||
List<String> propertyNames = new ArrayList<>();
|
||||
|
||||
int colIdx = 0;
|
||||
for (Cell cell : nameRow)
|
||||
{
|
||||
if (isDataColumn(colIdx))
|
||||
{
|
||||
String name = null;
|
||||
|
||||
if (forceColumnString)
|
||||
name = CellReference.convertNumToColString(colIdx);
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
name = cell.getStringCellValue();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
}
|
||||
|
||||
if (StringUtil.isEmpty(name))
|
||||
name = CellReference.convertNumToColString(colIdx);
|
||||
}
|
||||
|
||||
propertyNames.add(name);
|
||||
}
|
||||
|
||||
colIdx++;
|
||||
}
|
||||
|
||||
return propertyNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析单元格属性值。
|
||||
*
|
||||
* @param cell
|
||||
* @param property
|
||||
* 允许为{@code null}
|
||||
* @param converter
|
||||
* @return
|
||||
* @throws DataSetSourceParseException
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected Object resolvePropertyValue(Cell cell, DataSetProperty property, DataSetPropertyValueConverter converter)
|
||||
throws DataSetSourceParseException, DataSetException
|
||||
{
|
||||
CellType cellType = cell.getCellTypeEnum();
|
||||
|
||||
Object cellValue = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (CellType.BLANK.equals(cellType))
|
||||
{
|
||||
cellValue = null;
|
||||
}
|
||||
else if (CellType.BOOLEAN.equals(cellType))
|
||||
{
|
||||
cellValue = cell.getBooleanCellValue();
|
||||
}
|
||||
else if (CellType.ERROR.equals(cellType))
|
||||
{
|
||||
cellValue = cell.getErrorCellValue();
|
||||
}
|
||||
else if (CellType.FORMULA.equals(cellType))
|
||||
{
|
||||
cellValue = cell.getCellFormula();
|
||||
}
|
||||
else if (CellType.NUMERIC.equals(cellType))
|
||||
{
|
||||
if (DateUtil.isCellDateFormatted(cell))
|
||||
cellValue = cell.getDateCellValue();
|
||||
else
|
||||
cellValue = cell.getNumericCellValue();
|
||||
}
|
||||
else if (CellType.STRING.equals(cellType))
|
||||
{
|
||||
cellValue = cell.getStringCellValue();
|
||||
}
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
|
||||
cellValue = convertToPropertyDataType(converter, cellValue, property);
|
||||
|
||||
return cellValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否名称行
|
||||
*
|
||||
* @param rowIndex
|
||||
* 行索引(以{@code 0}计数)
|
||||
* @return
|
||||
*/
|
||||
protected boolean isNameRow(int rowIndex)
|
||||
{
|
||||
return ((rowIndex + 1) == this.nameRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数据行。
|
||||
*
|
||||
* @param rowIndex
|
||||
* 行索引(以{@code 0}计数)
|
||||
* @return
|
||||
*/
|
||||
protected boolean isDataRow(int rowIndex)
|
||||
{
|
||||
if (isNameRow(rowIndex))
|
||||
return false;
|
||||
|
||||
if (this._dataRowRanges == null || this._dataRowRanges.isEmpty())
|
||||
return true;
|
||||
|
||||
return IndexRange.includes(this._dataRowRanges, rowIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数据列。
|
||||
*
|
||||
* @param columnIndex
|
||||
* 列索引(以{@code 0}计数)
|
||||
* @return
|
||||
*/
|
||||
protected boolean isDataColumn(int columnIndex)
|
||||
{
|
||||
if (this._dataColumnRanges == null || this._dataColumnRanges.isEmpty())
|
||||
return true;
|
||||
|
||||
return IndexRange.includes(this._dataColumnRanges, columnIndex);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<IndexRange> resolveDataColumnRanges(String dataColumnExp) throws DataSetException
|
||||
{
|
||||
List<Range> ranges = getRangeExpResolver().resolve(dataColumnExp);
|
||||
|
||||
if (ranges == null || ranges.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
List<IndexRange> indexRanges = new ArrayList<>(ranges.size());
|
||||
|
||||
for (Range range : ranges)
|
||||
{
|
||||
int from = 0;
|
||||
int to = -1;
|
||||
|
||||
String fromStr = range.trimFrom();
|
||||
String toStr = range.trimTo();
|
||||
|
||||
if (!StringUtil.isEmpty(fromStr))
|
||||
from = CellReference.convertColStringToIndex(fromStr);
|
||||
|
||||
if (!StringUtil.isEmpty(toStr))
|
||||
to = CellReference.convertColStringToIndex(toStr);
|
||||
|
||||
indexRanges.add(new IndexRange(from, to));
|
||||
}
|
||||
|
||||
return indexRanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给定Excel文件是否是老版本的{@code .xls}文件。
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
protected boolean isXls(File file)
|
||||
{
|
||||
if (this.forceXls)
|
||||
return true;
|
||||
|
||||
return FileUtil.isExtension(file, EXTENSION_XLS);
|
||||
}
|
||||
|
||||
protected RangeExpResolver getRangeExpResolver()
|
||||
{
|
||||
return RANGE_EXP_RESOLVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Excel文件。
|
||||
* <p>
|
||||
* 实现方法应该返回实例级不变的文件。
|
||||
* </p>
|
||||
*
|
||||
* @param paramValues
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected abstract File getExcelFile(Map<String, ?> paramValues) throws DataSetException;
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
|
||||
/**
|
||||
* 抽象Freemarker模板{@linkplain DataSet}。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractFmkTemplateDataSet extends AbstractDataSet
|
||||
{
|
||||
public static final DataSetFmkTemplateResolver TEMPLATE_RESOLVER = new DataSetFmkTemplateResolver();
|
||||
|
||||
public AbstractFmkTemplateDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AbstractFmkTemplateDataSet(String id, String name, List<DataSetProperty> properties)
|
||||
{
|
||||
super(id, name, properties);
|
||||
}
|
||||
|
||||
protected String resolveTemplate(String template, Map<String, ?> paramValues)
|
||||
{
|
||||
if (template == null)
|
||||
return null;
|
||||
|
||||
return TEMPLATE_RESOLVER.resolve(template, paramValues);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,10 @@
|
|||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -16,6 +19,18 @@ import org.datagear.analysis.DataSetProperty;
|
|||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvableDataSet;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.datagear.util.IOUtil;
|
||||
import org.datagear.util.StringUtil;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.node.ValueNode;
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
||||
|
||||
/**
|
||||
* 抽象JSON数据集。
|
||||
|
@ -23,19 +38,23 @@ import org.datagear.analysis.ResolvedDataSetResult;
|
|||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractJsonDataSet extends AbstractFmkTemplateDataSet implements ResolvableDataSet
|
||||
public abstract class AbstractJsonDataSet extends AbstractResolvableDataSet implements ResolvableDataSet
|
||||
{
|
||||
public static final JsonDataSetSupport JSON_DATA_SET_SUPPORT = new JsonDataSetSupport();
|
||||
/** 使用Jackson的{@code JSONPath}配置 */
|
||||
protected static final Configuration JACKSON_JSON_PATH_CONFIGURATION = Configuration.builder()
|
||||
.jsonProvider(new JacksonJsonProvider()).mappingProvider(new JacksonMappingProvider()).build();
|
||||
|
||||
/** 数据JSON路径 */
|
||||
private String dataJsonPath = "";
|
||||
|
||||
public AbstractJsonDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public AbstractJsonDataSet(String id, String name)
|
||||
{
|
||||
super(id, name, Collections.EMPTY_LIST);
|
||||
super(id, name);
|
||||
}
|
||||
|
||||
public AbstractJsonDataSet(String id, String name, List<DataSetProperty> properties)
|
||||
|
@ -43,17 +62,350 @@ public abstract class AbstractJsonDataSet extends AbstractFmkTemplateDataSet imp
|
|||
super(id, name, properties);
|
||||
}
|
||||
|
||||
protected JsonDataSetSupport getJsonDataSetSupport()
|
||||
public String getDataJsonPath()
|
||||
{
|
||||
return JSON_DATA_SET_SUPPORT;
|
||||
return dataJsonPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedDataSetResult resolve(Map<String, ?> paramValues) throws DataSetException
|
||||
/**
|
||||
* 设置数据JSON路径。
|
||||
* <p>
|
||||
* 当希望返回的是原始JSON数据的指定JSON路径值时,可以设置此项。
|
||||
* </p>
|
||||
* <p>
|
||||
* 例如:"stores[0].books"、"[1].stores"、"$['store']['book'][0]"、
|
||||
* "$.store.book[*].author"、"$..book[2]",具体参考{@code JSONPath}相关文档。
|
||||
* </p>
|
||||
* <p>
|
||||
* 默认无数据路径,将直接返回原始JSON数据。
|
||||
* </p>
|
||||
*
|
||||
* @param dataJsonPath
|
||||
*/
|
||||
public void setDataJsonPath(String dataJsonPath)
|
||||
{
|
||||
DataSetResult result = getResult(paramValues);
|
||||
List<DataSetProperty> properties = getJsonDataSetSupport().resolveDataSetProperties(result.getData());
|
||||
this.dataJsonPath = dataJsonPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析结果。
|
||||
* <p>
|
||||
* 如果{@linkplain #getJsonReader(Map)}返回的{@linkplain TemplateResolvedSource#hasResolvedTemplate()},
|
||||
* 此方法将返回{@linkplain TemplateResolvedDataSetResult}。
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
protected ResolvedDataSetResult resolveResult(Map<String, ?> paramValues, List<DataSetProperty> properties)
|
||||
throws DataSetException
|
||||
{
|
||||
TemplateResolvedSource<Reader> reader = null;
|
||||
try
|
||||
{
|
||||
reader = getJsonReader(paramValues);
|
||||
|
||||
ResolvedDataSetResult result = resolveResult(reader.getSource(), properties);
|
||||
|
||||
if (reader.hasResolvedTemplate())
|
||||
result = new TemplateResolvedDataSetResult(result.getResult(), result.getProperties(),
|
||||
reader.getResolvedTemplate());
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (reader != null)
|
||||
IOUtil.close(reader.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取JSON输入流。
|
||||
* <p>
|
||||
* 实现方法应该返回实例级不变的输入流。
|
||||
* </p>
|
||||
*
|
||||
* @param paramValues
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected abstract TemplateResolvedSource<Reader> getJsonReader(Map<String, ?> paramValues) throws Throwable;
|
||||
|
||||
/**
|
||||
* 解析结果。
|
||||
*
|
||||
* @param jsonReader
|
||||
* JSON输入流
|
||||
* @param properties
|
||||
* 允许为{@code null},此时会自动解析
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected ResolvedDataSetResult resolveResult(Reader jsonReader, List<DataSetProperty> properties) throws Throwable
|
||||
{
|
||||
boolean resolveProperties = (properties == null || properties.isEmpty());
|
||||
|
||||
JsonNode jsonNode = getObjectMapperNonStardand().readTree(jsonReader);
|
||||
|
||||
if (!isLegalResultDataJsonNode(jsonNode))
|
||||
throw new UnsupportedJsonResultDataException("Result data must be JSON object or array");
|
||||
|
||||
Object data = null;
|
||||
|
||||
if (jsonNode != null)
|
||||
data = readDataByJsonPath(jsonNode, getDataJsonPath());
|
||||
|
||||
if (resolveProperties)
|
||||
properties = resolveDataSetProperties(data);
|
||||
|
||||
if (!resolveProperties)
|
||||
data = convertJsonResultData(data, properties, createDataSetPropertyValueConverter());
|
||||
|
||||
DataSetResult result = new DataSetResult(data);
|
||||
|
||||
return new ResolvedDataSetResult(result, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取指定JSON路径的数据。
|
||||
*
|
||||
* @param jsonNode
|
||||
* 允许为{@code null}
|
||||
* @param dataJsonPath
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
* @throws ReadJsonDataPathException
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected Object readDataByJsonPath(JsonNode jsonNode, String dataJsonPath)
|
||||
throws ReadJsonDataPathException, Throwable
|
||||
{
|
||||
if (jsonNode == null)
|
||||
return null;
|
||||
|
||||
Object data = getObjectMapperNonStardand().treeToValue(jsonNode, Object.class);
|
||||
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
if (StringUtil.isEmpty(dataJsonPath))
|
||||
return data;
|
||||
|
||||
String stdDataJsonPath = dataJsonPath.trim();
|
||||
|
||||
if (StringUtil.isEmpty(stdDataJsonPath))
|
||||
return data;
|
||||
|
||||
// 转换"stores[0].books"、"[1].stores"简化模式为规范的JSONPath
|
||||
if (!stdDataJsonPath.startsWith("$"))
|
||||
{
|
||||
if (stdDataJsonPath.startsWith("["))
|
||||
stdDataJsonPath = "$" + stdDataJsonPath;
|
||||
else
|
||||
stdDataJsonPath = "$." + stdDataJsonPath;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonPath.compile(stdDataJsonPath).read(data, JACKSON_JSON_PATH_CONFIGURATION);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new ReadJsonDataPathException(dataJsonPath, t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param resultData
|
||||
* 允许为{@code null}
|
||||
* @param properties
|
||||
* @param converter
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected Object convertJsonResultData(Object resultData, List<DataSetProperty> properties,
|
||||
DataSetPropertyValueConverter converter) throws Throwable
|
||||
{
|
||||
Object re = null;
|
||||
|
||||
// JSON对象
|
||||
if (resultData == null)
|
||||
{
|
||||
re = null;
|
||||
}
|
||||
else if (resultData instanceof Map<?, ?>)
|
||||
{
|
||||
Map<String, Object> reMap = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> source = (Map<String, Object>) resultData;
|
||||
|
||||
for (Map.Entry<String, Object> entry : source.entrySet())
|
||||
{
|
||||
String name = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
|
||||
DataSetProperty property = getDataNameTypeByName(properties, name);
|
||||
|
||||
value = convertToPropertyDataType(converter, value, property);
|
||||
|
||||
reMap.put(name, value);
|
||||
}
|
||||
|
||||
re = reMap;
|
||||
}
|
||||
else if (resultData instanceof List<?>)
|
||||
{
|
||||
List<?> list = (List<?>) resultData;
|
||||
|
||||
List<Object> reList = new ArrayList<>(list.size());
|
||||
|
||||
for (Object ele : list)
|
||||
reList.add(convertJsonResultData(ele, properties, converter));
|
||||
|
||||
re = reList;
|
||||
}
|
||||
else if (resultData instanceof Object[])
|
||||
{
|
||||
Object[] array = (Object[]) resultData;
|
||||
|
||||
Object[] reArray = new Object[array.length];
|
||||
|
||||
for (int i = 0; i < array.length; i++)
|
||||
reArray[i] = convertJsonResultData(array[i], properties, converter);
|
||||
|
||||
re = reArray;
|
||||
}
|
||||
else
|
||||
throw new UnsupportedJsonResultDataException("Result data must be object or object array/list");
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是合法的数据集结果数据{@linkplain JsonNode}。
|
||||
* <p>
|
||||
* 参考{@linkplain DataSetResult#getData()}说明。
|
||||
* </p>
|
||||
*
|
||||
* @param jsonNode
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
*/
|
||||
protected boolean isLegalResultDataJsonNode(JsonNode jsonNode) throws Throwable
|
||||
{
|
||||
if (jsonNode == null || jsonNode.isNull())
|
||||
return true;
|
||||
|
||||
if (jsonNode instanceof ValueNode)
|
||||
return false;
|
||||
|
||||
if (jsonNode instanceof ArrayNode)
|
||||
{
|
||||
ArrayNode arrayNode = (ArrayNode) jsonNode;
|
||||
|
||||
for (int i = 0; i < arrayNode.size(); i++)
|
||||
{
|
||||
JsonNode eleNode = arrayNode.get(i);
|
||||
|
||||
if (eleNode == null || eleNode.isNull())
|
||||
continue;
|
||||
|
||||
if (!(eleNode instanceof ObjectNode))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON对象的{@linkplain DataSetProperty}。
|
||||
*
|
||||
* @param resultData
|
||||
* 允许为{@code null},JSON对象、JSON对象数组、JSON对象列表
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<DataSetProperty> resolveDataSetProperties(Object resultData) throws Throwable
|
||||
{
|
||||
if (resultData == null)
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
else if (resultData instanceof Map<?, ?>)
|
||||
{
|
||||
return resolveJsonObjDataSetProperties((Map<String, ?>) resultData);
|
||||
}
|
||||
else if (resultData instanceof List<?>)
|
||||
{
|
||||
List<?> list = (List<?>) resultData;
|
||||
|
||||
if (list.size() == 0)
|
||||
return Collections.EMPTY_LIST;
|
||||
else
|
||||
return resolveJsonObjDataSetProperties((Map<String, ?>) list.get(0));
|
||||
}
|
||||
else if (resultData instanceof Object[])
|
||||
{
|
||||
Object[] array = (Object[]) resultData;
|
||||
|
||||
if (array.length == 0)
|
||||
return Collections.EMPTY_LIST;
|
||||
else
|
||||
return resolveJsonObjDataSetProperties((Map<String, ?>) array[0]);
|
||||
}
|
||||
else
|
||||
throw new UnsupportedJsonResultDataException("Result data must be object or object array/list");
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON对象的{@linkplain DataSetProperty}。
|
||||
*
|
||||
* @param jsonObj
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected List<DataSetProperty> resolveJsonObjDataSetProperties(Map<String, ?> jsonObj) throws Throwable
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
|
||||
if (jsonObj == null)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Map.Entry<String, ?> entry : jsonObj.entrySet())
|
||||
{
|
||||
Object value = entry.getValue();
|
||||
String type = DataSetProperty.DataType.resolveDataType(value);
|
||||
|
||||
DataSetProperty property = new DataSetProperty(entry.getKey(), type);
|
||||
|
||||
// JSON数值只有NUMBER类型
|
||||
if (DataSetProperty.DataType.INTEGER.equals(property.getType())
|
||||
|| DataSetProperty.DataType.DECIMAL.equals(property.getType()))
|
||||
property.setType(DataSetProperty.DataType.NUMBER);
|
||||
|
||||
properties.add(property);
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
protected ObjectMapper getObjectMapperNonStardand()
|
||||
{
|
||||
return JsonSupport.getObjectMapperNonStardand();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,25 +8,27 @@
|
|||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.util.IOUtil;
|
||||
|
||||
/**
|
||||
* 抽象JSON文件数据集。
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractJsonFileDataSet extends AbstractJsonSourceDataSet
|
||||
public abstract class AbstractJsonFileDataSet extends AbstractJsonDataSet
|
||||
{
|
||||
public static final String DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
/** 文件编码 */
|
||||
private String encoding = DEFAULT_ENCODING;
|
||||
private String encoding = IOUtil.CHARSET_UTF_8;
|
||||
|
||||
public AbstractJsonFileDataSet()
|
||||
{
|
||||
|
@ -54,15 +56,17 @@ public abstract class AbstractJsonFileDataSet extends AbstractJsonSourceDataSet
|
|||
}
|
||||
|
||||
@Override
|
||||
protected DataSetResult getOrginalResult(Map<String, ?> paramValues) throws DataSetException
|
||||
protected TemplateResolvedSource<Reader> getJsonReader(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
File jsonFile = getJsonFile(paramValues);
|
||||
Object data = getJsonDataSetSupport().resolveResultData(jsonFile, getEncoding());
|
||||
return new DataSetResult(data);
|
||||
File file = getJsonFile(paramValues);
|
||||
return new TemplateResolvedSource<>(IOUtil.getReader(file, this.encoding));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取JSON文件。
|
||||
* <p>
|
||||
* 实现方法应该返回实例级不变的文件。
|
||||
* </p>
|
||||
*
|
||||
* @param paramValues
|
||||
* @return
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
|
||||
/**
|
||||
* 抽象JSON源数据集。
|
||||
* <p>
|
||||
* JSON源数据集的一个特点是:源数据是无法编辑的,因此需要定义{@linkplain DataSetResultTransformer}逻辑。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractJsonSourceDataSet extends AbstractJsonDataSet
|
||||
{
|
||||
private DataSetResultTransformer dataSetResultTransformer;
|
||||
|
||||
public AbstractJsonSourceDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public AbstractJsonSourceDataSet(String id, String name)
|
||||
{
|
||||
super(id, name);
|
||||
}
|
||||
|
||||
public AbstractJsonSourceDataSet(String id, String name, List<DataSetProperty> properties)
|
||||
{
|
||||
super(id, name, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取{@linkplain DataSetResultTransformer}。
|
||||
*
|
||||
* @return 可能为{@code null}
|
||||
*/
|
||||
public DataSetResultTransformer getDataSetResultTransformer()
|
||||
{
|
||||
return dataSetResultTransformer;
|
||||
}
|
||||
|
||||
public void setDataSetResultTransformer(DataSetResultTransformer dataSetResultTransformer)
|
||||
{
|
||||
this.dataSetResultTransformer = dataSetResultTransformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSetResult getResult(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
DataSetResult result = getOrginalResult(paramValues);
|
||||
|
||||
if (this.dataSetResultTransformer == null)
|
||||
return result;
|
||||
|
||||
return this.dataSetResultTransformer.transform(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始的{@linkplain DataSetResult}。
|
||||
*
|
||||
* @param paramValues
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected abstract DataSetResult getOrginalResult(Map<String, ?> paramValues) throws DataSetException;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvableDataSet;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
|
||||
/**
|
||||
* 抽象{@linkplain ResolvableDataSet}。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractResolvableDataSet extends AbstractDataSet implements ResolvableDataSet
|
||||
{
|
||||
public AbstractResolvableDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public AbstractResolvableDataSet(String id, String name)
|
||||
{
|
||||
super(id, name, Collections.EMPTY_LIST);
|
||||
}
|
||||
|
||||
public AbstractResolvableDataSet(String id, String name, List<DataSetProperty> properties)
|
||||
{
|
||||
super(id, name, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSetResult getResult(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
List<DataSetProperty> properties = getProperties();
|
||||
|
||||
if (properties == null || properties.isEmpty())
|
||||
throw new DataSetException("[getProperties()] must not be empty");
|
||||
|
||||
ResolvedDataSetResult result = resolveResult(paramValues, properties);
|
||||
|
||||
return result.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedDataSetResult resolve(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
return resolveResult(paramValues, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析结果。
|
||||
*
|
||||
* @param paramValues
|
||||
* @param properties
|
||||
* 允许为{@code null}/空,此时,应自动解析并设置返回结果的{@linkplain ResolvedDataSetResult#setProperties(List)};
|
||||
* 如果不为{@code null}/空,直接将{@code properties}作为解析数据依据, 使用它处理结果数据,
|
||||
* 并设置为返回结果的{@linkplain ResolvedDataSetResult#setProperties(List)}
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected abstract ResolvedDataSetResult resolveResult(Map<String, ?> paramValues, List<DataSetProperty> properties)
|
||||
throws DataSetException;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.util.FileUtil;
|
||||
|
||||
/**
|
||||
* 目录内CSV文件{@linkplain DataSet}。
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class CsvDirectoryFileDataSet extends AbstractCsvFileDataSet
|
||||
{
|
||||
/** JSON文件所在的目录 */
|
||||
private File directory;
|
||||
|
||||
/** JSON文件名 */
|
||||
private String fileName;
|
||||
|
||||
public CsvDirectoryFileDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public CsvDirectoryFileDataSet(String id, String name, File directory, String fileName)
|
||||
{
|
||||
super(id, name);
|
||||
this.directory = directory;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public CsvDirectoryFileDataSet(String id, String name, List<DataSetProperty> properties, File directory,
|
||||
String fileName)
|
||||
{
|
||||
super(id, name, properties);
|
||||
this.directory = directory;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public File getDirectory()
|
||||
{
|
||||
return directory;
|
||||
}
|
||||
|
||||
public void setDirectory(File directory)
|
||||
{
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
public String getFileName()
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getCsvFile(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
File jsonFile = FileUtil.getFile(this.directory, this.fileName);
|
||||
return jsonFile;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.util.IOUtil;
|
||||
|
||||
/**
|
||||
* CSV值数据集。
|
||||
* <p>
|
||||
* 此类的{@linkplain #getValue()}支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class CsvValueDataSet extends AbstractCsvDataSet
|
||||
{
|
||||
/** CSV字符串 */
|
||||
private String value;
|
||||
|
||||
public CsvValueDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public CsvValueDataSet(String id, String name, String value)
|
||||
{
|
||||
super(id, name);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public CsvValueDataSet(String id, String name, List<DataSetProperty> properties, String value)
|
||||
{
|
||||
super(id, name, properties);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置CSV字符串值,格式为:
|
||||
*
|
||||
* <pre>
|
||||
* name, value
|
||||
* aaa, 1
|
||||
* bbb, 2
|
||||
* </pre>
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setValue(String value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateResolvedDataSetResult resolve(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
return (TemplateResolvedDataSetResult) resolveResult(paramValues, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TemplateResolvedSource<Reader> getCsvReader(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
String csv = resolveAsFmkTemplateIfHasParam(this.value, paramValues);
|
||||
return new TemplateResolvedSource<>(IOUtil.getReader(csv), csv);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 数据格式。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class DataFormat implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||
|
||||
public static final String DEFAULT_TIME_FORMAT = "hh:mm:ss";
|
||||
|
||||
public static final String DEFAULT_TIMESTAMP_FORMAT = "yyyy-MM-dd hh:mm:ss";
|
||||
|
||||
public static final String DEFAULT_NUMBER_FORMAT = "#.##########";
|
||||
|
||||
/** 日期格式 */
|
||||
private String dateFormat = DEFAULT_DATE_FORMAT;
|
||||
|
||||
/** 时间格式 */
|
||||
private String timeFormat = DEFAULT_TIME_FORMAT;
|
||||
|
||||
/** 时间戳格式 */
|
||||
private String timestampFormat = DEFAULT_TIMESTAMP_FORMAT;
|
||||
|
||||
/** 数值格式 */
|
||||
private String numberFormat = DEFAULT_NUMBER_FORMAT;
|
||||
|
||||
public DataFormat()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public String getDateFormat()
|
||||
{
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
public void setDateFormat(String dateFormat)
|
||||
{
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
public String getTimeFormat()
|
||||
{
|
||||
return timeFormat;
|
||||
}
|
||||
|
||||
public void setTimeFormat(String timeFormat)
|
||||
{
|
||||
this.timeFormat = timeFormat;
|
||||
}
|
||||
|
||||
public String getTimestampFormat()
|
||||
{
|
||||
return timestampFormat;
|
||||
}
|
||||
|
||||
public void setTimestampFormat(String timestampFormat)
|
||||
{
|
||||
this.timestampFormat = timestampFormat;
|
||||
}
|
||||
|
||||
public String getNumberFormat()
|
||||
{
|
||||
return numberFormat;
|
||||
}
|
||||
|
||||
public void setNumberFormat(String numberFormat)
|
||||
{
|
||||
this.numberFormat = numberFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((dateFormat == null) ? 0 : dateFormat.hashCode());
|
||||
result = prime * result + ((numberFormat == null) ? 0 : numberFormat.hashCode());
|
||||
result = prime * result + ((timeFormat == null) ? 0 : timeFormat.hashCode());
|
||||
result = prime * result + ((timestampFormat == null) ? 0 : timestampFormat.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
DataFormat other = (DataFormat) obj;
|
||||
if (dateFormat == null)
|
||||
{
|
||||
if (other.dateFormat != null)
|
||||
return false;
|
||||
}
|
||||
else if (!dateFormat.equals(other.dateFormat))
|
||||
return false;
|
||||
if (numberFormat == null)
|
||||
{
|
||||
if (other.numberFormat != null)
|
||||
return false;
|
||||
}
|
||||
else if (!numberFormat.equals(other.numberFormat))
|
||||
return false;
|
||||
if (timeFormat == null)
|
||||
{
|
||||
if (other.timeFormat != null)
|
||||
return false;
|
||||
}
|
||||
else if (!timeFormat.equals(other.timeFormat))
|
||||
return false;
|
||||
if (timestampFormat == null)
|
||||
{
|
||||
if (other.timestampFormat != null)
|
||||
return false;
|
||||
}
|
||||
else if (!timestampFormat.equals(other.timestampFormat))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [dateFormat=" + dateFormat + ", timeFormat=" + timeFormat
|
||||
+ ", timestampFormat="
|
||||
+ timestampFormat + ", numberFormat=" + numberFormat + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetProperty.DataType;
|
||||
|
||||
/**
|
||||
* {@linkplain DataSetProperty}值转换器。
|
||||
* <p>
|
||||
* 它支持将对象转换为{@linkplain DataSetProperty.DataType}类型的值。
|
||||
* </p>
|
||||
* <p>
|
||||
* 此类的{@linkplain #convert(java.util.Map, java.util.Collection)}、{@linkplain #convert(Object, String)}不是线程安全的。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class DataSetPropertyValueConverter extends DataValueConverter
|
||||
{
|
||||
private DataFormat dataFormat;
|
||||
|
||||
private SimpleDateFormat _dateFormat = null;
|
||||
private SimpleDateFormat _timeFormat = null;
|
||||
private SimpleDateFormat _timestampFormat = null;
|
||||
private DecimalFormat _numberFormat = null;
|
||||
|
||||
public DataSetPropertyValueConverter()
|
||||
{
|
||||
super();
|
||||
setDataFormat(new DataFormat());
|
||||
}
|
||||
|
||||
public DataSetPropertyValueConverter(DataFormat dataFormat)
|
||||
{
|
||||
super();
|
||||
setDataFormat(new DataFormat());
|
||||
}
|
||||
|
||||
public DataFormat getDataFormat()
|
||||
{
|
||||
return dataFormat;
|
||||
}
|
||||
|
||||
public void setDataFormat(DataFormat dataFormat)
|
||||
{
|
||||
this.dataFormat = dataFormat;
|
||||
|
||||
this._dateFormat = new SimpleDateFormat(dataFormat.getDateFormat());
|
||||
this._timeFormat = new SimpleDateFormat(dataFormat.getTimeFormat());
|
||||
this._timestampFormat = new SimpleDateFormat(dataFormat.getTimestampFormat());
|
||||
this._numberFormat = new DecimalFormat(dataFormat.getNumberFormat());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object convertValue(Object value, String type) throws DataValueConvertionException
|
||||
{
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (type == null)
|
||||
return value;
|
||||
|
||||
try
|
||||
{
|
||||
if (value instanceof String)
|
||||
return convertStringValue((String) value, type);
|
||||
else if (value instanceof Boolean)
|
||||
return convertBooleanValue((Boolean) value, type);
|
||||
else if (value instanceof Number)
|
||||
return convertNumberValue((Number) value, type);
|
||||
else if (value instanceof Time)
|
||||
return convertTimeValue((Time) value, type);
|
||||
else if (value instanceof Timestamp)
|
||||
return convertTimestampValue((Timestamp) value, type);
|
||||
else if (value instanceof java.util.Date)
|
||||
return convertDateValue((java.util.Date) value, type);
|
||||
else
|
||||
{
|
||||
if (DataType.UNKNOWN.equals(type))
|
||||
return value;
|
||||
else
|
||||
throw new DataValueConvertionException(value, type);
|
||||
}
|
||||
}
|
||||
catch (DataValueConvertionException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataValueConvertionException(value, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object convertStringValue(String value, String type) throws Throwable
|
||||
{
|
||||
if (DataType.STRING.equals(type) || DataType.UNKNOWN.equals(type))
|
||||
return value;
|
||||
|
||||
if (value == null || value.isEmpty())
|
||||
return null;
|
||||
|
||||
if (DataType.BOOLEAN.equals(type))
|
||||
return "true".equalsIgnoreCase(value) || "1".equals(value);
|
||||
else if (DataType.NUMBER.equals(type))
|
||||
return this._numberFormat.parse(value);
|
||||
else if (DataType.INTEGER.equals(type))
|
||||
return this._numberFormat.parse(value).intValue();
|
||||
else if (DataType.DECIMAL.equals(type))
|
||||
return this._numberFormat.parse(value).doubleValue();
|
||||
else if (DataType.DATE.equals(type))
|
||||
{
|
||||
java.util.Date date = this._dateFormat.parse(value);
|
||||
return new Date(date.getTime());
|
||||
}
|
||||
else if (DataType.TIME.equals(type))
|
||||
{
|
||||
java.util.Date date = this._timeFormat.parse(value);
|
||||
return new Time(date.getTime());
|
||||
}
|
||||
else if (DataType.TIMESTAMP.equals(type))
|
||||
{
|
||||
java.util.Date date = this._timestampFormat.parse(value);
|
||||
return new Timestamp(date.getTime());
|
||||
}
|
||||
else
|
||||
throw new DataValueConvertionException(value, type);
|
||||
}
|
||||
|
||||
protected Object convertBooleanValue(Boolean value, String type) throws Throwable
|
||||
{
|
||||
if (DataType.BOOLEAN.equals(type) || DataType.UNKNOWN.equals(type))
|
||||
return value;
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (DataType.STRING.equals(type))
|
||||
return value.toString();
|
||||
else if (DataType.NUMBER.equals(type) || DataType.INTEGER.equals(type) || DataType.DECIMAL.equals(type))
|
||||
return (Boolean.TRUE.equals(value) ? 1 : 0);
|
||||
else
|
||||
throw new DataValueConvertionException(value, type);
|
||||
}
|
||||
|
||||
protected Object convertNumberValue(Number value, String type) throws Throwable
|
||||
{
|
||||
if (DataType.NUMBER.equals(type) || DataType.UNKNOWN.equals(type))
|
||||
return value;
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (DataType.STRING.equals(type))
|
||||
return this._numberFormat.format(value);
|
||||
else if (DataType.BOOLEAN.equals(type))
|
||||
return (value.intValue() > 0);
|
||||
else if (DataType.INTEGER.equals(type))
|
||||
return value.longValue();
|
||||
else if (DataType.DECIMAL.equals(type))
|
||||
return value.doubleValue();
|
||||
else if (DataType.DATE.equals(type))
|
||||
return new Date(value.longValue());
|
||||
else if (DataType.TIME.equals(type))
|
||||
return new Time(value.longValue());
|
||||
else if (DataType.TIMESTAMP.equals(type))
|
||||
return new Timestamp(value.longValue());
|
||||
else
|
||||
throw new DataValueConvertionException(value, type);
|
||||
}
|
||||
|
||||
protected Object convertDateValue(java.util.Date value, String type) throws Throwable
|
||||
{
|
||||
if (DataType.UNKNOWN.equals(type))
|
||||
return value;
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (DataType.STRING.equals(type))
|
||||
return this._dateFormat.format(value);
|
||||
else if (DataType.NUMBER.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.INTEGER.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.DECIMAL.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.DATE.equals(type))
|
||||
return new Date(value.getTime());
|
||||
else if (DataType.TIME.equals(type))
|
||||
return new Time(value.getTime());
|
||||
else if (DataType.TIMESTAMP.equals(type))
|
||||
return new Timestamp(value.getTime());
|
||||
else
|
||||
throw new DataValueConvertionException(value, type);
|
||||
}
|
||||
|
||||
protected Object convertTimeValue(Time value, String type) throws Throwable
|
||||
{
|
||||
if (DataType.TIME.equals(type) || DataType.UNKNOWN.equals(type))
|
||||
return value;
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (DataType.STRING.equals(type))
|
||||
return this._timeFormat.format(value);
|
||||
else if (DataType.NUMBER.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.INTEGER.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.DECIMAL.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.DATE.equals(type))
|
||||
return new Date(value.getTime());
|
||||
else if (DataType.TIMESTAMP.equals(type))
|
||||
return new Timestamp(value.getTime());
|
||||
else
|
||||
throw new DataValueConvertionException(value, type);
|
||||
}
|
||||
|
||||
protected Object convertTimestampValue(Timestamp value, String type) throws Throwable
|
||||
{
|
||||
if (DataType.TIMESTAMP.equals(type) || DataType.UNKNOWN.equals(type))
|
||||
return value;
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (DataType.STRING.equals(type))
|
||||
return this._timestampFormat.format(value);
|
||||
else if (DataType.NUMBER.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.INTEGER.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.DECIMAL.equals(type))
|
||||
return value.getTime();
|
||||
else if (DataType.DATE.equals(type))
|
||||
return new Date(value.getTime());
|
||||
else if (DataType.TIME.equals(type))
|
||||
return new Time(value.getTime());
|
||||
else
|
||||
throw new DataValueConvertionException(value, type);
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
|
||||
/**
|
||||
* {@linkplain DataSetResultTransformer}转换异常。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class DataSetResultTransformException extends DataSetException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public DataSetResultTransformException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public DataSetResultTransformException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DataSetResultTransformException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public DataSetResultTransformException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
|
||||
/**
|
||||
* {@linkplain DataSetResult}转换器。
|
||||
* <p>
|
||||
* 某些类型的{@linkplain DataSet}是从不可控制的数据源中读取数据的(比如API调用、JSON文件、CSV文件),
|
||||
* 此类即为这些场景提供支持,使{@linkplain DataSet}支持对数据源的数据进行转换。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public interface DataSetResultTransformer
|
||||
{
|
||||
/**
|
||||
* 转换为新的{@linkplain DataSetResult}。
|
||||
*
|
||||
* @param orginalResult
|
||||
* @return 已转换的{@linkplain DataSetResult}
|
||||
* @throws DataSetResultTransformException
|
||||
*/
|
||||
DataSetResult transform(DataSetResult orginalResult) throws DataSetResultTransformException;
|
||||
}
|
|
@ -23,7 +23,7 @@ public class DataValueConvertionException extends RuntimeException
|
|||
|
||||
public DataValueConvertionException(Object source, String type)
|
||||
{
|
||||
super();
|
||||
super("Convert from [" + source + "] to [" + type + "] is not supported");
|
||||
this.type = type;
|
||||
this.source = source;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.util.FileUtil;
|
||||
|
||||
/**
|
||||
* 目录内Excel文件{@linkplain DataSet}。
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class ExcelDirectoryFileDataSet extends AbstractExcelDataSet
|
||||
{
|
||||
/** Excel文件所在的目录 */
|
||||
private File directory;
|
||||
|
||||
/** Excel文件名 */
|
||||
private String fileName;
|
||||
|
||||
public ExcelDirectoryFileDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ExcelDirectoryFileDataSet(String id, String name, File directory, String fileName)
|
||||
{
|
||||
super(id, name);
|
||||
this.directory = directory;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param name
|
||||
* @param properties
|
||||
*/
|
||||
public ExcelDirectoryFileDataSet(String id, String name, List<DataSetProperty> properties, File directory,
|
||||
String fileName)
|
||||
{
|
||||
super(id, name, properties);
|
||||
this.directory = directory;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public File getDirectory()
|
||||
{
|
||||
return directory;
|
||||
}
|
||||
|
||||
public void setDirectory(File directory)
|
||||
{
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
public String getFileName()
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getExcelFile(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
File excelFile = FileUtil.getFile(this.directory, this.fileName);
|
||||
return excelFile;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
/**
|
||||
* {@linkplain HttpDataSet#getHeaderContent()}不是名/值对象数组JSON异常。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class HeaderContentNotNameValueObjArrayJsonException extends NotNameValueObjArrayJsonException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public HeaderContentNotNameValueObjArrayJsonException(String json)
|
||||
{
|
||||
super(json);
|
||||
}
|
||||
|
||||
public HeaderContentNotNameValueObjArrayJsonException(String json, String message)
|
||||
{
|
||||
super(json, message);
|
||||
}
|
||||
|
||||
public HeaderContentNotNameValueObjArrayJsonException(String json, Throwable cause)
|
||||
{
|
||||
super(json, cause);
|
||||
}
|
||||
|
||||
public HeaderContentNotNameValueObjArrayJsonException(String json, String message, Throwable cause)
|
||||
{
|
||||
super(json, message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,622 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hc.client5.http.HttpResponseException;
|
||||
import org.apache.hc.client5.http.classic.HttpClient;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpDelete;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPatch;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPut;
|
||||
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.ContentType;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.NameValuePair;
|
||||
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
|
||||
import org.apache.hc.core5.http.io.entity.StringEntity;
|
||||
import org.apache.hc.core5.http.message.BasicNameValuePair;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.datagear.util.IOUtil;
|
||||
import org.datagear.util.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* HTTP数据集。
|
||||
* <p>
|
||||
* 此类的{@linkplain #getUri()}、{@linkplain #getHeaderContent()}、{@linkplain #getRequestContent()}支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class HttpDataSet extends AbstractResolvableDataSet
|
||||
{
|
||||
protected static final Logger LOGGER = LoggerFactory.getLogger(HttpDataSet.class);
|
||||
|
||||
public static final String REQUEST_METHOD_GET = "GET";
|
||||
|
||||
public static final String REQUEST_METHOD_POST = "POST";
|
||||
|
||||
public static final String REQUEST_METHOD_PUT = "PUT";
|
||||
|
||||
public static final String REQUEST_METHOD_PATCH = "PATCH";
|
||||
|
||||
public static final String REQUEST_METHOD_DELETE = "DELETE";
|
||||
|
||||
// 这些HTTP方法不适应于此
|
||||
// public static final String REQUEST_METHOD_HEAD = "HEAD";
|
||||
// public static final String REQUEST_METHOD_OPTIONS = "OPTIONS";
|
||||
// public static final String REQUEST_METHOD_TRACE = "TRACE";
|
||||
|
||||
/**
|
||||
* 请求内容类型:表单式的参数名/值类型,对应的HTTP请求类型为:application/x-www-form-urlencoded
|
||||
*/
|
||||
public static final String REQUEST_CONTENT_TYPE_FORM_URLENCODED = "FORM_URLENCODED";
|
||||
|
||||
/**
|
||||
* 请求内容类型:JSON,对应的HTTP请求类型为:application/json
|
||||
*/
|
||||
public static final String REQUEST_CONTENT_TYPE_JSON = "JSON";
|
||||
|
||||
/**
|
||||
* 响应内容类型:JSON,对应的HTTP响应类型为:application/json
|
||||
*/
|
||||
public static final String RESPONSE_CONTENT_TYPE_JSON = "JSON";
|
||||
|
||||
protected static final List<NameValuePair> NOT_NAME_VALUE_PAIR_OBJ_ARRAY_JSON = new ArrayList<>(0);
|
||||
|
||||
/** HTTP客户端 */
|
||||
private HttpClient httpClient;
|
||||
|
||||
/** HTTP请求地址 */
|
||||
private String uri;
|
||||
|
||||
/** 请求头JSON文本 */
|
||||
private String headerContent = "";
|
||||
|
||||
/** 请求方法 */
|
||||
private String requestMethod = REQUEST_METHOD_GET;
|
||||
|
||||
/** 请求内容类型 */
|
||||
private String requestContentType = REQUEST_CONTENT_TYPE_FORM_URLENCODED;
|
||||
|
||||
/** 请求内容编码 */
|
||||
private String requestContentCharset = IOUtil.CHARSET_UTF_8;
|
||||
|
||||
/** 请求内容JSON文本 */
|
||||
private String requestContent = "";
|
||||
|
||||
/** 响应类型 */
|
||||
private String responseContentType = RESPONSE_CONTENT_TYPE_JSON;
|
||||
|
||||
/** 响应数据的JSON路径 */
|
||||
private String responseDataJsonPath = "";
|
||||
|
||||
public HttpDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public HttpDataSet(String id, String name, HttpClient httpClient, String uri)
|
||||
{
|
||||
super(id, name);
|
||||
this.httpClient = httpClient;
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public HttpDataSet(String id, String name, List<DataSetProperty> properties, HttpClient httpClient, String uri)
|
||||
{
|
||||
super(id, name, properties);
|
||||
this.httpClient = httpClient;
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public HttpClient getHttpClient()
|
||||
{
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public void setHttpClient(HttpClient httpClient)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public String getUri()
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求地址。
|
||||
* <p>
|
||||
* 请求地址支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @param uri
|
||||
*/
|
||||
public void setUri(String uri)
|
||||
{
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public String getHeaderContent()
|
||||
{
|
||||
return headerContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求头JSON文本,格式应为:
|
||||
* <p>
|
||||
* <code>
|
||||
* <pre>
|
||||
* [
|
||||
* {name: "...", value: "..."},
|
||||
* {name: "...", value: "..."},
|
||||
* ...
|
||||
* ]
|
||||
* </pre>
|
||||
* </code>
|
||||
* </p>
|
||||
* <p>
|
||||
* 请求头JSON文本支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @param headerContent
|
||||
*/
|
||||
public void setHeaderContent(String headerContent)
|
||||
{
|
||||
this.headerContent = headerContent;
|
||||
}
|
||||
|
||||
public String getRequestMethod()
|
||||
{
|
||||
return requestMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置HTTP方法,参考{@code REQUEST_METHOD_*}常量。
|
||||
*
|
||||
* @param requestMethod
|
||||
*/
|
||||
public void setRequestMethod(String requestMethod)
|
||||
{
|
||||
this.requestMethod = requestMethod;
|
||||
}
|
||||
|
||||
public String getRequestContentType()
|
||||
{
|
||||
return requestContentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求内容类型,允许的值为:
|
||||
* <p>
|
||||
* {@linkplain #REQUEST_CONTENT_TYPE_FORM_URLENCODED}、{@linkplain #REQUEST_CONTENT_TYPE_JSON}。
|
||||
* </p>
|
||||
*
|
||||
* @param requestContentType
|
||||
*/
|
||||
public void setRequestContentType(String requestContentType)
|
||||
{
|
||||
this.requestContentType = requestContentType;
|
||||
}
|
||||
|
||||
public String getRequestContentCharset()
|
||||
{
|
||||
return requestContentCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求内容编码。
|
||||
* <p>
|
||||
* 默认请求内容编码为{@code UTF-8}。
|
||||
* </p>
|
||||
*
|
||||
* @param requestContentCharset
|
||||
*/
|
||||
public void setRequestContentCharset(String requestContentCharset)
|
||||
{
|
||||
this.requestContentCharset = requestContentCharset;
|
||||
}
|
||||
|
||||
public String getRequestContent()
|
||||
{
|
||||
return requestContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求内容JSON文本,为{@code null}或{@code ""}表示无请求内容。
|
||||
* <p>
|
||||
* 当{@linkplain #getRequestContentType()}为{@linkplain #REQUEST_CONTENT_TYPE_FORM_URLENCODED}时,请求内容JSON文本格式应为:
|
||||
* </p>
|
||||
* <code>
|
||||
* <pre>
|
||||
* [
|
||||
* {name: "...", value: "..."},
|
||||
* {name: "...", value: "..."},
|
||||
* ...
|
||||
* ]
|
||||
* </pre>
|
||||
* </code>
|
||||
* <p>
|
||||
* 其中,{@code name}表示请求参数名,{@code value}表示请求参数值。
|
||||
* </p>
|
||||
* <p>
|
||||
* 当{@linkplain #getRequestContentType()}为{@linkplain #REQUEST_CONTENT_TYPE_JSON}时,请求内容JSON文本没有特殊格式要求。
|
||||
* </p>
|
||||
* <p>
|
||||
* 请求内容JSON文本支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @param requestContent
|
||||
*/
|
||||
public void setRequestContent(String requestContent)
|
||||
{
|
||||
this.requestContent = requestContent;
|
||||
}
|
||||
|
||||
public String getResponseContentType()
|
||||
{
|
||||
return responseContentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置相应类型。
|
||||
* <p>
|
||||
* 目前仅支持{@linkplain #RESPONSE_CONTENT_TYPE_JSON},且是默认值。
|
||||
* </p>
|
||||
*
|
||||
* @param responseContentType
|
||||
*/
|
||||
public void setResponseContentType(String responseContentType)
|
||||
{
|
||||
this.responseContentType = responseContentType;
|
||||
}
|
||||
|
||||
public String getResponseDataJsonPath()
|
||||
{
|
||||
return responseDataJsonPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应数据的JSON路径。
|
||||
* <p>
|
||||
* 当希望返回的是响应原始JSON数据的指定JSON路径值时,可以设置此项。
|
||||
* </p>
|
||||
* <p>
|
||||
* 具体格式参考{@linkplain AbstractJsonDataSet#setDataJsonPath(String)}。
|
||||
* </p>
|
||||
* <p>
|
||||
* 默认无数据路径,将直接返回响应原始JSON数据。
|
||||
* </p>
|
||||
*
|
||||
* @param responseDataJsonPath
|
||||
*/
|
||||
public void setResponseDataJsonPath(String responseDataJsonPath)
|
||||
{
|
||||
this.responseDataJsonPath = responseDataJsonPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateResolvedDataSetResult resolve(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
return resolveResult(paramValues, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TemplateResolvedDataSetResult resolveResult(Map<String, ?> paramValues, List<DataSetProperty> properties)
|
||||
throws DataSetException
|
||||
{
|
||||
try
|
||||
{
|
||||
String uri = resolveTemplateUri(paramValues);
|
||||
String headerContent = resolveTemplateHeaderContent(paramValues);
|
||||
String requestContent = resolveTemplateRequestContent(paramValues);
|
||||
|
||||
ClassicHttpRequest request = createHttpRequest(uri);
|
||||
|
||||
setHttpHeaders(request, headerContent);
|
||||
setHttpEntity(request, requestContent);
|
||||
|
||||
JsonResponseHandler responseHandler = new JsonResponseHandler();
|
||||
responseHandler.setProperties(properties);
|
||||
responseHandler.setResponseDataJsonPath(getResponseDataJsonPath());
|
||||
|
||||
ResolvedDataSetResult result = this.httpClient.execute(request, responseHandler);
|
||||
|
||||
String templateResult = "URI:" + System.lineSeparator() + uri //
|
||||
+ System.lineSeparator() + "-----------------------------------------" + System.lineSeparator() //
|
||||
+ "Request headers:" + System.lineSeparator() + headerContent //
|
||||
+ System.lineSeparator() + "-----------------------------------------" + System.lineSeparator() //
|
||||
+ "Request content:" + System.lineSeparator() + requestContent;
|
||||
|
||||
return new TemplateResolvedDataSetResult(result.getResult(), result.getProperties(), templateResult);
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setHttpHeaders(ClassicHttpRequest request, String headerContent) throws Throwable
|
||||
{
|
||||
if (StringUtil.isEmpty(headerContent))
|
||||
return;
|
||||
|
||||
List<NameValuePair> headers = toNameValuePairs(headerContent);
|
||||
|
||||
if (headers == NOT_NAME_VALUE_PAIR_OBJ_ARRAY_JSON)
|
||||
throw new HeaderContentNotNameValueObjArrayJsonException(headerContent);
|
||||
|
||||
for (NameValuePair header : headers)
|
||||
request.setHeader(header.getName(), header.getValue());
|
||||
}
|
||||
|
||||
protected void setHttpEntity(ClassicHttpRequest request, String requestContent) throws Throwable
|
||||
{
|
||||
if (REQUEST_CONTENT_TYPE_FORM_URLENCODED.equals(this.requestContentType))
|
||||
{
|
||||
List<NameValuePair> params = toNameValuePairs(requestContent);
|
||||
|
||||
if (params == NOT_NAME_VALUE_PAIR_OBJ_ARRAY_JSON)
|
||||
throw new RequestContentNotNameValueObjArrayJsonException(requestContent);
|
||||
|
||||
request.setEntity(new UrlEncodedFormEntity(params, Charset.forName(this.requestContentCharset)));
|
||||
}
|
||||
else if (REQUEST_CONTENT_TYPE_JSON.equals(this.requestContentType))
|
||||
{
|
||||
ContentType contentType = ContentType.create(ContentType.APPLICATION_JSON.getMimeType(),
|
||||
Charset.forName(this.requestContentCharset));
|
||||
StringEntity entity = new StringEntity(requestContent, contentType);
|
||||
request.setEntity(entity);
|
||||
}
|
||||
else
|
||||
throw new DataSetException("Request content type [" + this.requestContentType + "] is not supported");
|
||||
}
|
||||
|
||||
protected String resolveTemplateUri(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
return resolveAsFmkTemplateIfHasParam(this.uri, paramValues);
|
||||
}
|
||||
|
||||
protected String resolveTemplateHeaderContent(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
return resolveAsFmkTemplateIfHasParam(this.headerContent, paramValues);
|
||||
}
|
||||
|
||||
protected String resolveTemplateRequestContent(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
return resolveAsFmkTemplateIfHasParam(this.requestContent, paramValues);
|
||||
}
|
||||
|
||||
protected ClassicHttpRequest createHttpRequest(String uri) throws Throwable
|
||||
{
|
||||
if (REQUEST_METHOD_GET.equals(this.requestMethod) || StringUtil.isEmpty(this.requestMethod))
|
||||
return new HttpGet(uri);
|
||||
else if (REQUEST_METHOD_POST.equals(this.requestMethod))
|
||||
return new HttpPost(uri);
|
||||
else if (REQUEST_METHOD_PUT.equals(this.requestMethod))
|
||||
return new HttpPut(uri);
|
||||
else if (REQUEST_METHOD_PATCH.equals(this.requestMethod))
|
||||
return new HttpPatch(uri);
|
||||
else if (REQUEST_METHOD_DELETE.equals(this.requestMethod))
|
||||
return new HttpDelete(uri);
|
||||
// else if (REQUEST_METHOD_HEAD.equals(this.httpMethod))
|
||||
// return new HttpHead(uri);
|
||||
// else if (REQUEST_METHOD_OPTIONS.equals(this.httpMethod))
|
||||
// return new HttpOptions(uri);
|
||||
// else if (REQUEST_METHOD_TRACE.equals(this.httpMethod))
|
||||
// return new HttpTrace(uri);
|
||||
else
|
||||
throw new DataSetException("HTTP method [" + this.requestMethod + "] is not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定JSON字符串转换为名/值列表。
|
||||
*
|
||||
* @param nameValueObjJsonArray
|
||||
* 允许为{@code null}、{@code ""}
|
||||
* @return 空列表表示无名/值,返回{@code #NOT_NAME_VALUE_PAIR_OBJ_ARRAY_JSON}表示{@code nameValueObjJsonArray}格式不合法
|
||||
* @throws Throwable
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<NameValuePair> toNameValuePairs(String nameValueObjJsonArray) throws Throwable
|
||||
{
|
||||
if (StringUtil.isEmpty(nameValueObjJsonArray))
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
Object jsonObj = getObjectMapperNonStardand().readValue(nameValueObjJsonArray, Object.class);
|
||||
|
||||
if (jsonObj == null)
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
if (!(jsonObj instanceof Collection<?>))
|
||||
return NOT_NAME_VALUE_PAIR_OBJ_ARRAY_JSON;
|
||||
|
||||
Collection<?> collection = (Collection<?>) jsonObj;
|
||||
|
||||
List<NameValuePair> nameValuePairs = new ArrayList<>(collection.size());
|
||||
|
||||
for (Object ele : collection)
|
||||
{
|
||||
String name = null;
|
||||
String value = null;
|
||||
|
||||
if (ele instanceof Map<?, ?>)
|
||||
{
|
||||
Map<String, ?> eleMap = (Map<String, ?>) ele;
|
||||
Object nameVal = eleMap.get("name");
|
||||
Object valueVal = eleMap.get("value");
|
||||
|
||||
if (nameVal instanceof String)
|
||||
{
|
||||
name = (String) nameVal;
|
||||
if (valueVal != null)
|
||||
value = (valueVal instanceof String ? (String) valueVal : valueVal.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (name == null)
|
||||
return NOT_NAME_VALUE_PAIR_OBJ_ARRAY_JSON;
|
||||
|
||||
nameValuePairs.add(new BasicNameValuePair(name, value));
|
||||
}
|
||||
|
||||
return nameValuePairs;
|
||||
}
|
||||
|
||||
protected ObjectMapper getObjectMapperNonStardand()
|
||||
{
|
||||
return JsonSupport.getObjectMapperNonStardand();
|
||||
}
|
||||
|
||||
protected static class JsonResponseHandler implements HttpClientResponseHandler<ResolvedDataSetResult>
|
||||
{
|
||||
private List<DataSetProperty> properties;
|
||||
|
||||
private String responseDataJsonPath = "";
|
||||
|
||||
public JsonResponseHandler()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public List<DataSetProperty> getProperties()
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据集属性。
|
||||
*
|
||||
* @param properties
|
||||
* 如果为{@code null}或空,则执行解析
|
||||
*/
|
||||
public void setProperties(List<DataSetProperty> properties)
|
||||
{
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public String getResponseDataJsonPath()
|
||||
{
|
||||
return responseDataJsonPath;
|
||||
}
|
||||
|
||||
public void setResponseDataJsonPath(String responseDataJsonPath)
|
||||
{
|
||||
this.responseDataJsonPath = responseDataJsonPath;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ResolvedDataSetResult handleResponse(ClassicHttpResponse response) throws HttpException, IOException
|
||||
{
|
||||
int code = response.getCode();
|
||||
HttpEntity entity = response.getEntity();
|
||||
|
||||
if (code < 200 || code >= 300)
|
||||
throw new HttpResponseException(code, response.getReasonPhrase());
|
||||
|
||||
Reader reader = null;
|
||||
|
||||
if (entity == null)
|
||||
reader = IOUtil.getReader("");
|
||||
else
|
||||
{
|
||||
Charset contentCharset = resolveCharset(entity, ContentType.APPLICATION_JSON.getCharset());
|
||||
reader = IOUtil.getReader(entity.getContent(), contentCharset);
|
||||
}
|
||||
|
||||
if (this.properties == null || this.properties.isEmpty())
|
||||
{
|
||||
HttpResponseJsonDataSet jsonDataSet = new HttpResponseJsonDataSet(reader);
|
||||
jsonDataSet.setDataJsonPath(this.responseDataJsonPath);
|
||||
|
||||
return jsonDataSet.resolve(Collections.EMPTY_MAP);
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpResponseJsonDataSet jsonDataSet = new HttpResponseJsonDataSet(this.properties, reader);
|
||||
jsonDataSet.setDataJsonPath(this.responseDataJsonPath);
|
||||
|
||||
DataSetResult result = jsonDataSet.getResult(Collections.EMPTY_MAP);
|
||||
return new ResolvedDataSetResult(result, this.properties);
|
||||
}
|
||||
}
|
||||
|
||||
protected Charset resolveCharset(HttpEntity entity, Charset defaultCharset)
|
||||
{
|
||||
Charset contentCharset = null;
|
||||
|
||||
String contentTypeStr = entity.getContentType();
|
||||
|
||||
if (!StringUtil.isEmpty(contentTypeStr))
|
||||
{
|
||||
try
|
||||
{
|
||||
ContentType contentType = ContentType.parse(contentTypeStr);
|
||||
contentCharset = contentType.getCharset();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOGGER.warn("Default charset [" + defaultCharset + "] will be used because parse error", t);
|
||||
|
||||
contentCharset = defaultCharset;
|
||||
}
|
||||
}
|
||||
|
||||
return (contentCharset != null ? contentCharset : defaultCharset);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class HttpResponseJsonDataSet extends AbstractJsonDataSet
|
||||
{
|
||||
private Reader responseJsonReader;
|
||||
|
||||
public HttpResponseJsonDataSet(Reader responseJsonReader)
|
||||
{
|
||||
super(HttpResponseJsonDataSet.class.getName(), HttpResponseJsonDataSet.class.getName());
|
||||
this.responseJsonReader = responseJsonReader;
|
||||
}
|
||||
|
||||
public HttpResponseJsonDataSet(List<DataSetProperty> properties, Reader responseJsonReader)
|
||||
{
|
||||
super(HttpResponseJsonDataSet.class.getName(), HttpResponseJsonDataSet.class.getName(), properties);
|
||||
this.responseJsonReader = responseJsonReader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TemplateResolvedSource<Reader> getJsonReader(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
return new TemplateResolvedSource<>(this.responseJsonReader);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,274 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.util.IOUtil;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.node.ValueNode;
|
||||
|
||||
/**
|
||||
* JSON {@linkplain DataSet}支持类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class JsonDataSetSupport extends JsonSupport
|
||||
{
|
||||
public JsonDataSetSupport()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON数据。
|
||||
*
|
||||
* @param jsonValue
|
||||
* @return
|
||||
* @throws DataSetSourceParseException
|
||||
* @throws DataSetException
|
||||
*/
|
||||
public Object resolveValue(String jsonValue) throws DataSetSourceParseException, DataSetException
|
||||
{
|
||||
StringReader reader = new StringReader(jsonValue);
|
||||
return resolveValue(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON数据。
|
||||
*
|
||||
* @param jsonReader
|
||||
* @return
|
||||
* @throws DataSetSourceParseException
|
||||
* @throws DataSetException
|
||||
*/
|
||||
public Object resolveValue(Reader jsonReader) throws DataSetSourceParseException, DataSetException
|
||||
{
|
||||
try
|
||||
{
|
||||
return parseNonStardand(jsonReader, Object.class);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetException(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析数据集结果数据。
|
||||
*
|
||||
* @param jsonValue
|
||||
* @return
|
||||
* @throws DataSetSourceParseException
|
||||
* @throws UnsupportedJsonResultDataException
|
||||
* @throws DataSetException
|
||||
*/
|
||||
public Object resolveResultData(String jsonValue)
|
||||
throws DataSetSourceParseException, UnsupportedJsonResultDataException, DataSetException
|
||||
{
|
||||
StringReader reader = new StringReader(jsonValue);
|
||||
return resolveResultData(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析数据集结果数据。
|
||||
*
|
||||
* @param file
|
||||
* @param encoding
|
||||
* @return
|
||||
* @throws DataSetSourceParseException
|
||||
* @throws UnsupportedJsonResultDataException
|
||||
* @throws DataSetException
|
||||
*/
|
||||
public Object resolveResultData(File file, String encoding)
|
||||
throws DataSetSourceParseException, UnsupportedJsonResultDataException, DataSetException
|
||||
{
|
||||
Reader reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
reader = IOUtil.getReader(file, encoding);
|
||||
return resolveResultData(reader);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DataSetException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(reader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析数据集结果数据。
|
||||
*
|
||||
* @param reader
|
||||
* @return
|
||||
* @throws DataSetSourceParseException
|
||||
* @throws UnsupportedJsonResultDataException
|
||||
* @throws DataSetException
|
||||
*/
|
||||
public Object resolveResultData(Reader reader)
|
||||
throws DataSetSourceParseException, UnsupportedJsonResultDataException, DataSetException
|
||||
{
|
||||
JsonNode jsonNode = null;
|
||||
|
||||
try
|
||||
{
|
||||
jsonNode = getObjectMapperNonStardand().readTree(reader);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
|
||||
if (!isLegalResultDataJsonNode(jsonNode))
|
||||
throw new UnsupportedJsonResultDataException("Result data must be object or object array/list");
|
||||
|
||||
if (jsonNode == null)
|
||||
return null;
|
||||
|
||||
Object data = null;
|
||||
|
||||
try
|
||||
{
|
||||
data = getObjectMapperNonStardand().treeToValue(jsonNode, Object.class);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetException(t);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是合法的数据集结果数据{@linkplain JsonNode}。
|
||||
* <p>
|
||||
* 参考{@linkplain DataSetResult#getData()}说明。
|
||||
* </p>
|
||||
*
|
||||
* @param jsonNode
|
||||
* @return
|
||||
*/
|
||||
public boolean isLegalResultDataJsonNode(JsonNode jsonNode)
|
||||
{
|
||||
if (jsonNode == null || jsonNode.isNull())
|
||||
return true;
|
||||
|
||||
if (jsonNode instanceof ValueNode)
|
||||
return false;
|
||||
|
||||
if (jsonNode instanceof ArrayNode)
|
||||
{
|
||||
ArrayNode arrayNode = (ArrayNode) jsonNode;
|
||||
|
||||
for (int i = 0; i < arrayNode.size(); i++)
|
||||
{
|
||||
JsonNode eleNode = arrayNode.get(i);
|
||||
|
||||
if (eleNode == null || eleNode.isNull())
|
||||
continue;
|
||||
|
||||
if (!(eleNode instanceof ObjectNode))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON对象的{@linkplain DataSetProperty}。
|
||||
*
|
||||
* @param resultData
|
||||
* JSON对象、JSON对象数组、JSON对象列表
|
||||
* @return
|
||||
* @throws UnsupportedJsonResultDataException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<DataSetProperty> resolveDataSetProperties(Object resultData) throws UnsupportedJsonResultDataException
|
||||
{
|
||||
if (resultData == null)
|
||||
{
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
else if (resultData instanceof Map<?, ?>)
|
||||
{
|
||||
return resolveJsonObjDataSetProperties((Map<String, ?>) resultData);
|
||||
}
|
||||
else if (resultData instanceof List<?>)
|
||||
{
|
||||
List<?> list = (List<?>) resultData;
|
||||
|
||||
if (list.size() == 0)
|
||||
return Collections.EMPTY_LIST;
|
||||
else
|
||||
return resolveJsonObjDataSetProperties((Map<String, ?>) list.get(0));
|
||||
}
|
||||
else if (resultData instanceof Object[])
|
||||
{
|
||||
Object[] array = (Object[]) resultData;
|
||||
|
||||
if (array.length == 0)
|
||||
return Collections.EMPTY_LIST;
|
||||
else
|
||||
return resolveJsonObjDataSetProperties((Map<String, ?>) array[0]);
|
||||
}
|
||||
else
|
||||
throw new UnsupportedJsonResultDataException("Result data must be object or object array/list");
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON对象的{@linkplain DataSetProperty}。
|
||||
*
|
||||
* @param jsonObj
|
||||
* @return
|
||||
*/
|
||||
public List<DataSetProperty> resolveJsonObjDataSetProperties(Map<String, ?> jsonObj)
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
|
||||
if (jsonObj == null)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Map.Entry<String, ?> entry : jsonObj.entrySet())
|
||||
{
|
||||
Object value = entry.getValue();
|
||||
String type = DataSetProperty.DataType.resolveDataType(value);
|
||||
|
||||
DataSetProperty property = new DataSetProperty(entry.getKey(), type);
|
||||
|
||||
// JSON数值只有NUMBER类型
|
||||
if (DataSetProperty.DataType.isInteger(property.getType())
|
||||
|| DataSetProperty.DataType.isDecimal(property.getType()))
|
||||
property.setType(DataSetProperty.DataType.NUMBER);
|
||||
|
||||
properties.add(property);
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
}
|
|
@ -18,6 +18,9 @@ import org.datagear.util.FileUtil;
|
|||
|
||||
/**
|
||||
* 目录内JSON文件{@linkplain DataSet}。
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
|
@ -73,8 +76,7 @@ public class JsonDirectoryFileDataSet extends AbstractJsonFileDataSet
|
|||
@Override
|
||||
protected File getJsonFile(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
String fileName = resolveTemplate(this.fileName, paramValues);
|
||||
File jsonFile = FileUtil.getFile(directory, fileName);
|
||||
File jsonFile = FileUtil.getFile(this.directory, this.fileName);
|
||||
return jsonFile;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.util.IOUtil;
|
||||
|
||||
/**
|
||||
* JSON字符串值数据集。
|
||||
|
@ -55,25 +56,15 @@ public class JsonValueDataSet extends AbstractJsonDataSet
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataSetResult getResult(Map<String, ?> paramValues) throws DataSetException
|
||||
public TemplateResolvedDataSetResult resolve(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
String json = resolveTemplate(this.value, paramValues);
|
||||
|
||||
Object data = getJsonDataSetSupport().resolveResultData(json);
|
||||
|
||||
return new DataSetResult(data);
|
||||
return (TemplateResolvedDataSetResult) resolveResult(paramValues, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateResolvedDataSetResult resolve(Map<String, ?> paramValues) throws DataSetException
|
||||
protected TemplateResolvedSource<Reader> getJsonReader(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
String json = resolveTemplate(this.value, paramValues);
|
||||
|
||||
Object data = getJsonDataSetSupport().resolveResultData(json);
|
||||
DataSetResult result = new DataSetResult(data);
|
||||
|
||||
List<DataSetProperty> properties = getJsonDataSetSupport().resolveDataSetProperties(result.getData());
|
||||
|
||||
return new TemplateResolvedDataSetResult(result, properties, json);
|
||||
String json = resolveAsFmkTemplateIfHasParam(this.value, paramValues);
|
||||
return new TemplateResolvedSource<>(IOUtil.getReader(json), json);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
|
||||
/**
|
||||
* JSON字符串不是名/值数组格式异常。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class NotNameValueObjArrayJsonException extends DataSetException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String json;
|
||||
|
||||
public NotNameValueObjArrayJsonException(String json)
|
||||
{
|
||||
super("The json must be name/value object array");
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public NotNameValueObjArrayJsonException(String json, String message)
|
||||
{
|
||||
super(message);
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public NotNameValueObjArrayJsonException(String json, Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public NotNameValueObjArrayJsonException(String json, String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public String getJson()
|
||||
{
|
||||
return json;
|
||||
}
|
||||
|
||||
protected void setJson(String json)
|
||||
{
|
||||
this.json = json;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.util.StringUtil;
|
||||
|
||||
/**
|
||||
* 范围解析器。
|
||||
* <p>
|
||||
* 此类用于解析诸如{@code "1, 2-3, 6-, -15}之类的范围表达式。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class RangeExpResolver
|
||||
{
|
||||
public static final char RANGE_SPLITTER_CHAR = '-';
|
||||
|
||||
public static final String RANGE_SPLITTER_STRING = "-";
|
||||
|
||||
public static final char RANGE_GROUP_SPLITTER_CHAR = ',';
|
||||
|
||||
public static final String RANGE_GROUP_SPLITTER_STRING = ",";
|
||||
|
||||
private char rangeSplitter = RANGE_SPLITTER_CHAR;
|
||||
|
||||
private char rangeGroupSplitter = RANGE_GROUP_SPLITTER_CHAR;
|
||||
|
||||
public RangeExpResolver()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public char getRangeSplitter()
|
||||
{
|
||||
return rangeSplitter;
|
||||
}
|
||||
|
||||
public void setRangeSplitter(char rangeSplitter)
|
||||
{
|
||||
this.rangeSplitter = rangeSplitter;
|
||||
}
|
||||
|
||||
public char getRangeGroupSplitter()
|
||||
{
|
||||
return rangeGroupSplitter;
|
||||
}
|
||||
|
||||
public void setRangeGroupSplitter(char rangeGroupSplitter)
|
||||
{
|
||||
this.rangeGroupSplitter = rangeGroupSplitter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<IndexRange> resolveIndex(String exp) throws NumberFormatException
|
||||
{
|
||||
List<Range> ranges = resolve(exp);
|
||||
|
||||
if (ranges.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
List<IndexRange> indexRanges = new ArrayList<>(ranges.size());
|
||||
|
||||
for (Range range : ranges)
|
||||
indexRanges.add(new IndexRange(range));
|
||||
|
||||
return indexRanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析范围表达式组。
|
||||
* <p>
|
||||
* 例如:{@code "1, 2-5, 8-, -15"}
|
||||
* </p>
|
||||
*
|
||||
* @param exp
|
||||
* @return 如果{@code exp}为{@code null}、或{@code ""},将返回空列表
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Range> resolve(String exp)
|
||||
{
|
||||
if (exp != null)
|
||||
exp = exp.trim();
|
||||
|
||||
if (exp == null || exp.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
List<Range> ranges = new ArrayList<>();
|
||||
|
||||
String[] ss = StringUtil.split(exp, this.rangeGroupSplitter + "", false);
|
||||
|
||||
for (String s : ss)
|
||||
{
|
||||
Range range = resolveSingle(s);
|
||||
|
||||
if (range != null)
|
||||
ranges.add(range);
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
public IndexRange resolveSingleIndex(String exp) throws NumberFormatException
|
||||
{
|
||||
Range range = resolveSingle(exp);
|
||||
|
||||
if (range == null)
|
||||
return null;
|
||||
|
||||
return new IndexRange(range);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析单个范围表达式。
|
||||
* <p>
|
||||
* 例如:{@code "1"}、{@code "4-5"}、{@code "8-"}、{@code "-15"}
|
||||
* </p>
|
||||
*
|
||||
* @param exp
|
||||
* @return 如果{@code exp}为{@code null}、或{@code ""},将返回{@code null}
|
||||
*/
|
||||
public Range resolveSingle(String exp)
|
||||
{
|
||||
if (exp != null)
|
||||
exp = exp.trim();
|
||||
|
||||
if (exp == null || exp.isEmpty())
|
||||
return null;
|
||||
|
||||
String from = "";
|
||||
String to = "";
|
||||
|
||||
int idx = exp.indexOf(this.rangeSplitter);
|
||||
int len = exp.length();
|
||||
|
||||
// 单个值:"1"
|
||||
if (idx < 0)
|
||||
{
|
||||
from = exp;
|
||||
to = from;
|
||||
}
|
||||
// 都未指定:"-"
|
||||
else if (idx == 0 && len == 1)
|
||||
{
|
||||
from = "";
|
||||
to = "";
|
||||
}
|
||||
// 仅指定截至值:"-4"
|
||||
else if (idx == 0)
|
||||
{
|
||||
from = "";
|
||||
to = exp.substring(1);
|
||||
}
|
||||
// 仅指定起始值:"4-"
|
||||
else if (idx == len - 1)
|
||||
{
|
||||
from = exp.substring(0, len - 1);
|
||||
to = "";
|
||||
}
|
||||
// 都指定:"3-5"
|
||||
else
|
||||
{
|
||||
from = exp.substring(0, idx);
|
||||
to = exp.substring(idx + 1);
|
||||
}
|
||||
|
||||
return new Range(from, to);
|
||||
}
|
||||
|
||||
public static RangeExpResolver valueOf(char rangeSplitter, char rangeGroupSplitter)
|
||||
{
|
||||
RangeExpResolver resolver = new RangeExpResolver();
|
||||
resolver.setRangeSplitter(rangeSplitter);
|
||||
resolver.setRangeGroupSplitter(rangeGroupSplitter);
|
||||
|
||||
return resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* 范围。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public static class Range implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 起始 */
|
||||
private String from = "";
|
||||
|
||||
/** 截至 */
|
||||
private String to = "";
|
||||
|
||||
public Range()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public Range(String from)
|
||||
{
|
||||
super();
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public Range(String from, String to)
|
||||
{
|
||||
super();
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public boolean hasFrom()
|
||||
{
|
||||
return (this.from != null && !this.from.isEmpty());
|
||||
}
|
||||
|
||||
public String trimFrom()
|
||||
{
|
||||
if (this.from == null)
|
||||
return "";
|
||||
|
||||
return this.from.trim();
|
||||
}
|
||||
|
||||
public String getFrom()
|
||||
{
|
||||
return from;
|
||||
}
|
||||
|
||||
public void setFrom(String from)
|
||||
{
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public boolean hasTo()
|
||||
{
|
||||
return (this.to != null && !this.to.isEmpty());
|
||||
}
|
||||
|
||||
public String trimTo()
|
||||
{
|
||||
if (this.to == null)
|
||||
return "";
|
||||
|
||||
return this.to.trim();
|
||||
}
|
||||
|
||||
public String getTo()
|
||||
{
|
||||
return to;
|
||||
}
|
||||
|
||||
public void setTo(String to)
|
||||
{
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((from == null) ? 0 : from.hashCode());
|
||||
result = prime * result + ((to == null) ? 0 : to.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Range other = (Range) obj;
|
||||
if (from == null)
|
||||
{
|
||||
if (other.from != null)
|
||||
return false;
|
||||
}
|
||||
else if (!from.equals(other.from))
|
||||
return false;
|
||||
if (to == null)
|
||||
{
|
||||
if (other.to != null)
|
||||
return false;
|
||||
}
|
||||
else if (!to.equals(other.to))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [from=" + from + ", to=" + to + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 索引范围。
|
||||
* <p>
|
||||
* 索引指大于或等于{@code 0}的整数值。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
protected static class IndexRange implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 起始索引 */
|
||||
private int from = 0;
|
||||
|
||||
/** 截至索引(包含) */
|
||||
private int to = -1;
|
||||
|
||||
public IndexRange()
|
||||
{
|
||||
super();
|
||||
this.from = 0;
|
||||
this.to = -1;
|
||||
}
|
||||
|
||||
public IndexRange(int from)
|
||||
{
|
||||
super();
|
||||
this.from = from;
|
||||
this.to = -1;
|
||||
}
|
||||
|
||||
public IndexRange(int from, int to)
|
||||
{
|
||||
super();
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public IndexRange(Range range) throws NumberFormatException
|
||||
{
|
||||
super();
|
||||
|
||||
int from = 0;
|
||||
int to = -1;
|
||||
|
||||
String fromStr = range.trimFrom();
|
||||
String toStr = range.trimTo();
|
||||
|
||||
if (!StringUtil.isEmpty(fromStr))
|
||||
from = Integer.parseInt(fromStr);
|
||||
|
||||
if (!StringUtil.isEmpty(toStr))
|
||||
to = Integer.parseInt(toStr);
|
||||
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public int getFrom()
|
||||
{
|
||||
return from;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置起始索引。
|
||||
*
|
||||
* @param from
|
||||
* 起始索引,小于{@code 0}表示不限定
|
||||
*/
|
||||
public void setFrom(int from)
|
||||
{
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public int getTo()
|
||||
{
|
||||
return to;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置截至索引(包含)。
|
||||
*
|
||||
* @param to
|
||||
* 截至索引,小于{@code 0}表示不限定
|
||||
*/
|
||||
public void setTo(int to)
|
||||
{
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含给定索引数值。
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public boolean includes(int index)
|
||||
{
|
||||
if (this.from > -1 && index < this.from)
|
||||
return false;
|
||||
|
||||
if (this.to > -1 && index > this.to)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + from;
|
||||
result = prime * result + to;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
IndexRange other = (IndexRange) obj;
|
||||
if (from != other.from)
|
||||
return false;
|
||||
if (to != other.to)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getSimpleName() + " [from=" + from + ", to=" + to + "]";
|
||||
}
|
||||
|
||||
public static boolean includes(List<IndexRange> indexRanges, int index)
|
||||
{
|
||||
for (int i = 0; i < indexRanges.size(); i++)
|
||||
if (indexRanges.get(i).includes(index))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
/**
|
||||
* 读取指定JSON路径的数据异常。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class ReadJsonDataPathException extends DataSetSourceParseException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String dataPath;
|
||||
|
||||
public ReadJsonDataPathException(String dataPath)
|
||||
{
|
||||
super();
|
||||
this.dataPath = dataPath;
|
||||
}
|
||||
|
||||
public ReadJsonDataPathException(String dataPath, String message)
|
||||
{
|
||||
super(message);
|
||||
this.dataPath = dataPath;
|
||||
}
|
||||
|
||||
public ReadJsonDataPathException(String dataPath, Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
this.dataPath = dataPath;
|
||||
}
|
||||
|
||||
public ReadJsonDataPathException(String dataPath, String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
this.dataPath = dataPath;
|
||||
}
|
||||
|
||||
public String getDataPath()
|
||||
{
|
||||
return dataPath;
|
||||
}
|
||||
|
||||
protected void setDataPath(String dataPath)
|
||||
{
|
||||
this.dataPath = dataPath;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
/**
|
||||
* {@linkplain HttpDataSet#getRequestContent()}不是名/值对象数组JSON异常。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class RequestContentNotNameValueObjArrayJsonException extends NotNameValueObjArrayJsonException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RequestContentNotNameValueObjArrayJsonException(String json)
|
||||
{
|
||||
super(json);
|
||||
}
|
||||
|
||||
public RequestContentNotNameValueObjArrayJsonException(String json, String message)
|
||||
{
|
||||
super(json, message);
|
||||
}
|
||||
|
||||
public RequestContentNotNameValueObjArrayJsonException(String json, Throwable cause)
|
||||
{
|
||||
super(json, cause);
|
||||
}
|
||||
|
||||
public RequestContentNotNameValueObjArrayJsonException(String json, String message, Throwable cause)
|
||||
{
|
||||
super(json, message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
|
||||
/**
|
||||
* 简单CSV文件数据集。
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class SimpleCsvFileDataSet extends AbstractCsvFileDataSet
|
||||
{
|
||||
/** CSV文件 */
|
||||
private File file;
|
||||
|
||||
public SimpleCsvFileDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SimpleCsvFileDataSet(String id, String name, File file)
|
||||
{
|
||||
super(id, name);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public SimpleCsvFileDataSet(String id, String name, List<DataSetProperty> properties, File file)
|
||||
{
|
||||
super(id, name, properties);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public File getFile()
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(File file)
|
||||
{
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getCsvFile(Map<String, ?> paramValues) throws Throwable
|
||||
{
|
||||
return this.file;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
|
||||
/**
|
||||
* 简单Excel数据集。
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class SimpleExcelDataSet extends AbstractExcelDataSet
|
||||
{
|
||||
/** Excel文件 */
|
||||
private File file;
|
||||
|
||||
public SimpleExcelDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SimpleExcelDataSet(String id, String name, File file)
|
||||
{
|
||||
super(id, name);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public SimpleExcelDataSet(String id, String name, List<DataSetProperty> properties, File file)
|
||||
{
|
||||
super(id, name, properties);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getExcelFile(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
return this.file;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,9 @@ import org.datagear.analysis.DataSetProperty;
|
|||
|
||||
/**
|
||||
* 简单JSON文件数据集。
|
||||
* <p>
|
||||
* 注意:此类不支持<code>Freemarker</code>模板语言。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
|
|
|
@ -9,20 +9,27 @@ package org.datagear.analysis.support;
|
|||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetProperty.DataType;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvableDataSet;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.datagear.util.JDBCCompatiblity;
|
||||
import org.datagear.util.JdbcSupport;
|
||||
import org.datagear.util.JdbcUtil;
|
||||
import org.datagear.util.QueryResultSet;
|
||||
import org.datagear.util.Sql;
|
||||
import org.datagear.util.SqlType;
|
||||
import org.datagear.util.resource.ConnectionFactory;
|
||||
|
||||
/**
|
||||
|
@ -34,9 +41,9 @@ import org.datagear.util.resource.ConnectionFactory;
|
|||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class SqlDataSet extends AbstractFmkTemplateDataSet implements ResolvableDataSet
|
||||
public class SqlDataSet extends AbstractResolvableDataSet implements ResolvableDataSet
|
||||
{
|
||||
protected static final SqlDataSetSupport SQL_DATA_SET_SUPPORT = new SqlDataSetSupport();
|
||||
protected static final JdbcSupport JDBC_SUPPORT = new JdbcSupport();
|
||||
|
||||
private ConnectionFactory connectionFactory;
|
||||
|
||||
|
@ -47,10 +54,9 @@ public class SqlDataSet extends AbstractFmkTemplateDataSet implements Resolvable
|
|||
super();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public SqlDataSet(String id, String name, ConnectionFactory connectionFactory, String sql)
|
||||
{
|
||||
super(id, name, Collections.EMPTY_LIST);
|
||||
super(id, name);
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
@ -84,35 +90,16 @@ public class SqlDataSet extends AbstractFmkTemplateDataSet implements Resolvable
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataSetResult getResult(Map<String, ?> paramValues) throws DataSetException
|
||||
public TemplateResolvedDataSetResult resolve(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
List<DataSetProperty> properties = getProperties();
|
||||
|
||||
if (properties == null || properties.isEmpty())
|
||||
throw new DataSetException("[getProperties()] must not be empty");
|
||||
|
||||
ResolvedDataSetResult result = getResolvedDataSetResult(paramValues, properties);
|
||||
return result.getResult();
|
||||
return resolveResult(paramValues, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateResolvedDataSetResult resolve(Map<String, ?> paramValues) throws DataSetException
|
||||
protected TemplateResolvedDataSetResult resolveResult(Map<String, ?> paramValues, List<DataSetProperty> properties)
|
||||
throws DataSetException
|
||||
{
|
||||
return getResolvedDataSetResult(paramValues, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param paramValues
|
||||
* @param properties
|
||||
* 允许为{@code null},此时会自动解析
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected TemplateResolvedDataSetResult getResolvedDataSetResult(Map<String, ?> paramValues,
|
||||
List<DataSetProperty> properties) throws DataSetException
|
||||
{
|
||||
String sql = resolveTemplate(getSql(), paramValues);
|
||||
String sql = resolveAsFmkTemplateIfHasParam(getSql(), paramValues);
|
||||
|
||||
Connection cn = null;
|
||||
|
||||
|
@ -120,32 +107,42 @@ public class SqlDataSet extends AbstractFmkTemplateDataSet implements Resolvable
|
|||
{
|
||||
cn = getConnectionFactory().get();
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Throwable t)
|
||||
{
|
||||
JdbcUtil.closeConnection(cn);
|
||||
throw new SqlDataSetConnectionException(e);
|
||||
throw new SqlDataSetConnectionException(t);
|
||||
}
|
||||
|
||||
Sql sqlObj = Sql.valueOf(sql);
|
||||
|
||||
JdbcSupport jdbcSupport = getJdbcSupport();
|
||||
|
||||
QueryResultSet qrs = null;
|
||||
|
||||
try
|
||||
{
|
||||
qrs = getSqlDataSetSupport().executeQuery(cn, sqlObj, ResultSet.TYPE_FORWARD_ONLY);
|
||||
qrs = jdbcSupport.executeQuery(cn, sqlObj, ResultSet.TYPE_FORWARD_ONLY);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new SqlDataSetSqlExecutionException(sql, t);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ResultSet rs = qrs.getResultSet();
|
||||
|
||||
if (properties == null || properties.isEmpty())
|
||||
properties = getSqlDataSetSupport().resolveDataSetProperties(cn, rs, null);
|
||||
ResolvedDataSetResult result = resolveResult(cn, rs, properties);
|
||||
|
||||
List<Map<String, ?>> data = getSqlDataSetSupport().resolveResultData(cn, rs, properties);
|
||||
DataSetResult result = new DataSetResult(data);
|
||||
|
||||
return new TemplateResolvedDataSetResult(result, properties, sql);
|
||||
return new TemplateResolvedDataSetResult(result.getResult(), result.getProperties(), sql);
|
||||
}
|
||||
catch (SQLException e)
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw new SqlDataSetSqlExecutionException(sql, e);
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetException(t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -167,46 +164,163 @@ public class SqlDataSet extends AbstractFmkTemplateDataSet implements Resolvable
|
|||
}
|
||||
|
||||
/**
|
||||
* 解析结果。
|
||||
*
|
||||
* @param cn
|
||||
* @param sql
|
||||
* @param rs
|
||||
* @param properties
|
||||
* 允许为{@code null},此时会自动解析
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected ResolvedDataSetResult getResolvedDataSetResult(Connection cn, String sql,
|
||||
List<DataSetProperty> properties) throws DataSetException
|
||||
protected ResolvedDataSetResult resolveResult(Connection cn, ResultSet rs, List<DataSetProperty> properties)
|
||||
throws Throwable
|
||||
{
|
||||
Sql sqlObj = Sql.valueOf(sql);
|
||||
boolean resolveProperties = (properties == null || properties.isEmpty());
|
||||
|
||||
QueryResultSet qrs = null;
|
||||
List<Map<String, ?>> datas = new ArrayList<>();
|
||||
|
||||
try
|
||||
JdbcSupport jdbcSupport = getJdbcSupport();
|
||||
DataSetPropertyValueConverter converter = createDataSetPropertyValueConverter();
|
||||
|
||||
ResultSetMetaData rsMeta = rs.getMetaData();
|
||||
String[] colNames = jdbcSupport.getColumnNames(rsMeta);
|
||||
SqlType[] sqlTypes = jdbcSupport.getColumnSqlTypes(rsMeta);
|
||||
|
||||
if (resolveProperties)
|
||||
{
|
||||
qrs = getSqlDataSetSupport().executeQuery(cn, sqlObj, ResultSet.TYPE_FORWARD_ONLY);
|
||||
ResultSet rs = qrs.getResultSet();
|
||||
|
||||
if (properties == null || properties.isEmpty())
|
||||
properties = getSqlDataSetSupport().resolveDataSetProperties(cn, rs, null);
|
||||
|
||||
List<Map<String, ?>> data = getSqlDataSetSupport().resolveResultData(cn, rs, properties);
|
||||
DataSetResult result = new DataSetResult(data);
|
||||
|
||||
return new ResolvedDataSetResult(result, properties);
|
||||
properties = new ArrayList<>(colNames.length);
|
||||
for (int i = 0; i < colNames.length; i++)
|
||||
properties.add(new DataSetProperty(colNames[i], toPropertyDataType(sqlTypes[i], colNames[i])));
|
||||
}
|
||||
catch (SQLException e)
|
||||
|
||||
int maxColumnSize = Math.min(colNames.length, properties.size());
|
||||
|
||||
int rowIdx = 0;
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
throw new SqlDataSetSqlExecutionException(sql, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
QueryResultSet.close(qrs);
|
||||
Map<String, Object> row = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < maxColumnSize; i++)
|
||||
{
|
||||
DataSetProperty property = properties.get(i);
|
||||
|
||||
Object value = jdbcSupport.getColumnValue(cn, rs, colNames[i], sqlTypes[i].getType());
|
||||
|
||||
if (resolveProperties && rowIdx == 0)
|
||||
{
|
||||
@JDBCCompatiblity("某些驱动程序可能存在一种情况,列类型会被toPropertyDataType()解析为DataType.UNKNOWN,但是实际值是允许的,"
|
||||
+ "比如PostgreSQL-42.2.5驱动对于[SELECT 'aaa' as NAME]语句,结果的SQL类型是Types.OTHER,但实际值是允许的字符串")
|
||||
boolean resolveTypeByValue = (DataType.UNKNOWN.equals(property.getType()));
|
||||
|
||||
if (resolveTypeByValue)
|
||||
property.setType(resolvePropertyDataType(value));
|
||||
}
|
||||
|
||||
value = convertToPropertyDataType(converter, value, property);
|
||||
|
||||
row.put(property.getName(), value);
|
||||
}
|
||||
|
||||
datas.add(row);
|
||||
|
||||
rowIdx++;
|
||||
}
|
||||
|
||||
DataSetResult result = new DataSetResult(datas);
|
||||
|
||||
return new ResolvedDataSetResult(result, properties);
|
||||
}
|
||||
|
||||
protected SqlDataSetSupport getSqlDataSetSupport()
|
||||
/**
|
||||
* 由SQL类型转换为{@linkplain DataSetProperty#getType()}。
|
||||
*
|
||||
* @param sqlType
|
||||
* @param columnName
|
||||
* 允许为{@code null},列名称
|
||||
* @return
|
||||
* @throws SQLException
|
||||
* @throws SqlDataSetUnsupportedSqlTypeException
|
||||
*/
|
||||
protected String toPropertyDataType(SqlType sqlType, String columnName)
|
||||
throws SQLException, SqlDataSetUnsupportedSqlTypeException
|
||||
{
|
||||
return SQL_DATA_SET_SUPPORT;
|
||||
String dataType = null;
|
||||
|
||||
int type = sqlType.getType();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
// 确定不支持的类型
|
||||
case Types.BINARY:
|
||||
case Types.BLOB:
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.VARBINARY:
|
||||
throw new SqlDataSetUnsupportedSqlTypeException(sqlType, columnName);
|
||||
|
||||
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:
|
||||
{
|
||||
dataType = DataType.DECIMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.DATE:
|
||||
{
|
||||
dataType = DataType.DATE;
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.TIME:
|
||||
{
|
||||
dataType = DataType.TIME;
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.TIMESTAMP:
|
||||
{
|
||||
dataType = DataType.TIMESTAMP;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
dataType = DataType.UNKNOWN;
|
||||
}
|
||||
|
||||
return dataType;
|
||||
}
|
||||
|
||||
protected JdbcSupport getJdbcSupport()
|
||||
{
|
||||
return JDBC_SUPPORT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,433 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetProperty.DataType;
|
||||
import org.datagear.util.JdbcSupport;
|
||||
import org.datagear.util.SqlType;
|
||||
|
||||
/**
|
||||
* SQL数据集支持类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class SqlDataSetSupport extends JdbcSupport
|
||||
{
|
||||
public SqlDataSetSupport()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析结果数据。
|
||||
*
|
||||
* @param cn
|
||||
* @param rs
|
||||
* @param properties
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
public List<Map<String, ?>> resolveResultData(Connection cn, ResultSet rs, List<DataSetProperty> properties)
|
||||
throws SQLException
|
||||
{
|
||||
List<Map<String, ?>> datas = new ArrayList<>();
|
||||
|
||||
ResultSetMetaData rsMeta = rs.getMetaData();
|
||||
int[] rsColumns = resolveResultsetColumns(properties, rsMeta);
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
Map<String, Object> row = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < rsColumns.length; i++)
|
||||
{
|
||||
DataSetProperty property = properties.get(i);
|
||||
int rsColumn = rsColumns[i];
|
||||
|
||||
Object value = resolvePropertyDataValue(cn, rs, rsColumn, getColumnSqlType(rsMeta, rsColumn),
|
||||
property.getType());
|
||||
|
||||
row.put(property.getName(), value);
|
||||
}
|
||||
|
||||
datas.add(row);
|
||||
}
|
||||
|
||||
return datas;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析结果集中对应{@linkplain DataSetProperty}的索引数组。
|
||||
*
|
||||
* @param properties
|
||||
* @param rsMeta
|
||||
* @return
|
||||
* @throws SQLException
|
||||
* @throws DataSetException
|
||||
*/
|
||||
public int[] resolveResultsetColumns(List<DataSetProperty> properties, ResultSetMetaData rsMeta)
|
||||
throws SQLException, DataSetException
|
||||
{
|
||||
int[] columns = new int[properties.size()];
|
||||
|
||||
int rsColumnCount = rsMeta.getColumnCount();
|
||||
|
||||
for (int i = 0; i < columns.length; i++)
|
||||
{
|
||||
String pname = properties.get(i).getName();
|
||||
|
||||
int myIndex = -1;
|
||||
|
||||
for (int j = 1; j <= rsColumnCount; j++)
|
||||
{
|
||||
if (pname.equalsIgnoreCase(getColumnName(rsMeta, j)))
|
||||
{
|
||||
myIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (myIndex <= 0)
|
||||
throw new DataSetException(
|
||||
"Column named '" + pname + "' not found in the " + ResultSet.class.getSimpleName());
|
||||
|
||||
columns[i] = myIndex;
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析数据值。
|
||||
*
|
||||
* @param cn
|
||||
* @param rs
|
||||
* @param column
|
||||
* @param sqlType
|
||||
* @param dataType
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
public Object resolvePropertyDataValue(Connection cn, ResultSet rs, int column, SqlType sqlType, String dataType)
|
||||
throws SQLException
|
||||
{
|
||||
Object value = null;
|
||||
|
||||
int type = sqlType.getType();
|
||||
|
||||
if (DataType.isString(dataType))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Types.CHAR:
|
||||
case Types.NCHAR:
|
||||
case Types.NVARCHAR:
|
||||
case Types.VARCHAR:
|
||||
{
|
||||
value = rs.getString(column);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new SqlDataSetUnsupportedSqlTypeException(sqlType);
|
||||
}
|
||||
}
|
||||
else if (DataType.isBoolean(dataType))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
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 SqlDataSetUnsupportedSqlTypeException(sqlType);
|
||||
}
|
||||
}
|
||||
else if (DataType.isInteger(dataType))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
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 SqlDataSetUnsupportedSqlTypeException(sqlType);
|
||||
}
|
||||
}
|
||||
else if (DataType.isDecimal(dataType))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
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 SqlDataSetUnsupportedSqlTypeException(sqlType);
|
||||
}
|
||||
}
|
||||
else if (DataType.isDate(dataType))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Types.DATE:
|
||||
{
|
||||
value = rs.getDate(column);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new SqlDataSetUnsupportedSqlTypeException(sqlType);
|
||||
}
|
||||
}
|
||||
else if (DataType.isTime(dataType))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Types.TIME:
|
||||
{
|
||||
value = rs.getTime(column);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new SqlDataSetUnsupportedSqlTypeException(sqlType);
|
||||
}
|
||||
}
|
||||
else if (DataType.isTimestamp(dataType))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Types.TIMESTAMP:
|
||||
{
|
||||
value = rs.getTimestamp(column);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new SqlDataSetUnsupportedSqlTypeException(sqlType);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
if (rs.wasNull())
|
||||
value = null;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析{@linkplain DataSetProperty}列表。
|
||||
*
|
||||
* @param cn
|
||||
* @param rs
|
||||
* @param labels
|
||||
* {@linkplain DataSetProperty#getLabel()}数组,允许为{@code null}或任意长度的数组
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
public List<DataSetProperty> resolveDataSetProperties(Connection cn, ResultSet rs, String[] labels)
|
||||
throws SQLException
|
||||
{
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
|
||||
List<DataSetProperty> properties = new ArrayList<>(columnCount);
|
||||
|
||||
for (int i = 1; i <= columnCount; i++)
|
||||
{
|
||||
String columnName = getColumnName(metaData, i);
|
||||
SqlType sqlType = getColumnSqlType(metaData, i);
|
||||
|
||||
String dataType = toPropertyDataType(sqlType, columnName);
|
||||
|
||||
DataSetProperty property = createDataSetProperty();
|
||||
property.setName(columnName);
|
||||
property.setType(dataType);
|
||||
|
||||
if (labels != null && labels.length > i - 1)
|
||||
property.setLabel(labels[i - 1]);
|
||||
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 由SQL类型转换为{@linkplain DataSetProperty#getType()}。
|
||||
*
|
||||
* @param sqlType
|
||||
* @param columnName
|
||||
* 允许为{@code null},列名称
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
public String toPropertyDataType(SqlType sqlType, String columnName) throws SQLException
|
||||
{
|
||||
String dataType = null;
|
||||
|
||||
int type = sqlType.getType();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
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:
|
||||
{
|
||||
dataType = DataType.DECIMAL;
|
||||
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 SqlDataSetUnsupportedSqlTypeException(sqlType, columnName);
|
||||
}
|
||||
|
||||
return dataType;
|
||||
}
|
||||
|
||||
protected DataSetProperty createDataSetProperty()
|
||||
{
|
||||
return new DataSetProperty();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
/**
|
||||
* 模板已解析的源。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class TemplateResolvedSource<T>
|
||||
{
|
||||
private T source;
|
||||
|
||||
/** 已解析的模板内容 */
|
||||
private String resolvedTemplate = null;
|
||||
|
||||
public TemplateResolvedSource()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public TemplateResolvedSource(T source)
|
||||
{
|
||||
super();
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public TemplateResolvedSource(T source, String resolvedTemplate)
|
||||
{
|
||||
super();
|
||||
this.source = source;
|
||||
this.resolvedTemplate = resolvedTemplate;
|
||||
}
|
||||
|
||||
public T getSource()
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(T source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public boolean hasResolvedTemplate()
|
||||
{
|
||||
return (this.resolvedTemplate != null && !this.resolvedTemplate.isEmpty());
|
||||
}
|
||||
|
||||
public String getResolvedTemplate()
|
||||
{
|
||||
return resolvedTemplate;
|
||||
}
|
||||
|
||||
public void setResolvedTemplate(String resolvedTemplate)
|
||||
{
|
||||
this.resolvedTemplate = resolvedTemplate;
|
||||
}
|
||||
}
|
|
@ -81,7 +81,7 @@ public class HtmlChartPluginLoader
|
|||
private JsonChartPluginPropertiesResolver jsonChartPluginPropertiesResolver = new JsonChartPluginPropertiesResolver();
|
||||
|
||||
/** 文件编码 */
|
||||
private String encoding = "UTF-8";
|
||||
private String encoding = IOUtil.CHARSET_UTF_8;
|
||||
|
||||
public HtmlChartPluginLoader()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain AbstractJsonDataSet}单元测试用例。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class AbstractJsonDataSetTest
|
||||
{
|
||||
@Test
|
||||
public void resolveTest_dataJsonPath()
|
||||
{
|
||||
String jsonString = "{ path0: { path1: [ { path2: [ { name:'aaa', value: 11, size: 12 } ] } ] } }";
|
||||
|
||||
JsonValueDataSet dataSet = new JsonValueDataSet(JsonValueDataSet.class.getSimpleName(),
|
||||
JsonValueDataSet.class.getSimpleName(), jsonString);
|
||||
|
||||
dataSet.setDataJsonPath("path0.path1[0].path2");
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(Collections.emptyMap());
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
assertEquals(jsonString, result.getTemplateResult());
|
||||
|
||||
{
|
||||
assertEquals(3, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(1, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("size")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain CsvDirectoryFileDataSet}单元测试类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class CsvDirectoryFileDataSetTest
|
||||
{
|
||||
private static final File DIRECTORY = new File("src/test/resources/org/datagear/analysis/support/");
|
||||
|
||||
@Test
|
||||
public void getResultTest()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("尺寸", DataSetProperty.DataType.NUMBER));
|
||||
|
||||
CsvDirectoryFileDataSet dataSet = new CsvDirectoryFileDataSet("a", "a", properties, DIRECTORY,
|
||||
"CsvDirectoryFileDataSetTest-0.csv");
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
DataSetResult result = dataSet.getResult(Collections.EMPTY_MAP);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("尺寸")).intValue());
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(21, ((Number) row.get("value")).intValue());
|
||||
assertEquals(22, ((Number) row.get("尺寸")).intValue());
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(31, ((Number) row.get("value")).intValue());
|
||||
assertEquals(32, ((Number) row.get("尺寸")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest()
|
||||
{
|
||||
CsvDirectoryFileDataSet dataSet = new CsvDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"CsvDirectoryFileDataSetTest-0.csv");
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ResolvedDataSetResult result = dataSet.resolve(Collections.EMPTY_MAP);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
{
|
||||
assertEquals(3, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("尺寸", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("尺寸")).intValue());
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(21, ((Number) row.get("value")).intValue());
|
||||
assertEquals(22, ((Number) row.get("尺寸")).intValue());
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(31, ((Number) row.get("value")).intValue());
|
||||
assertEquals(32, ((Number) row.get("尺寸")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_noNameRow()
|
||||
{
|
||||
CsvDirectoryFileDataSet dataSet = new CsvDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"CsvDirectoryFileDataSetTest-0.csv");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ResolvedDataSetResult result = dataSet.resolve(Collections.EMPTY_MAP);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
{
|
||||
assertEquals(3, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("1", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("2", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("3", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(4, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("name", row.get("1"));
|
||||
assertEquals("value", row.get("2"));
|
||||
assertEquals("尺寸", row.get("3"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("aaa", row.get("1"));
|
||||
assertEquals("11", row.get("2"));
|
||||
assertEquals("12", row.get("3"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("bbb", row.get("1"));
|
||||
assertEquals("21", row.get("2"));
|
||||
assertEquals("22", row.get("3"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(3);
|
||||
|
||||
assertEquals("ccc", row.get("1"));
|
||||
assertEquals("31", row.get("2"));
|
||||
assertEquals("32", row.get("3"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetParam;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain CsvValueDataSet}单元测试类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class CsvValueDataSetTest
|
||||
{
|
||||
@Test
|
||||
public void getResultTest_hasParam()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("size", DataSetProperty.DataType.NUMBER));
|
||||
|
||||
List<DataSetParam> params = new ArrayList<DataSetParam>();
|
||||
params.add(new DataSetParam("size", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
CsvValueDataSet dataSet = new CsvValueDataSet("a", "a", properties,
|
||||
"name, value, size \n aaa, 11, ${size}");
|
||||
dataSet.setParams(params);
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("size", 12);
|
||||
|
||||
DataSetResult result = dataSet.getResult(paramValues);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(1, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("size")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResultTest_hasParam_convertPropertyValue()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("size", DataSetProperty.DataType.STRING));
|
||||
|
||||
List<DataSetParam> params = new ArrayList<DataSetParam>();
|
||||
params.add(new DataSetParam("size", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
CsvValueDataSet dataSet = new CsvValueDataSet("a", "a", properties,
|
||||
"name, value, size \n aaa, 11, ${size}");
|
||||
dataSet.setParams(params);
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("size", 12);
|
||||
|
||||
DataSetResult result = dataSet.getResult(paramValues);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(1, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals("12", row.get("size"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_hasParam()
|
||||
{
|
||||
List<DataSetParam> params = new ArrayList<DataSetParam>();
|
||||
params.add(new DataSetParam("size", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
CsvValueDataSet dataSet = new CsvValueDataSet("a", "a",
|
||||
"name, value, size \n aaa, 11, ${size}");
|
||||
dataSet.setParams(params);
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("size", 12);
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(paramValues);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
assertEquals("name, value, size \n aaa, 11, 12", result.getTemplateResult());
|
||||
|
||||
{
|
||||
assertEquals(3, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(1, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("size")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* 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,355 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain ExcelDirectoryFileDataSet}单元测试用例。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class ExcelDirectoryFileDataSetTest
|
||||
{
|
||||
private static final File DIRECTORY = new File("src/test/resources/org/datagear/analysis/support/");
|
||||
|
||||
@Test
|
||||
public void getResultTest_xlsx()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("size", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("date", DataSetProperty.DataType.DATE));
|
||||
|
||||
ExcelDirectoryFileDataSet dataSet = new ExcelDirectoryFileDataSet("a", "a", properties, DIRECTORY,
|
||||
"ExcelDirectoryFileDataSetTest-0.xlsx");
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
DataSetResult result = dataSet.getResult(Collections.EMPTY_MAP);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(15, ((Number) row.get("value")).intValue());
|
||||
assertEquals(16, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-01", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(25, ((Number) row.get("value")).intValue());
|
||||
assertEquals(26, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-02", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(35, ((Number) row.get("value")).intValue());
|
||||
assertEquals(36, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-03", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResultTest_xlsx_convertPropertyValue()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("size", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("date", DataSetProperty.DataType.STRING));
|
||||
|
||||
ExcelDirectoryFileDataSet dataSet = new ExcelDirectoryFileDataSet("a", "a", properties, DIRECTORY,
|
||||
"ExcelDirectoryFileDataSetTest-0.xlsx");
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
DataSetResult result = dataSet.getResult(Collections.EMPTY_MAP);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(15, ((Number) row.get("value")).intValue());
|
||||
assertEquals("16", row.get("size"));
|
||||
assertEquals("2020-08-01", row.get("date"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(25, ((Number) row.get("value")).intValue());
|
||||
assertEquals("26", row.get("size"));
|
||||
assertEquals("2020-08-02", row.get("date"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(35, ((Number) row.get("value")).intValue());
|
||||
assertEquals("36", row.get("size"));
|
||||
assertEquals("2020-08-03", row.get("date"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_xlsx()
|
||||
{
|
||||
ExcelDirectoryFileDataSet dataSet = new ExcelDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"ExcelDirectoryFileDataSetTest-0.xlsx");
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
ResolvedDataSetResult resolvedResult = dataSet.resolve(new HashMap<>());
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) resolvedResult.getResult().getData();
|
||||
List<DataSetProperty> properties = resolvedResult.getProperties();
|
||||
|
||||
{
|
||||
assertEquals(4, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(3);
|
||||
assertEquals("date", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DATE, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(15, ((Number) row.get("value")).intValue());
|
||||
assertEquals(16, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-01", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(25, ((Number) row.get("value")).intValue());
|
||||
assertEquals(26, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-02", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(35, ((Number) row.get("value")).intValue());
|
||||
assertEquals(36, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-03", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_xls()
|
||||
{
|
||||
ExcelDirectoryFileDataSet dataSet = new ExcelDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"ExcelDirectoryFileDataSetTest-1.xls");
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
ResolvedDataSetResult resolvedResult = dataSet.resolve(new HashMap<>());
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) resolvedResult.getResult().getData();
|
||||
List<DataSetProperty> properties = resolvedResult.getProperties();
|
||||
|
||||
{
|
||||
assertEquals(4, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(3);
|
||||
assertEquals("date", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DATE, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(15, ((Number) row.get("value")).intValue());
|
||||
assertEquals(16, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-01", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(25, ((Number) row.get("value")).intValue());
|
||||
assertEquals(26, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-02", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(35, ((Number) row.get("value")).intValue());
|
||||
assertEquals(36, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-03", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_dataRowColumnExp()
|
||||
{
|
||||
ExcelDirectoryFileDataSet dataSet = new ExcelDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"ExcelDirectoryFileDataSetTest-0.xlsx");
|
||||
dataSet.setNameRow(1);
|
||||
dataSet.setDataRowExp("2,3-");
|
||||
dataSet.setDataColumnExp("A,C-");
|
||||
|
||||
ResolvedDataSetResult resolvedResult = dataSet.resolve(new HashMap<>());
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) resolvedResult.getResult().getData();
|
||||
List<DataSetProperty> properties = resolvedResult.getProperties();
|
||||
|
||||
{
|
||||
assertEquals(3, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("date", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DATE, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(16, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-01", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(26, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-02", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(36, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-03", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,496 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.ContentType;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
|
||||
import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap;
|
||||
import org.apache.hc.core5.http.io.HttpRequestHandler;
|
||||
import org.apache.hc.core5.http.io.entity.StringEntity;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.datagear.analysis.DataSetParam;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.util.IOUtil;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain HttpDataSet}单元测试用例。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class HttpDataSetTest
|
||||
{
|
||||
protected static final int PORT = 50402;
|
||||
|
||||
protected static final String SERVER = "http://localhost:" + PORT;
|
||||
|
||||
protected static final String PARAM_NAME_0 = "param0";
|
||||
|
||||
protected static final String PARAM_NAME_1 = "param1";
|
||||
|
||||
protected static HttpServer server;
|
||||
|
||||
protected static CloseableHttpClient httpClient;
|
||||
|
||||
@BeforeClass
|
||||
public static void initTestHttpServer() throws Throwable
|
||||
{
|
||||
server = ServerBootstrap.bootstrap().setListenerPort(PORT)
|
||||
//
|
||||
.register("/testSimple", new HttpRequestHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
StringEntity responseEntity = new StringEntity(
|
||||
"[{name: 'aaa', value: 11}, {name: '名称b', value: 22}]", ContentType.APPLICATION_JSON);
|
||||
response.setEntity(responseEntity);
|
||||
}
|
||||
})
|
||||
//
|
||||
.register("/testParam", new HttpRequestHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
Map<String, String> params = parseRequestParams(request);
|
||||
String p0 = params.get(PARAM_NAME_0);
|
||||
String p1 = params.get(PARAM_NAME_1);
|
||||
|
||||
StringEntity responseEntity = new StringEntity("[{name: '" + PARAM_NAME_0 + "', value: '" + p0
|
||||
+ "'}, {name: '" + PARAM_NAME_1 + "', value: '" + p1 + "'}]",
|
||||
ContentType.APPLICATION_JSON);
|
||||
response.setEntity(responseEntity);
|
||||
}
|
||||
})
|
||||
//
|
||||
.register("/testJson", new HttpRequestHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
String reqJson = getRequestStringContent(request);
|
||||
|
||||
StringEntity responseEntity = new StringEntity(reqJson, ContentType.APPLICATION_JSON);
|
||||
response.setEntity(responseEntity);
|
||||
}
|
||||
})
|
||||
//
|
||||
.register("/testHeader", new HttpRequestHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
Header h0 = request.getHeader(PARAM_NAME_0);
|
||||
Header h1 = request.getHeader(PARAM_NAME_1);
|
||||
|
||||
StringEntity responseEntity = new StringEntity(
|
||||
"[{name: '" + PARAM_NAME_0 + "', value: '" + h0.getValue() + "'}, {name: '"
|
||||
+ PARAM_NAME_1 + "', value: '" + h1.getValue() + "'}]",
|
||||
ContentType.APPLICATION_JSON);
|
||||
response.setEntity(responseEntity);
|
||||
}
|
||||
})
|
||||
//
|
||||
.register("/testResponseJsonPath", new HttpRequestHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
StringEntity responseEntity = new StringEntity(
|
||||
"{ path0: { path1: [ { path2: [{name: 'aaa', value: 11}, {name: '名称b', value: 22}] } ] } }",
|
||||
ContentType.APPLICATION_JSON);
|
||||
response.setEntity(responseEntity);
|
||||
}
|
||||
})
|
||||
//
|
||||
.create();
|
||||
|
||||
server.start();
|
||||
|
||||
httpClient = HttpClients.createDefault();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void closeHttpServer() throws Throwable
|
||||
{
|
||||
server.close();
|
||||
httpClient.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_onlyUri() throws Throwable
|
||||
{
|
||||
List<DataSetParam> params = Arrays.asList(new DataSetParam("param", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
HttpDataSet dataSet = new HttpDataSet(HttpDataSet.class.getName(), HttpDataSet.class.getName(), httpClient,
|
||||
SERVER + "/testSimple?param=${param}");
|
||||
|
||||
dataSet.setParams(params);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("param", "pv");
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(paramValues);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
String templateResult = result.getTemplateResult();
|
||||
|
||||
{
|
||||
assertEquals(2, properties.size());
|
||||
|
||||
assertTrue(templateResult.contains("param=pv"));
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(2, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("名称b", row.get("name"));
|
||||
assertEquals(22, ((Number) row.get("value")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_setRequestMethod_GET() throws Throwable
|
||||
{
|
||||
HttpDataSet dataSet = new HttpDataSet(HttpDataSet.class.getName(), HttpDataSet.class.getName(), httpClient,
|
||||
SERVER + "/testSimple");
|
||||
|
||||
dataSet.setRequestMethod(HttpDataSet.REQUEST_METHOD_GET);
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(Collections.emptyMap());
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
assertEquals(2, properties.size());
|
||||
assertEquals(2, data.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_setRequestMethod_POST() throws Throwable
|
||||
{
|
||||
HttpDataSet dataSet = new HttpDataSet(HttpDataSet.class.getName(), HttpDataSet.class.getName(), httpClient,
|
||||
SERVER + "/testSimple");
|
||||
|
||||
dataSet.setRequestMethod(HttpDataSet.REQUEST_METHOD_POST);
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(Collections.emptyMap());
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
assertEquals(2, properties.size());
|
||||
assertEquals(2, data.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_REQUEST_CONTENT_TYPE_FORM_URLENCODED() throws Throwable
|
||||
{
|
||||
String pv0 = "p0";
|
||||
String pv1 = "参数值1";
|
||||
|
||||
List<DataSetParam> params = Arrays.asList(new DataSetParam("param", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
HttpDataSet dataSet = new HttpDataSet(HttpDataSet.class.getName(), HttpDataSet.class.getName(), httpClient,
|
||||
SERVER + "/testParam");
|
||||
dataSet.setRequestContent("[ { name: '" + PARAM_NAME_0 + "', value: '" + pv0 + "' }, { name: '" + PARAM_NAME_1
|
||||
+ "', value: '${param}' } ]");
|
||||
dataSet.setParams(params);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("param", pv1);
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(paramValues);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
String templateResult = result.getTemplateResult();
|
||||
|
||||
{
|
||||
assertEquals(2, properties.size());
|
||||
|
||||
assertTrue(templateResult.contains("value: '" + pv1 + "'"));
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(2, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals(PARAM_NAME_0, row.get("name"));
|
||||
assertEquals(pv0, row.get("value"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals(PARAM_NAME_1, row.get("name"));
|
||||
assertEquals(pv1, row.get("value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_REQUEST_CONTENT_TYPE_JSON() throws Throwable
|
||||
{
|
||||
String pv0 = "p0";
|
||||
String pv1 = "参数值1";
|
||||
|
||||
List<DataSetParam> params = Arrays.asList(new DataSetParam("param", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
HttpDataSet dataSet = new HttpDataSet(HttpDataSet.class.getName(), HttpDataSet.class.getName(), httpClient,
|
||||
SERVER + "/testJson");
|
||||
dataSet.setRequestContentType(HttpDataSet.REQUEST_CONTENT_TYPE_JSON);
|
||||
dataSet.setRequestContent("[ { name: '" + PARAM_NAME_0 + "', value: '" + pv0 + "' }, { name: '" + PARAM_NAME_1
|
||||
+ "', value: '${param}' } ]");
|
||||
dataSet.setParams(params);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("param", pv1);
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(paramValues);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
String templateResult = result.getTemplateResult();
|
||||
|
||||
{
|
||||
assertEquals(2, properties.size());
|
||||
|
||||
assertTrue(templateResult.contains("value: '" + pv1 + "'"));
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(2, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals(PARAM_NAME_0, row.get("name"));
|
||||
assertEquals(pv0, row.get("value"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals(PARAM_NAME_1, row.get("name"));
|
||||
assertEquals(pv1, row.get("value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_setHeaderContent() throws Throwable
|
||||
{
|
||||
String pv0 = "p0";
|
||||
String pv1 = "p1";
|
||||
|
||||
List<DataSetParam> params = Arrays.asList(new DataSetParam("param", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
HttpDataSet dataSet = new HttpDataSet(HttpDataSet.class.getName(), HttpDataSet.class.getName(), httpClient,
|
||||
SERVER + "/testHeader");
|
||||
dataSet.setHeaderContent("[ { name: '" + PARAM_NAME_0 + "', value: '" + pv0 + "' }, { name: '" + PARAM_NAME_1
|
||||
+ "', value: '${param}' } ]");
|
||||
dataSet.setParams(params);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("param", pv1);
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(paramValues);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
String templateResult = result.getTemplateResult();
|
||||
|
||||
{
|
||||
assertEquals(2, properties.size());
|
||||
|
||||
assertTrue(templateResult.contains("value: '" + pv1 + "'"));
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(2, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals(PARAM_NAME_0, row.get("name"));
|
||||
assertEquals(pv0, row.get("value"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals(PARAM_NAME_1, row.get("name"));
|
||||
assertEquals(pv1, row.get("value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_setResponseDataJsonPath() throws Throwable
|
||||
{
|
||||
HttpDataSet dataSet = new HttpDataSet(HttpDataSet.class.getName(), HttpDataSet.class.getName(), httpClient,
|
||||
SERVER + "/testResponseJsonPath");
|
||||
dataSet.setResponseDataJsonPath("path0.path1[0].path2");
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(Collections.emptyMap());
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
{
|
||||
assertEquals(2, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(2, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("名称b", row.get("name"));
|
||||
assertEquals(22, ((Number) row.get("value")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static Map<String, String> parseRequestParams(ClassicHttpRequest request) throws IOException
|
||||
{
|
||||
Map<String, String> map = new HashMap<>();
|
||||
|
||||
String content = getRequestStringContent(request);
|
||||
|
||||
String[] strss = content.split("&");
|
||||
for (String strs : strss)
|
||||
{
|
||||
String[] pv = strs.split("=");
|
||||
|
||||
map.put(pv[0], URLDecoder.decode(pv[1], IOUtil.CHARSET_UTF_8));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
protected static String getRequestStringContent(ClassicHttpRequest request) throws IOException
|
||||
{
|
||||
HttpEntity entity = request.getEntity();
|
||||
String contentTypeStr = entity.getContentType();
|
||||
ContentType contentType = ContentType.parse(contentTypeStr);
|
||||
Reader reader = new InputStreamReader(entity.getContent(), contentType.getCharset());
|
||||
String content = IOUtil.readString(reader, false);
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain JsonDataSetSupport}单元测试类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class JsonDataSetSupportTest
|
||||
{
|
||||
private JsonDataSetSupport jsonDataSetSupport = new JsonDataSetSupport();
|
||||
|
||||
@Test
|
||||
public void resolveResultDataTest_String()
|
||||
{
|
||||
Object data = jsonDataSetSupport.resolveResultData("{name:'a', value: 3}");
|
||||
|
||||
Assert.assertTrue(data instanceof Map);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) data;
|
||||
|
||||
Assert.assertEquals("a", map.get("name"));
|
||||
Assert.assertEquals(3, ((Number) map.get("value")).intValue());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain JsonDirectoryFileDataSet}单元测试类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class JsonDirectoryFileDataSetTest
|
||||
{
|
||||
private static final File DIRECTORY = new File("src/test/resources/org/datagear/analysis/support/");
|
||||
|
||||
@Test
|
||||
public void getResultTest()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("尺寸", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("date", DataSetProperty.DataType.STRING));
|
||||
|
||||
JsonDirectoryFileDataSet dataSet = new JsonDirectoryFileDataSet("a", "a", properties, DIRECTORY,
|
||||
"JsonDirectoryFileDataSetTest-0.json");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
DataSetResult result = dataSet.getResult(Collections.EMPTY_MAP);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-01", row.get("date"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(21, ((Number) row.get("value")).intValue());
|
||||
assertEquals(22, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-02", row.get("date"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(31, ((Number) row.get("value")).intValue());
|
||||
assertEquals(32, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-03", row.get("date"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResultTest_convertPropertyValue()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("尺寸", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("date", DataSetProperty.DataType.DATE));
|
||||
|
||||
JsonDirectoryFileDataSet dataSet = new JsonDirectoryFileDataSet("a", "a", properties, DIRECTORY,
|
||||
"JsonDirectoryFileDataSetTest-0.json");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
DataSetResult result = dataSet.getResult(Collections.EMPTY_MAP);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(DataFormat.DEFAULT_DATE_FORMAT);
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-01", dateFormat.format(((Date) row.get("date"))));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(21, ((Number) row.get("value")).intValue());
|
||||
assertEquals(22, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-02", dateFormat.format(((Date) row.get("date"))));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(31, ((Number) row.get("value")).intValue());
|
||||
assertEquals(32, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-03", dateFormat.format(((Date) row.get("date"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest()
|
||||
{
|
||||
JsonDirectoryFileDataSet dataSet = new JsonDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"JsonDirectoryFileDataSetTest-0.json");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ResolvedDataSetResult result = dataSet.resolve(Collections.EMPTY_MAP);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
{
|
||||
assertEquals(4, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("尺寸", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(3);
|
||||
assertEquals("date", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-01", row.get("date"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(21, ((Number) row.get("value")).intValue());
|
||||
assertEquals(22, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-02", row.get("date"));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(31, ((Number) row.get("value")).intValue());
|
||||
assertEquals(32, ((Number) row.get("尺寸")).intValue());
|
||||
assertEquals("2020-08-03", row.get("date"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetParam;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain JsonValueDataSet}单元测试类。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class JsonValueDataSetTest
|
||||
{
|
||||
@Test
|
||||
public void getResultTest_hasParam()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("size", DataSetProperty.DataType.NUMBER));
|
||||
|
||||
List<DataSetParam> params = new ArrayList<>();
|
||||
params.add(new DataSetParam("size", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
JsonValueDataSet dataSet = new JsonValueDataSet(JsonValueDataSet.class.getSimpleName(),
|
||||
JsonValueDataSet.class.getSimpleName(), properties, "[ { name:'aaa', value: 11, size: ${size} } ]");
|
||||
dataSet.setParams(params);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("size", 12);
|
||||
|
||||
DataSetResult result = dataSet.getResult(paramValues);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(1, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("size")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResultTest_hasParam_convertPropertyValue()
|
||||
{
|
||||
List<DataSetProperty> properties = new ArrayList<>();
|
||||
properties.add(new DataSetProperty("name", DataSetProperty.DataType.STRING));
|
||||
properties.add(new DataSetProperty("value", DataSetProperty.DataType.NUMBER));
|
||||
properties.add(new DataSetProperty("size", DataSetProperty.DataType.STRING));
|
||||
|
||||
List<DataSetParam> params = new ArrayList<>();
|
||||
params.add(new DataSetParam("size", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
JsonValueDataSet dataSet = new JsonValueDataSet(JsonValueDataSet.class.getSimpleName(),
|
||||
JsonValueDataSet.class.getSimpleName(), properties, "[ { name:'aaa', value: 11, size: ${size} } ]");
|
||||
dataSet.setParams(params);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("size", 12);
|
||||
|
||||
DataSetResult result = dataSet.getResult(paramValues);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getData();
|
||||
|
||||
{
|
||||
assertEquals(1, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals("12", row.get("size"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_hasParam()
|
||||
{
|
||||
List<DataSetParam> params = new ArrayList<>();
|
||||
params.add(new DataSetParam("size", DataSetParam.DataType.NUMBER, true));
|
||||
|
||||
JsonValueDataSet dataSet = new JsonValueDataSet(JsonValueDataSet.class.getSimpleName(),
|
||||
JsonValueDataSet.class.getSimpleName(), "[ { name:'aaa', value: 11, size: ${size} } ]");
|
||||
dataSet.setParams(params);
|
||||
|
||||
Map<String, Object> paramValues = new HashMap<>();
|
||||
paramValues.put("size", 12);
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(paramValues);
|
||||
List<DataSetProperty> properties = result.getProperties();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) result.getResult().getData();
|
||||
|
||||
assertEquals("[ { name:'aaa', value: 11, size: 12 } ]", result.getTemplateResult());
|
||||
|
||||
{
|
||||
assertEquals(3, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.NUMBER, property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(1, data.size());
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(11, ((Number) row.get("value")).intValue());
|
||||
assertEquals(12, ((Number) row.get("size")).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,10 +16,10 @@ import java.util.Map;
|
|||
|
||||
import org.datagear.analysis.DataSetParam;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetProperty.DataType;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.util.JdbcUtil;
|
||||
import org.datagear.util.resource.SimpleConnectionFactory;
|
||||
import org.datagear.util.test.DBTestSupport;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -61,10 +61,12 @@ public class SqlDataSetTest extends DBTestSupport
|
|||
|
||||
String sql = "SELECT ID, NAME FROM T_ACCOUNT <#if id??>WHERE ID = ${id} AND NAME != '${name}'</#if>";
|
||||
|
||||
List<DataSetProperty> dataSetProperties = Arrays.asList(new DataSetProperty("ID", DataType.INTEGER),
|
||||
new DataSetProperty("NAME", DataType.STRING));
|
||||
List<DataSetParam> dataSetParams = Arrays.asList(new DataSetParam("id", DataType.STRING, true),
|
||||
new DataSetParam("name", DataType.STRING, true));
|
||||
List<DataSetProperty> dataSetProperties = Arrays.asList(
|
||||
new DataSetProperty("ID", DataSetProperty.DataType.INTEGER),
|
||||
new DataSetProperty("NAME", DataSetProperty.DataType.STRING));
|
||||
|
||||
List<DataSetParam> dataSetParams = Arrays.asList(new DataSetParam("id", DataSetParam.DataType.STRING, true),
|
||||
new DataSetParam("name", DataSetParam.DataType.STRING, true));
|
||||
|
||||
SqlDataSet sqlDataSet = new SqlDataSet("1", "1", dataSetProperties, connectionFactory, sql);
|
||||
sqlDataSet.setParams(dataSetParams);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
name, value, 尺寸
|
||||
aaa, 11, 12
|
||||
bbb, 21, 22
|
||||
ccc, 31, 32
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
name: "aaa",
|
||||
value: 11,
|
||||
"尺寸": 12,
|
||||
date: "2020-08-01"
|
||||
},
|
||||
{
|
||||
name: "bbb",
|
||||
value: 21,
|
||||
"尺寸": 22,
|
||||
date: "2020-08-02"
|
||||
},
|
||||
{
|
||||
name: "ccc",
|
||||
value: 31,
|
||||
"尺寸": 32,
|
||||
date: "2020-08-03"
|
||||
}
|
||||
]
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<version>1.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-connection</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<version>1.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-dataexchange</artifactId>
|
||||
|
@ -27,17 +27,17 @@
|
|||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-csv</artifactId>
|
||||
<version>1.4</version>
|
||||
<version>${commons-csv.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>3.17</version>
|
||||
<version>${poi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>3.17</version>
|
||||
<version>${poi-ooxml.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<version>1.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-management</artifactId>
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.management.domain;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.support.CsvDirectoryFileDataSet;
|
||||
|
||||
/**
|
||||
* {@linkplain CsvDirectoryFileDataSet}实体。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class CsvFileDataSetEntity extends CsvDirectoryFileDataSet implements DirectoryFileDataSetEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 展示名 */
|
||||
private String displayName;
|
||||
|
||||
/** 创建用户 */
|
||||
private User createUser;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createTime;
|
||||
|
||||
/** 权限 */
|
||||
private int dataPermission = PERMISSION_NOT_LOADED;
|
||||
|
||||
public CsvFileDataSetEntity()
|
||||
{
|
||||
super();
|
||||
this.createTime = new Date();
|
||||
}
|
||||
|
||||
public CsvFileDataSetEntity(String id, String name, List<DataSetProperty> properties, File directory,
|
||||
String fileName, String displayName, User createUser)
|
||||
{
|
||||
super(id, name, properties, directory, fileName);
|
||||
this.displayName = displayName;
|
||||
this.createTime = new Date();
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName()
|
||||
{
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayName(String displayName)
|
||||
{
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataSetType()
|
||||
{
|
||||
return DataSetEntity.DATA_SET_TYPE_CsvFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataSetType(String dataSetType)
|
||||
{
|
||||
// XXX 什么也不做,不采用抛出异常的方式,便于统一底层SQL查询语句
|
||||
// throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getCreateUser()
|
||||
{
|
||||
return createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateUser(User createUser)
|
||||
{
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreateTime()
|
||||
{
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateTime(Date createTime)
|
||||
{
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataPermission()
|
||||
{
|
||||
return dataPermission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataPermission(int dataPermission)
|
||||
{
|
||||
this.dataPermission = dataPermission;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.management.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.support.CsvValueDataSet;
|
||||
|
||||
/**
|
||||
* {@linkplain CsvValueDataSet}实体。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class CsvValueDataSetEntity extends CsvValueDataSet implements DataSetEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 创建用户 */
|
||||
private User createUser;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createTime;
|
||||
|
||||
/** 权限 */
|
||||
private int dataPermission = PERMISSION_NOT_LOADED;
|
||||
|
||||
public CsvValueDataSetEntity()
|
||||
{
|
||||
super();
|
||||
this.createTime = new Date();
|
||||
}
|
||||
|
||||
public CsvValueDataSetEntity(String id, String name, List<DataSetProperty> properties, String value,
|
||||
User createUser)
|
||||
{
|
||||
super(id, name, properties, value);
|
||||
this.createTime = new Date();
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataSetType()
|
||||
{
|
||||
return DataSetEntity.DATA_SET_TYPE_CsvValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataSetType(String dataSetType)
|
||||
{
|
||||
// XXX 什么也不做,不采用抛出异常的方式,便于统一底层SQL查询语句
|
||||
// throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getCreateUser()
|
||||
{
|
||||
return createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateUser(User createUser)
|
||||
{
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreateTime()
|
||||
{
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateTime(Date createTime)
|
||||
{
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataPermission()
|
||||
{
|
||||
return dataPermission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataPermission(int dataPermission)
|
||||
{
|
||||
this.dataPermission = dataPermission;
|
||||
}
|
||||
}
|
|
@ -31,6 +31,18 @@ public interface DataSetEntity extends DataSet, CreateUserEntity<String>, DataPe
|
|||
/** 数据集类型:JSON文件 */
|
||||
String DATA_SET_TYPE_JsonFile = "JsonFile";
|
||||
|
||||
/** 数据集类型:Excel */
|
||||
String DATA_SET_TYPE_Excel = "Excel";
|
||||
|
||||
/** 数据集类型:CSV值 */
|
||||
String DATA_SET_TYPE_CsvValue = "CsvValue";
|
||||
|
||||
/** 数据集类型:CSV文件 */
|
||||
String DATA_SET_TYPE_CsvFile = "CsvFile";
|
||||
|
||||
/** 数据集类型:HTTP接口 */
|
||||
String DATA_SET_TYPE_Http = "Http";
|
||||
|
||||
/**
|
||||
* 设置名称。
|
||||
*
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.management.domain;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 目录内文件数据集实体。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public interface DirectoryFileDataSetEntity extends DataSetEntity
|
||||
{
|
||||
/**
|
||||
* 获取目录。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
File getDirectory();
|
||||
|
||||
/**
|
||||
* 设置目录。
|
||||
*
|
||||
* @param directory
|
||||
*/
|
||||
void setDirectory(File directory);
|
||||
|
||||
/**
|
||||
* 获取文件名。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getFileName();
|
||||
|
||||
/**
|
||||
* 设置文件名。
|
||||
*
|
||||
* @param fileName
|
||||
*/
|
||||
void setFileName(String fileName);
|
||||
|
||||
/**
|
||||
* 获取文件展示名。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getDisplayName();
|
||||
|
||||
/**
|
||||
* 设置文件展示名。
|
||||
*
|
||||
* @param displayName
|
||||
*/
|
||||
void setDisplayName(String displayName);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.management.domain;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.support.ExcelDirectoryFileDataSet;
|
||||
|
||||
/**
|
||||
* {@linkplain ExcelDirectoryFileDataSet}实体。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class ExcelDataSetEntity extends ExcelDirectoryFileDataSet implements DirectoryFileDataSetEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 展示名 */
|
||||
private String displayName;
|
||||
|
||||
/** 创建用户 */
|
||||
private User createUser;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createTime;
|
||||
|
||||
/** 权限 */
|
||||
private int dataPermission = PERMISSION_NOT_LOADED;
|
||||
|
||||
public ExcelDataSetEntity()
|
||||
{
|
||||
super();
|
||||
this.createTime = new Date();
|
||||
}
|
||||
|
||||
public ExcelDataSetEntity(String id, String name, List<DataSetProperty> properties, File directory, String fileName,
|
||||
String displayName, User createUser)
|
||||
{
|
||||
super(id, name, properties, directory, fileName);
|
||||
this.displayName = displayName;
|
||||
this.createTime = new Date();
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName()
|
||||
{
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayName(String displayName)
|
||||
{
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataSetType()
|
||||
{
|
||||
return DataSetEntity.DATA_SET_TYPE_Excel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataSetType(String dataSetType)
|
||||
{
|
||||
// XXX 什么也不做,不采用抛出异常的方式,便于统一底层SQL查询语句
|
||||
// throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getCreateUser()
|
||||
{
|
||||
return createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateUser(User createUser)
|
||||
{
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreateTime()
|
||||
{
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateTime(Date createTime)
|
||||
{
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataPermission()
|
||||
{
|
||||
return dataPermission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataPermission(int dataPermission)
|
||||
{
|
||||
this.dataPermission = dataPermission;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.management.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.classic.HttpClient;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.support.HttpDataSet;
|
||||
|
||||
/**
|
||||
* {@linkplain HttpDataSet}实体。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class HttpDataSetEntity extends HttpDataSet implements DataSetEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 创建用户 */
|
||||
private User createUser;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createTime;
|
||||
|
||||
/** 权限 */
|
||||
private int dataPermission = PERMISSION_NOT_LOADED;
|
||||
|
||||
public HttpDataSetEntity()
|
||||
{
|
||||
super();
|
||||
this.createTime = new Date();
|
||||
}
|
||||
|
||||
public HttpDataSetEntity(String id, String name, HttpClient httpClient, String uri, User createUser)
|
||||
{
|
||||
super(id, name, httpClient, uri);
|
||||
this.createTime = new Date();
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
public HttpDataSetEntity(String id, String name, List<DataSetProperty> properties, HttpClient httpClient,
|
||||
String uri, User createUser)
|
||||
{
|
||||
super(id, name, properties, httpClient, uri);
|
||||
this.createTime = new Date();
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataSetType()
|
||||
{
|
||||
return DataSetEntity.DATA_SET_TYPE_Http;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataSetType(String dataSetType)
|
||||
{
|
||||
// XXX 什么也不做,不采用抛出异常的方式,便于统一底层SQL查询语句
|
||||
// throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getCreateUser()
|
||||
{
|
||||
return createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateUser(User createUser)
|
||||
{
|
||||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreateTime()
|
||||
{
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateTime(Date createTime)
|
||||
{
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataPermission()
|
||||
{
|
||||
return dataPermission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataPermission(int dataPermission)
|
||||
{
|
||||
this.dataPermission = dataPermission;
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ import org.datagear.analysis.support.JsonDirectoryFileDataSet;
|
|||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class JsonFileDataSetEntity extends JsonDirectoryFileDataSet implements DataSetEntity
|
||||
public class JsonFileDataSetEntity extends JsonDirectoryFileDataSet implements DirectoryFileDataSetEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -51,11 +51,13 @@ public class JsonFileDataSetEntity extends JsonDirectoryFileDataSet implements D
|
|||
this.createUser = createUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName()
|
||||
{
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayName(String displayName)
|
||||
{
|
||||
this.displayName = displayName;
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.datagear.management.service;
|
|||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.hc.client5.http.classic.HttpClient;
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.management.domain.DataSetEntity;
|
||||
|
||||
|
@ -36,4 +37,11 @@ public interface DataSetEntityService
|
|||
* @return
|
||||
*/
|
||||
File getDataSetDirectory(String dataSetId);
|
||||
|
||||
/**
|
||||
* 获取{@linkplain HttpClient}。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
HttpClient getHttpClient();
|
||||
}
|
||||
|
|
|
@ -12,12 +12,17 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hc.client5.http.classic.HttpClient;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetParam;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.connection.ConnectionSource;
|
||||
import org.datagear.management.domain.CsvFileDataSetEntity;
|
||||
import org.datagear.management.domain.CsvValueDataSetEntity;
|
||||
import org.datagear.management.domain.DataSetEntity;
|
||||
import org.datagear.management.domain.ExcelDataSetEntity;
|
||||
import org.datagear.management.domain.HttpDataSetEntity;
|
||||
import org.datagear.management.domain.JsonFileDataSetEntity;
|
||||
import org.datagear.management.domain.JsonValueDataSetEntity;
|
||||
import org.datagear.management.domain.SchemaConnectionFactory;
|
||||
|
@ -51,29 +56,35 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
|
|||
/** 数据集文件存储根目录 */
|
||||
private File dataSetRootDirectory;
|
||||
|
||||
private HttpClient httpClient;
|
||||
|
||||
public DataSetEntityServiceImpl()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public DataSetEntityServiceImpl(SqlSessionFactory sqlSessionFactory, ConnectionSource connectionSource,
|
||||
SchemaService schemaService, AuthorizationService authorizationService, File dataSetRootDirectory)
|
||||
SchemaService schemaService, AuthorizationService authorizationService, File dataSetRootDirectory,
|
||||
HttpClient httpClient)
|
||||
{
|
||||
super(sqlSessionFactory);
|
||||
this.connectionSource = connectionSource;
|
||||
this.schemaService = schemaService;
|
||||
this.authorizationService = authorizationService;
|
||||
setDataSetRootDirectory(dataSetRootDirectory);
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public DataSetEntityServiceImpl(SqlSessionTemplate sqlSessionTemplate, ConnectionSource connectionSource,
|
||||
SchemaService schemaService, AuthorizationService authorizationService, File dataSetRootDirectory)
|
||||
SchemaService schemaService, AuthorizationService authorizationService, File dataSetRootDirectory,
|
||||
HttpClient httpClient)
|
||||
{
|
||||
super(sqlSessionTemplate);
|
||||
this.connectionSource = connectionSource;
|
||||
this.schemaService = schemaService;
|
||||
this.authorizationService = authorizationService;
|
||||
setDataSetRootDirectory(dataSetRootDirectory);
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public ConnectionSource getConnectionSource()
|
||||
|
@ -116,6 +127,17 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
|
|||
this.dataSetRootDirectory = dataSetRootDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClient getHttpClient()
|
||||
{
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
public void setHttpClient(HttpClient httpClient)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataSetDirectory(String dataSetId)
|
||||
{
|
||||
|
@ -167,6 +189,14 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
|
|||
success = addJsonValueDataSetEntity((JsonValueDataSetEntity) entity);
|
||||
else if (entity instanceof JsonFileDataSetEntity)
|
||||
success = addJsonFileDataSetEntity((JsonFileDataSetEntity) entity);
|
||||
else if (entity instanceof ExcelDataSetEntity)
|
||||
success = addExcelDataSetEntity((ExcelDataSetEntity) entity);
|
||||
else if (entity instanceof CsvValueDataSetEntity)
|
||||
success = addCsvValueDataSetEntity((CsvValueDataSetEntity) entity);
|
||||
else if (entity instanceof CsvFileDataSetEntity)
|
||||
success = addCsvFileDataSetEntity((CsvFileDataSetEntity) entity);
|
||||
else if (entity instanceof HttpDataSetEntity)
|
||||
success = addHttpDataSetEntity((HttpDataSetEntity) entity);
|
||||
}
|
||||
|
||||
if (success)
|
||||
|
@ -199,6 +229,38 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
|
|||
return (updateMybatis("insertJsonFileDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
protected boolean addExcelDataSetEntity(ExcelDataSetEntity entity)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("entity", entity);
|
||||
|
||||
return (updateMybatis("insertExcelDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
protected boolean addCsvValueDataSetEntity(CsvValueDataSetEntity entity)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("entity", entity);
|
||||
|
||||
return (updateMybatis("insertCsvValueDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
protected boolean addCsvFileDataSetEntity(CsvFileDataSetEntity entity)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("entity", entity);
|
||||
|
||||
return (updateMybatis("insertCsvFileDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
protected boolean addHttpDataSetEntity(HttpDataSetEntity entity)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("entity", entity);
|
||||
|
||||
return (updateMybatis("insertHttpDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean update(DataSetEntity entity, Map<String, Object> params)
|
||||
{
|
||||
|
@ -215,6 +277,14 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
|
|||
success = updateJsonValueDataSetEntity((JsonValueDataSetEntity) entity);
|
||||
else if (entity instanceof JsonFileDataSetEntity)
|
||||
success = updateJsonFileDataSetEntity((JsonFileDataSetEntity) entity);
|
||||
else if (entity instanceof ExcelDataSetEntity)
|
||||
success = updateExcelDataSetEntity((ExcelDataSetEntity) entity);
|
||||
else if (entity instanceof CsvValueDataSetEntity)
|
||||
success = updateCsvValueDataSetEntity((CsvValueDataSetEntity) entity);
|
||||
else if (entity instanceof CsvFileDataSetEntity)
|
||||
success = updateCsvFileDataSetEntity((CsvFileDataSetEntity) entity);
|
||||
else if (entity instanceof HttpDataSetEntity)
|
||||
success = updateHttpDataSetEntity((HttpDataSetEntity) entity);
|
||||
}
|
||||
|
||||
if (success)
|
||||
|
@ -247,6 +317,38 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
|
|||
return (updateMybatis("updateJsonFileDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
protected boolean updateExcelDataSetEntity(ExcelDataSetEntity entity)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("entity", entity);
|
||||
|
||||
return (updateMybatis("updateExcelDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
protected boolean updateCsvValueDataSetEntity(CsvValueDataSetEntity entity)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("entity", entity);
|
||||
|
||||
return (updateMybatis("updateCsvValueDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
protected boolean updateCsvFileDataSetEntity(CsvFileDataSetEntity entity)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("entity", entity);
|
||||
|
||||
return (updateMybatis("updateCsvFileDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
protected boolean updateHttpDataSetEntity(HttpDataSetEntity entity)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("entity", entity);
|
||||
|
||||
return (updateMybatis("updateHttpDataSetEntity", params) > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceType()
|
||||
{
|
||||
|
@ -291,6 +393,14 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
|
|||
obj = getJsonValueDataSetEntityById(obj.getId());
|
||||
else if (DataSetEntity.DATA_SET_TYPE_JsonFile.equals(obj.getDataSetType()))
|
||||
obj = getJsonFileDataSetEntityById(obj.getId());
|
||||
else if (DataSetEntity.DATA_SET_TYPE_Excel.equals(obj.getDataSetType()))
|
||||
obj = getExcelDataSetEntityById(obj.getId());
|
||||
else if (DataSetEntity.DATA_SET_TYPE_CsvValue.equals(obj.getDataSetType()))
|
||||
obj = getCsvValueDataSetEntityById(obj.getId());
|
||||
else if (DataSetEntity.DATA_SET_TYPE_CsvFile.equals(obj.getDataSetType()))
|
||||
obj = getCsvFileDataSetEntityById(obj.getId());
|
||||
else if (DataSetEntity.DATA_SET_TYPE_Http.equals(obj.getDataSetType()))
|
||||
obj = getHttpDataSetEntityById(obj.getId());
|
||||
|
||||
if (obj == null)
|
||||
return null;
|
||||
|
@ -342,6 +452,55 @@ public class DataSetEntityServiceImpl extends AbstractMybatisDataPermissionEntit
|
|||
return entity;
|
||||
}
|
||||
|
||||
protected ExcelDataSetEntity getExcelDataSetEntityById(String id)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("id", id);
|
||||
|
||||
ExcelDataSetEntity entity = selectOneMybatis("getExcelDataSetEntityById", params);
|
||||
|
||||
if (entity != null)
|
||||
entity.setDirectory(getDataSetDirectory(id));
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
protected CsvValueDataSetEntity getCsvValueDataSetEntityById(String id)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("id", id);
|
||||
|
||||
CsvValueDataSetEntity entity = selectOneMybatis("getCsvValueDataSetEntityById", params);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
protected CsvFileDataSetEntity getCsvFileDataSetEntityById(String id)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("id", id);
|
||||
|
||||
CsvFileDataSetEntity entity = selectOneMybatis("getCsvFileDataSetEntityById", params);
|
||||
|
||||
if (entity != null)
|
||||
entity.setDirectory(getDataSetDirectory(id));
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
protected HttpDataSetEntity getHttpDataSetEntityById(String id)
|
||||
{
|
||||
Map<String, Object> params = buildParamMapWithIdentifierQuoteParameter();
|
||||
params.put("id", id);
|
||||
|
||||
HttpDataSetEntity entity = selectOneMybatis("getHttpDataSetEntityById", params);
|
||||
|
||||
if (entity != null)
|
||||
entity.setHttpClient(this.httpClient);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDataPermissionParameters(Map<String, Object> params, User user)
|
||||
{
|
||||
|
|
|
@ -506,3 +506,76 @@ ALTER TABLE DATAGEAR_DATA_SET_JSON_FILE ADD FOREIGN KEY (DS_ID) REFERENCES DATAG
|
|||
--version[1.11.1], DO NOT EDIT THIS LINE!
|
||||
-----------------------------------------
|
||||
|
||||
|
||||
-----------------------------------------
|
||||
--version[1.12.0], DO NOT EDIT THIS LINE!
|
||||
-----------------------------------------
|
||||
|
||||
--2020-08-28
|
||||
--JSON文件数据集添加编码字段
|
||||
ALTER TABLE DATAGEAR_DATA_SET_JSON_FILE ADD COLUMN DS_FILE_ENCODING VARCHAR(50);
|
||||
|
||||
--2020-08-28
|
||||
--Excel文件数据集
|
||||
CREATE TABLE DATAGEAR_DATA_SET_EXCEL
|
||||
(
|
||||
DS_ID VARCHAR(50) NOT NULL,
|
||||
DS_FILE_NAME VARCHAR(100) NOT NULL,
|
||||
DS_DISPLAY_NAME VARCHAR(100) NOT NULL,
|
||||
DS_SHEET_INDEX INTEGER,
|
||||
DS_NAME_ROW INTEGER,
|
||||
DS_DATA_ROW_EXP VARCHAR(100),
|
||||
DS_DATA_COLUMN_EXP VARCHAR(100),
|
||||
DS_FORCE_XLS VARCHAR(10),
|
||||
PRIMARY KEY (DS_ID)
|
||||
);
|
||||
|
||||
ALTER TABLE DATAGEAR_DATA_SET_EXCEL ADD FOREIGN KEY (DS_ID) REFERENCES DATAGEAR_DATA_SET (DS_ID) ON DELETE CASCADE;
|
||||
|
||||
--2020-08-31
|
||||
--CSV值数据集
|
||||
CREATE TABLE DATAGEAR_DATA_SET_CSV_VALUE
|
||||
(
|
||||
DS_ID VARCHAR(50) NOT NULL,
|
||||
DS_VALUE VARCHAR(10000) NOT NULL,
|
||||
DS_NAME_ROW INTEGER,
|
||||
PRIMARY KEY (DS_ID)
|
||||
);
|
||||
|
||||
ALTER TABLE DATAGEAR_DATA_SET_CSV_VALUE ADD FOREIGN KEY (DS_ID) REFERENCES DATAGEAR_DATA_SET (DS_ID) ON DELETE CASCADE;
|
||||
|
||||
--2020-08-31
|
||||
--CSV文件数据集
|
||||
CREATE TABLE DATAGEAR_DATA_SET_CSV_FILE
|
||||
(
|
||||
DS_ID VARCHAR(50) NOT NULL,
|
||||
DS_FILE_NAME VARCHAR(100) NOT NULL,
|
||||
DS_DISPLAY_NAME VARCHAR(100) NOT NULL,
|
||||
DS_FILE_ENCODING VARCHAR(50),
|
||||
DS_NAME_ROW INTEGER,
|
||||
PRIMARY KEY (DS_ID)
|
||||
);
|
||||
|
||||
ALTER TABLE DATAGEAR_DATA_SET_CSV_FILE ADD FOREIGN KEY (DS_ID) REFERENCES DATAGEAR_DATA_SET (DS_ID) ON DELETE CASCADE;
|
||||
|
||||
--2020-09-03
|
||||
--JSON文件数据集添加数据JSON路径字段
|
||||
ALTER TABLE DATAGEAR_DATA_SET_JSON_FILE ADD COLUMN DS_DATA_JSON_PATH VARCHAR(200);
|
||||
|
||||
--2020-09-05
|
||||
--HTTP数据集
|
||||
CREATE TABLE DATAGEAR_DATA_SET_HTTP
|
||||
(
|
||||
DS_ID VARCHAR(50) NOT NULL,
|
||||
DS_URI VARCHAR(1000) NOT NULL,
|
||||
DS_HEADER_CONTENT VARCHAR(5000),
|
||||
DS_RQT_METHOD VARCHAR(50),
|
||||
DS_RQT_CONTENT_TYPE VARCHAR(100),
|
||||
DS_RQT_CONTENT_CHARSET VARCHAR(100),
|
||||
DS_RQT_CONTENT varchar(10000),
|
||||
DS_RPS_CONTENT_TYPE VARCHAR(100),
|
||||
DS_RPS_DATA_JSON_PATH VARCHAR(200),
|
||||
PRIMARY KEY (DS_ID)
|
||||
);
|
||||
|
||||
ALTER TABLE DATAGEAR_DATA_SET_HTTP ADD FOREIGN KEY (DS_ID) REFERENCES DATAGEAR_DATA_SET (DS_ID) ON DELETE CASCADE;
|
||||
|
|
|
@ -39,11 +39,59 @@
|
|||
<insert id="insertJsonFileDataSetEntity">
|
||||
INSERT INTO DATAGEAR_DATA_SET_JSON_FILE
|
||||
(
|
||||
DS_ID, DS_FILE_NAME, DS_DISPLAY_NAME
|
||||
DS_ID, DS_FILE_NAME, DS_FILE_ENCODING, DS_DISPLAY_NAME, DS_DATA_JSON_PATH
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{entity.id}, #{entity.fileName}, #{entity.displayName}
|
||||
#{entity.id}, #{entity.fileName}, #{entity.encoding}, #{entity.displayName}, #{entity.dataJsonPath}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertExcelDataSetEntity">
|
||||
INSERT INTO DATAGEAR_DATA_SET_EXCEL
|
||||
(
|
||||
DS_ID, DS_FILE_NAME, DS_DISPLAY_NAME, DS_SHEET_INDEX, DS_NAME_ROW,
|
||||
DS_DATA_ROW_EXP, DS_DATA_COLUMN_EXP, DS_FORCE_XLS
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{entity.id}, #{entity.fileName}, #{entity.displayName}, #{entity.sheetIndex}, #{entity.nameRow},
|
||||
#{entity.dataRowExp}, #{entity.dataColumnExp}, #{entity.forceXls}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertCsvValueDataSetEntity">
|
||||
INSERT INTO DATAGEAR_DATA_SET_CSV_VALUE
|
||||
(
|
||||
DS_ID, DS_VALUE, DS_NAME_ROW
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{entity.id}, #{entity.value}, #{entity.nameRow}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertCsvFileDataSetEntity">
|
||||
INSERT INTO DATAGEAR_DATA_SET_CSV_FILE
|
||||
(
|
||||
DS_ID, DS_FILE_NAME, DS_FILE_ENCODING, DS_DISPLAY_NAME, DS_NAME_ROW
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{entity.id}, #{entity.fileName}, #{entity.encoding}, #{entity.displayName}, #{entity.nameRow}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertHttpDataSetEntity">
|
||||
INSERT INTO DATAGEAR_DATA_SET_HTTP
|
||||
(
|
||||
DS_ID, DS_URI, DS_HEADER_CONTENT, DS_RQT_METHOD, DS_RQT_CONTENT_TYPE,
|
||||
DS_RQT_CONTENT_CHARSET, DS_RQT_CONTENT, DS_RPS_CONTENT_TYPE, DS_RPS_DATA_JSON_PATH
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{entity.id}, #{entity.uri}, #{entity.headerContent}, #{entity.requestMethod}, #{entity.requestContentType},
|
||||
#{entity.requestContentCharset}, #{entity.requestContent}, #{entity.responseContentType}, #{entity.responseDataJsonPath}
|
||||
)
|
||||
</insert>
|
||||
|
||||
|
@ -103,7 +151,54 @@
|
|||
<update id="updateJsonFileDataSetEntity">
|
||||
UPDATE DATAGEAR_DATA_SET_JSON_FILE SET
|
||||
DS_FILE_NAME = #{entity.fileName},
|
||||
DS_DISPLAY_NAME = #{entity.displayName}
|
||||
DS_FILE_ENCODING = #{entity.encoding},
|
||||
DS_DISPLAY_NAME = #{entity.displayName},
|
||||
DS_DATA_JSON_PATH = #{entity.dataJsonPath}
|
||||
WHERE
|
||||
DS_ID = #{entity.id}
|
||||
</update>
|
||||
|
||||
<update id="updateExcelDataSetEntity">
|
||||
UPDATE DATAGEAR_DATA_SET_EXCEL SET
|
||||
DS_FILE_NAME = #{entity.fileName},
|
||||
DS_DISPLAY_NAME = #{entity.displayName},
|
||||
DS_SHEET_INDEX = #{entity.sheetIndex},
|
||||
DS_NAME_ROW = #{entity.nameRow},
|
||||
DS_DATA_ROW_EXP = #{entity.dataRowExp},
|
||||
DS_DATA_COLUMN_EXP = #{entity.dataColumnExp},
|
||||
DS_FORCE_XLS = #{entity.forceXls}
|
||||
WHERE
|
||||
DS_ID = #{entity.id}
|
||||
</update>
|
||||
|
||||
<update id="updateCsvValueDataSetEntity">
|
||||
UPDATE DATAGEAR_DATA_SET_CSV_VALUE SET
|
||||
DS_VALUE = #{entity.value},
|
||||
DS_NAME_ROW = #{entity.nameRow}
|
||||
WHERE
|
||||
DS_ID = #{entity.id}
|
||||
</update>
|
||||
|
||||
<update id="updateCsvFileDataSetEntity">
|
||||
UPDATE DATAGEAR_DATA_SET_CSV_FILE SET
|
||||
DS_FILE_NAME = #{entity.fileName},
|
||||
DS_FILE_ENCODING = #{entity.encoding},
|
||||
DS_DISPLAY_NAME = #{entity.displayName},
|
||||
DS_NAME_ROW = #{entity.nameRow}
|
||||
WHERE
|
||||
DS_ID = #{entity.id}
|
||||
</update>
|
||||
|
||||
<update id="updateHttpDataSetEntity">
|
||||
UPDATE DATAGEAR_DATA_SET_HTTP SET
|
||||
DS_URI = #{entity.uri},
|
||||
DS_HEADER_CONTENT = #{entity.headerContent},
|
||||
DS_RQT_METHOD = #{entity.requestMethod},
|
||||
DS_RQT_CONTENT_TYPE = #{entity.requestContentType},
|
||||
DS_RQT_CONTENT_CHARSET = #{entity.requestContentCharset},
|
||||
DS_RQT_CONTENT = #{entity.requestContent},
|
||||
DS_RPS_CONTENT_TYPE = #{entity.responseContentType},
|
||||
DS_RPS_DATA_JSON_PATH = #{entity.responseDataJsonPath}
|
||||
WHERE
|
||||
DS_ID = #{entity.id}
|
||||
</update>
|
||||
|
@ -169,7 +264,9 @@
|
|||
SELECT
|
||||
T1.*,
|
||||
T2.DS_FILE_NAME AS ${_iq_}fileName${_iq_},
|
||||
T2.DS_DISPLAY_NAME AS ${_iq_}displayName${_iq_}
|
||||
T2.DS_FILE_ENCODING AS ${_iq_}encoding${_iq_},
|
||||
T2.DS_DISPLAY_NAME AS ${_iq_}displayName${_iq_},
|
||||
T2.DS_DATA_JSON_PATH AS ${_iq_}dataJsonPath${_iq_}
|
||||
FROM
|
||||
(SELECT * FROM (<include refid="queryView" />) T0 WHERE T0.${_iq_}id${_iq_} = #{id}) T1
|
||||
INNER JOIN
|
||||
|
@ -178,6 +275,72 @@
|
|||
T1.${_iq_}id${_iq_} = T2.DS_ID
|
||||
</select>
|
||||
|
||||
<select id="getExcelDataSetEntityById" resultType="org.datagear.management.domain.ExcelDataSetEntity">
|
||||
SELECT
|
||||
T1.*,
|
||||
T2.DS_FILE_NAME AS ${_iq_}fileName${_iq_},
|
||||
T2.DS_DISPLAY_NAME AS ${_iq_}displayName${_iq_},
|
||||
|
||||
T2.DS_SHEET_INDEX AS ${_iq_}sheetIndex${_iq_},
|
||||
T2.DS_NAME_ROW AS ${_iq_}nameRow${_iq_},
|
||||
T2.DS_DATA_ROW_EXP AS ${_iq_}dataRowExp${_iq_},
|
||||
T2.DS_DATA_COLUMN_EXP AS ${_iq_}dataColumnExp${_iq_},
|
||||
T2.DS_FORCE_XLS AS ${_iq_}forceXls${_iq_}
|
||||
FROM
|
||||
(SELECT * FROM (<include refid="queryView" />) T0 WHERE T0.${_iq_}id${_iq_} = #{id}) T1
|
||||
INNER JOIN
|
||||
DATAGEAR_DATA_SET_EXCEL T2
|
||||
ON
|
||||
T1.${_iq_}id${_iq_} = T2.DS_ID
|
||||
</select>
|
||||
|
||||
<select id="getCsvValueDataSetEntityById" resultType="org.datagear.management.domain.CsvValueDataSetEntity">
|
||||
SELECT
|
||||
T1.*,
|
||||
T2.DS_VALUE AS ${_iq_}value${_iq_},
|
||||
T2.DS_NAME_ROW AS ${_iq_}nameRow${_iq_}
|
||||
FROM
|
||||
(SELECT * FROM (<include refid="queryView" />) T0 WHERE T0.${_iq_}id${_iq_} = #{id}) T1
|
||||
INNER JOIN
|
||||
DATAGEAR_DATA_SET_CSV_VALUE T2
|
||||
ON
|
||||
T1.${_iq_}id${_iq_} = T2.DS_ID
|
||||
</select>
|
||||
|
||||
<select id="getCsvFileDataSetEntityById" resultType="org.datagear.management.domain.CsvFileDataSetEntity">
|
||||
SELECT
|
||||
T1.*,
|
||||
T2.DS_FILE_NAME AS ${_iq_}fileName${_iq_},
|
||||
T2.DS_FILE_ENCODING AS ${_iq_}encoding${_iq_},
|
||||
T2.DS_DISPLAY_NAME AS ${_iq_}displayName${_iq_},
|
||||
T2.DS_NAME_ROW AS ${_iq_}nameRow${_iq_}
|
||||
FROM
|
||||
(SELECT * FROM (<include refid="queryView" />) T0 WHERE T0.${_iq_}id${_iq_} = #{id}) T1
|
||||
INNER JOIN
|
||||
DATAGEAR_DATA_SET_CSV_FILE T2
|
||||
ON
|
||||
T1.${_iq_}id${_iq_} = T2.DS_ID
|
||||
</select>
|
||||
|
||||
<select id="getHttpDataSetEntityById" resultType="org.datagear.management.domain.HttpDataSetEntity">
|
||||
SELECT
|
||||
T1.*,
|
||||
T2.DS_URI AS ${_iq_}uri${_iq_},
|
||||
T2.DS_HEADER_CONTENT AS ${_iq_}headerContent${_iq_},
|
||||
T2.DS_RQT_METHOD AS ${_iq_}requestMethod${_iq_},
|
||||
T2.DS_RQT_CONTENT_TYPE AS ${_iq_}requestContentType${_iq_},
|
||||
T2.DS_RQT_CONTENT_CHARSET AS ${_iq_}requestContentCharset${_iq_},
|
||||
T2.DS_RQT_CONTENT AS ${_iq_}requestContent${_iq_},
|
||||
T2.DS_RPS_CONTENT_TYPE AS ${_iq_}responseContentType${_iq_},
|
||||
T2.DS_RPS_DATA_JSON_PATH AS ${_iq_}responseDataJsonPath${_iq_}
|
||||
FROM
|
||||
(SELECT * FROM (<include refid="queryView" />) T0 WHERE T0.${_iq_}id${_iq_} = #{id}) T1
|
||||
INNER JOIN
|
||||
DATAGEAR_DATA_SET_HTTP T2
|
||||
ON
|
||||
T1.${_iq_}id${_iq_} = T2.DS_ID
|
||||
</select>
|
||||
|
||||
<select id="getPropertyPOs" resultType="org.datagear.management.service.impl.DataSetEntityServiceImpl$DataSetPropertyPO">
|
||||
SELECT
|
||||
PROP_DS_ID AS ${_iq_}dataSetId${_iq_},
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<version>1.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-meta</artifactId>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<version>1.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-persistence</artifactId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<version>1.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-util</artifactId>
|
||||
|
|
|
@ -21,7 +21,7 @@ public final class Global
|
|||
}
|
||||
|
||||
/** 当前版本号 */
|
||||
public static final String VERSION = "1.11.1";
|
||||
public static final String VERSION = "1.12.0";
|
||||
|
||||
/** 中文产品名称 */
|
||||
public static final String PRODUCT_NAME_ZH = "数据齿轮";
|
||||
|
|
|
@ -37,6 +37,10 @@ import java.util.zip.ZipOutputStream;
|
|||
*/
|
||||
public class IOUtil
|
||||
{
|
||||
public static final String CHARSET_UTF_8 = "UTF-8";
|
||||
|
||||
public static final String CHARSET_ISO_8859_1 = "ISO-8859-1";
|
||||
|
||||
private IOUtil()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -337,24 +341,41 @@ public class IOUtil
|
|||
*/
|
||||
public static BufferedReader getReader(File file) throws FileNotFoundException, UnsupportedEncodingException
|
||||
{
|
||||
return getReader(getInputStream(file), null);
|
||||
return getReader(getInputStream(file), (String) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输入流。
|
||||
*
|
||||
* @param in
|
||||
* @param encoding
|
||||
* @param charset
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public static BufferedReader getReader(InputStream in, String encoding) throws UnsupportedEncodingException
|
||||
public static BufferedReader getReader(InputStream in, String charset) throws UnsupportedEncodingException
|
||||
{
|
||||
if (StringUtil.isEmpty(encoding))
|
||||
if (StringUtil.isEmpty(charset))
|
||||
return new BufferedReader(new InputStreamReader(in));
|
||||
else
|
||||
return new BufferedReader(new InputStreamReader(in, encoding));
|
||||
return new BufferedReader(new InputStreamReader(in, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输入流。
|
||||
*
|
||||
* @param in
|
||||
* @param charset
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public static BufferedReader getReader(InputStream in, Charset charset) throws UnsupportedEncodingException
|
||||
{
|
||||
if (charset == null)
|
||||
return new BufferedReader(new InputStreamReader(in));
|
||||
else
|
||||
return new BufferedReader(new InputStreamReader(in, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -950,27 +950,16 @@ public class JdbcSupport
|
|||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
@JDBCCompatiblity("某些驱动程序可能不支持ResultSet.getObject方法,所以这里没有使用")
|
||||
public Object getColumnValue(Connection cn, ResultSet rs, String columnName, int sqlType) throws SQLException
|
||||
{
|
||||
Object value = null;
|
||||
|
||||
switch (sqlType)
|
||||
{
|
||||
case Types.TINYINT:
|
||||
case Types.ARRAY:
|
||||
{
|
||||
value = rs.getByte(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.SMALLINT:
|
||||
{
|
||||
value = rs.getShort(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.INTEGER:
|
||||
{
|
||||
value = rs.getInt(columnName);
|
||||
value = rs.getArray(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -980,23 +969,9 @@ public class JdbcSupport
|
|||
break;
|
||||
}
|
||||
|
||||
case Types.REAL:
|
||||
case Types.BINARY:
|
||||
{
|
||||
value = rs.getFloat(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.FLOAT:
|
||||
case Types.DOUBLE:
|
||||
{
|
||||
value = rs.getDouble(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.DECIMAL:
|
||||
case Types.NUMERIC:
|
||||
{
|
||||
value = rs.getBigDecimal(columnName);
|
||||
value = rs.getBytes(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1006,6 +981,12 @@ public class JdbcSupport
|
|||
break;
|
||||
}
|
||||
|
||||
case Types.BLOB:
|
||||
{
|
||||
value = rs.getBlob(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.BOOLEAN:
|
||||
{
|
||||
value = rs.getBoolean(columnName);
|
||||
|
@ -1013,22 +994,68 @@ public class JdbcSupport
|
|||
}
|
||||
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
{
|
||||
value = rs.getString(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.CLOB:
|
||||
{
|
||||
value = rs.getCharacterStream(columnName);
|
||||
value = rs.getClob(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.BINARY:
|
||||
case Types.VARBINARY:
|
||||
case Types.DATALINK:
|
||||
{
|
||||
value = rs.getBytes(columnName);
|
||||
value = rs.getObject(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.DATE:
|
||||
{
|
||||
value = rs.getDate(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.DECIMAL:
|
||||
{
|
||||
value = rs.getBigDecimal(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.DISTINCT:
|
||||
{
|
||||
value = rs.getObject(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.DOUBLE:
|
||||
{
|
||||
value = rs.getDouble(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.FLOAT:
|
||||
{
|
||||
value = rs.getFloat(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.INTEGER:
|
||||
{
|
||||
value = rs.getInt(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.JAVA_OBJECT:
|
||||
{
|
||||
value = rs.getObject(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.LONGNVARCHAR:
|
||||
{
|
||||
value = rs.getNCharacterStream(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1038,9 +1065,81 @@ public class JdbcSupport
|
|||
break;
|
||||
}
|
||||
|
||||
case Types.DATE:
|
||||
case Types.LONGVARCHAR:
|
||||
{
|
||||
value = rs.getDate(columnName);
|
||||
value = rs.getCharacterStream(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.NCHAR:
|
||||
{
|
||||
value = rs.getNString(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.NCLOB:
|
||||
{
|
||||
value = rs.getNClob(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.NUMERIC:
|
||||
{
|
||||
value = rs.getBigDecimal(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.NVARCHAR:
|
||||
{
|
||||
value = rs.getNString(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.OTHER:
|
||||
{
|
||||
value = rs.getObject(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.REAL:
|
||||
{
|
||||
value = rs.getFloat(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.REF:
|
||||
{
|
||||
value = rs.getRef(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.REF_CURSOR:
|
||||
{
|
||||
value = rs.getObject(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.ROWID:
|
||||
{
|
||||
value = rs.getRowId(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.SMALLINT:
|
||||
{
|
||||
value = rs.getShort(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.SQLXML:
|
||||
{
|
||||
value = rs.getSQLXML(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.STRUCT:
|
||||
{
|
||||
value = rs.getObject(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1058,46 +1157,29 @@ public class JdbcSupport
|
|||
break;
|
||||
}
|
||||
|
||||
case Types.CLOB:
|
||||
case Types.TINYINT:
|
||||
{
|
||||
value = rs.getClob(columnName);
|
||||
value = rs.getByte(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.BLOB:
|
||||
case Types.VARBINARY:
|
||||
{
|
||||
value = rs.getBlob(columnName);
|
||||
value = rs.getBytes(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.NCHAR:
|
||||
case Types.NVARCHAR:
|
||||
case Types.VARCHAR:
|
||||
{
|
||||
value = rs.getNString(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.LONGNVARCHAR:
|
||||
{
|
||||
value = rs.getNCharacterStream(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.NCLOB:
|
||||
{
|
||||
value = rs.getNClob(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
case Types.SQLXML:
|
||||
{
|
||||
value = rs.getSQLXML(columnName);
|
||||
value = rs.getString(columnName);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
value = getColumnValueExt(cn, rs, columnName, sqlType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rs.wasNull())
|
||||
|
@ -1171,6 +1253,25 @@ public class JdbcSupport
|
|||
return columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列名数组。
|
||||
*
|
||||
* @param metaData
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
public String[] getColumnNames(ResultSetMetaData metaData) throws SQLException
|
||||
{
|
||||
int size = metaData.getColumnCount();
|
||||
|
||||
String[] names = new String[size];
|
||||
|
||||
for (int i = 0; i < names.length; i++)
|
||||
names[i] = getColumnName(metaData, i + 1);
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列类型。
|
||||
*
|
||||
|
@ -1188,6 +1289,25 @@ public class JdbcSupport
|
|||
return new SqlType(type, typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列类型数组。
|
||||
*
|
||||
* @param metaData
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
public SqlType[] getColumnSqlTypes(ResultSetMetaData metaData) throws SQLException
|
||||
{
|
||||
int size = metaData.getColumnCount();
|
||||
|
||||
SqlType[] sqlTypes = new SqlType[size];
|
||||
|
||||
for (int i = 0; i < sqlTypes.length; i++)
|
||||
sqlTypes[i] = getColumnSqlType(metaData, i + 1);
|
||||
|
||||
return sqlTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL插入操作的自动生成结果。
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.datagear</groupId>
|
||||
<artifactId>datagear</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<version>1.12.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>datagear-web</artifactId>
|
||||
|
|
|
@ -17,6 +17,8 @@ import java.util.Map;
|
|||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.cometd.bayeux.server.BayeuxServer;
|
||||
import org.cometd.bayeux.server.BayeuxServer.Extension;
|
||||
import org.cometd.server.ext.AcknowledgedMessagesExtension;
|
||||
|
@ -72,6 +74,7 @@ import org.datagear.persistence.PersistenceManager;
|
|||
import org.datagear.persistence.support.DefaultDialectSource;
|
||||
import org.datagear.persistence.support.DefaultPersistenceManager;
|
||||
import org.datagear.persistence.support.SqlSelectManager;
|
||||
import org.datagear.util.IOUtil;
|
||||
import org.datagear.web.cometd.CustomJacksonJSONContextServer;
|
||||
import org.datagear.web.cometd.dataexchange.DataExchangeCometdService;
|
||||
import org.datagear.web.convert.CustomFormattingConversionServiceFactoryBean;
|
||||
|
@ -193,6 +196,7 @@ public class CoreConfiguration implements InitializingBean
|
|||
{
|
||||
ResourceBundleMessageSource bean = new ResourceBundleMessageSource();
|
||||
bean.setBasename("org.datagear.web.locales.datagear");
|
||||
bean.setDefaultEncoding(IOUtil.CHARSET_UTF_8);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
@ -233,6 +237,12 @@ public class CoreConfiguration implements InitializingBean
|
|||
return createDirectory(environment.getProperty("directory.dataSet"), true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CloseableHttpClient httpClient()
|
||||
{
|
||||
return HttpClients.createDefault();
|
||||
}
|
||||
|
||||
protected File createDirectory(String directoryName, boolean createIfInexistence) throws IOException
|
||||
{
|
||||
DirectoryFactory bean = new DirectoryFactory();
|
||||
|
@ -390,8 +400,8 @@ public class CoreConfiguration implements InitializingBean
|
|||
public DataSetEntityService dataSetEntityService() throws Exception
|
||||
{
|
||||
DataSetEntityServiceImpl bean = new DataSetEntityServiceImpl(this.sqlSessionFactory().getObject(),
|
||||
this.connectionSource(), this.schemaService(), this.authorizationService(),
|
||||
this.dataSetRootDirectory());
|
||||
this.connectionSource(), this.schemaService(), this.authorizationService(), this.dataSetRootDirectory(),
|
||||
this.httpClient());
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,18 +11,24 @@ import java.io.Serializable;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.datagear.analysis.Category;
|
||||
import org.datagear.analysis.Chart;
|
||||
import org.datagear.analysis.ChartDataSet;
|
||||
import org.datagear.analysis.ChartDefinition;
|
||||
import org.datagear.analysis.DashboardTheme;
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.DataSign;
|
||||
import org.datagear.analysis.Icon;
|
||||
import org.datagear.analysis.RenderContext;
|
||||
import org.datagear.analysis.RenderException;
|
||||
import org.datagear.analysis.support.AbstractChartPlugin;
|
||||
import org.datagear.analysis.support.AbstractDataSet;
|
||||
import org.datagear.analysis.support.CategorizationResolver;
|
||||
import org.datagear.analysis.support.CategorizationResolver.Categorization;
|
||||
import org.datagear.analysis.support.html.DirectoryHtmlChartPluginManager;
|
||||
|
@ -32,6 +38,8 @@ import org.datagear.web.util.KeywordMatcher;
|
|||
import org.datagear.web.util.WebUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* 抽象插件相关的控制器。
|
||||
*
|
||||
|
@ -214,6 +222,19 @@ public class AbstractChartPluginAwareController extends AbstractDataAnalysisCont
|
|||
return "/analysis/chartPlugin/icon/" + plugin.getId();
|
||||
}
|
||||
|
||||
protected ChartDataSetViewObj[] toChartDataSetViewObjs(ChartDataSet[] chartDataSets)
|
||||
{
|
||||
if (chartDataSets == null)
|
||||
return null;
|
||||
|
||||
ChartDataSetViewObj[] viewObjs = new ChartDataSetViewObj[chartDataSets.length];
|
||||
|
||||
for (int i = 0; i < chartDataSets.length; i++)
|
||||
viewObjs[i] = new ChartDataSetViewObj(chartDataSets[i]);
|
||||
|
||||
return viewObjs;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@linkplain HtmlChartPlugin}视图对象。
|
||||
*
|
||||
|
@ -264,4 +285,70 @@ public class AbstractChartPluginAwareController extends AbstractDataAnalysisCont
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@linkplain DataSet}视图对象。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public static class DataSetViewObj extends AbstractDataSet
|
||||
{
|
||||
public DataSetViewObj()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public DataSetViewObj(DataSet dataSet)
|
||||
{
|
||||
super();
|
||||
setId(dataSet.getId());
|
||||
setName(dataSet.getName());
|
||||
setProperties(dataSet.getProperties());
|
||||
setParams(dataSet.getParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSetResult getResult(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@linkplain ChartDataSet}视图对象。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public static class ChartDataSetViewObj extends ChartDataSet
|
||||
{
|
||||
public ChartDataSetViewObj()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ChartDataSetViewObj(ChartDataSet chartDataSet)
|
||||
{
|
||||
super();
|
||||
setDataSet(new DataSetViewObj(chartDataSet.getDataSet()));
|
||||
setPropertySigns(chartDataSet.getPropertySigns());
|
||||
setAlias(chartDataSet.getAlias());
|
||||
setParamValues(chartDataSet.getParamValues());
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public boolean isResultReady()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public DataSetResult getResult()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,8 +113,8 @@ public abstract class AbstractController
|
|||
* 检查并补充{@linkplain DataFilterPagingQuery#getDataFilter()}。
|
||||
*
|
||||
* @param request
|
||||
* @param pagingQuery
|
||||
* @return
|
||||
* @param pagingQuery 允许为{@code null}
|
||||
* @return 不会为{@code null}
|
||||
*/
|
||||
protected DataFilterPagingQuery inflateDataFilterPagingQuery(HttpServletRequest request,
|
||||
DataFilterPagingQuery pagingQuery)
|
||||
|
@ -126,14 +126,20 @@ public abstract class AbstractController
|
|||
* 检查并补充{@linkplain DataFilterPagingQuery#getDataFilter()}。
|
||||
*
|
||||
* @param request
|
||||
* @param pagingQuery
|
||||
* @param pagingQuery 允许为{@code null}
|
||||
* @param cookiePaginationSize
|
||||
* @return
|
||||
* @return 不会为{@code null}
|
||||
*/
|
||||
protected DataFilterPagingQuery inflateDataFilterPagingQuery(HttpServletRequest request,
|
||||
DataFilterPagingQuery pagingQuery, String cookiePaginationSize)
|
||||
{
|
||||
inflatePagingQuery(request, pagingQuery, cookiePaginationSize);
|
||||
PagingQuery pq = inflatePagingQuery(request, pagingQuery, cookiePaginationSize);
|
||||
|
||||
if (pagingQuery == null)
|
||||
{
|
||||
pagingQuery = new DataFilterPagingQuery(pq.getPage(), pq.getPageSize(), pq.getKeyword(), pq.getCondition());
|
||||
pagingQuery.setNotLike(pq.isNotLike());
|
||||
}
|
||||
|
||||
String value = pagingQuery.getDataFilter();
|
||||
|
||||
|
@ -187,8 +193,8 @@ public abstract class AbstractController
|
|||
* 检查并补充{@linkplain PagingQuery}。
|
||||
*
|
||||
* @param request
|
||||
* @param pagingQuery
|
||||
* @return
|
||||
* @param pagingQuery 允许为{@code null}
|
||||
* @return 不会为{@code null}
|
||||
*/
|
||||
protected PagingQuery inflatePagingQuery(HttpServletRequest request, PagingQuery pagingQuery)
|
||||
{
|
||||
|
@ -199,18 +205,15 @@ public abstract class AbstractController
|
|||
* 检查并补充{@linkplain PagingQuery}。
|
||||
*
|
||||
* @param request
|
||||
* @param pagingQuery
|
||||
* @param cookiePaginationSize
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
* @param pagingQuery 允许为{@code null}
|
||||
* @param cookiePaginationSize 允许为{@code null}
|
||||
* @return 不会为{@code null}
|
||||
*/
|
||||
protected PagingQuery inflatePagingQuery(HttpServletRequest request, PagingQuery pagingQuery,
|
||||
String cookiePaginationSize)
|
||||
{
|
||||
if (pagingQuery != null)
|
||||
return pagingQuery;
|
||||
|
||||
pagingQuery = new PagingQuery();
|
||||
if (pagingQuery == null)
|
||||
pagingQuery = new PagingQuery();
|
||||
|
||||
if (!isEmpty(cookiePaginationSize))
|
||||
{
|
||||
|
|
|
@ -275,13 +275,30 @@ public abstract class AbstractDataAnalysisController extends AbstractController
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void addHeartBeatValue(WebContext webContext)
|
||||
protected void addHeartBeatValue(HttpServletRequest request, WebContext webContext)
|
||||
{
|
||||
String heartbeatURL = webContext.getContextPath() + "/analysis/dashboard/heartbeat";
|
||||
heartbeatURL = addJsessionidParam(heartbeatURL, request.getSession().getId());
|
||||
|
||||
((Map<String, Object>) webContext.getExtraValues()).put(DASHBOARD_HEARTBEAT_URL_NAME, heartbeatURL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指定URL添加会话ID参数。
|
||||
* <p>
|
||||
* 图表、看板展示页可能会以<iframe>的方式嵌入外部网页中,当在跨域场景时,某些浏览器会禁用<iframe>内的cookie,导致会话无法保持,
|
||||
* 从而引起图表、看板内的ajax请求失效,此方法可以解决上述问题。
|
||||
* </p>
|
||||
*
|
||||
* @param url
|
||||
* @param sessionId
|
||||
* @return
|
||||
*/
|
||||
protected String addJsessionidParam(String url, String sessionId)
|
||||
{
|
||||
return WebUtils.addJsessionidParam(url, sessionId);
|
||||
}
|
||||
|
||||
protected static class SessionHtmlTplDashboardManager implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Map;
|
|||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.datagear.analysis.ChartPluginManager;
|
||||
import org.datagear.analysis.DataSetParam;
|
||||
|
@ -153,7 +154,7 @@ public class ChartController extends AbstractChartPluginAwareController implemen
|
|||
|
||||
model.addAttribute("chart", chart);
|
||||
model.addAttribute("chartPluginVO", toWriteJsonTemplateModel(chartPluginVO));
|
||||
model.addAttribute("chartDataSets", toWriteJsonTemplateModel(chart.getChartDataSets()));
|
||||
model.addAttribute("chartDataSets", toWriteJsonTemplateModel(toChartDataSetViewObjs(chart.getChartDataSets())));
|
||||
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "chart.editChart");
|
||||
model.addAttribute(KEY_FORM_ACTION, "save");
|
||||
|
||||
|
@ -208,7 +209,7 @@ public class ChartController extends AbstractChartPluginAwareController implemen
|
|||
|
||||
model.addAttribute("chart", chart);
|
||||
model.addAttribute("chartPluginVO", toWriteJsonTemplateModel(chartPluginVO));
|
||||
model.addAttribute("chartDataSets", toWriteJsonTemplateModel(chart.getChartDataSets()));
|
||||
model.addAttribute("chartDataSets", toWriteJsonTemplateModel(toChartDataSetViewObjs(chart.getChartDataSets())));
|
||||
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "chart.viewChart");
|
||||
model.addAttribute(KEY_READONLY, true);
|
||||
|
||||
|
@ -397,12 +398,15 @@ public class ChartController extends AbstractChartPluginAwareController implemen
|
|||
|
||||
protected WebContext createWebContext(HttpServletRequest request)
|
||||
{
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
String contextPath = getWebContextPath(request).get(request);
|
||||
WebContext webContext = new WebContext(contextPath, contextPath + "/analysis/chart/showData",
|
||||
contextPath + "/analysis/dashboard/loadChart");
|
||||
WebContext webContext = new WebContext(contextPath,
|
||||
addJsessionidParam(contextPath + "/analysis/chart/showData", session.getId()),
|
||||
addJsessionidParam(contextPath + "/analysis/dashboard/loadChart", session.getId()));
|
||||
|
||||
webContext.setExtraValues(new HashMap<String, Object>());
|
||||
addHeartBeatValue(webContext);
|
||||
addHeartBeatValue(request, webContext);
|
||||
|
||||
return webContext;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,10 @@ import java.sql.SQLException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.support.DataSetSourceParseException;
|
||||
import org.datagear.analysis.support.HeaderContentNotNameValueObjArrayJsonException;
|
||||
import org.datagear.analysis.support.RequestContentNotNameValueObjArrayJsonException;
|
||||
import org.datagear.analysis.support.SqlDataSetConnectionException;
|
||||
import org.datagear.analysis.support.SqlDataSetSqlExecutionException;
|
||||
import org.datagear.analysis.support.SqlDataSetUnsupportedSqlTypeException;
|
||||
|
@ -449,8 +452,8 @@ public class ControllerAdvice extends AbstractController
|
|||
|
||||
@ExceptionHandler(SqlDataSetConnectionException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public String handleAnalysisSqlDataSetConnectionException(HttpServletRequest request,
|
||||
HttpServletResponse response, SqlDataSetConnectionException exception)
|
||||
public String handleAnalysisSqlDataSetConnectionException(HttpServletRequest request, HttpServletResponse response,
|
||||
SqlDataSetConnectionException exception)
|
||||
{
|
||||
setOperationMessageForThrowable(request, buildMessageCode(SqlDataSetConnectionException.class), exception,
|
||||
false, exception.getMessage());
|
||||
|
@ -458,6 +461,39 @@ public class ControllerAdvice extends AbstractController
|
|||
return getErrorView(request, response);
|
||||
}
|
||||
|
||||
@ExceptionHandler(RequestContentNotNameValueObjArrayJsonException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public String handleAnalysisRequestContentNotNameValueObjArrayJsonException(HttpServletRequest request,
|
||||
HttpServletResponse response, RequestContentNotNameValueObjArrayJsonException exception)
|
||||
{
|
||||
setOperationMessageForThrowable(request,
|
||||
buildMessageCode(RequestContentNotNameValueObjArrayJsonException.class), exception, false);
|
||||
|
||||
return getErrorView(request, response);
|
||||
}
|
||||
|
||||
@ExceptionHandler(HeaderContentNotNameValueObjArrayJsonException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public String handleAnalysisHeaderContentNotNameValueObjArrayJsonException(HttpServletRequest request,
|
||||
HttpServletResponse response, HeaderContentNotNameValueObjArrayJsonException exception)
|
||||
{
|
||||
setOperationMessageForThrowable(request, buildMessageCode(HeaderContentNotNameValueObjArrayJsonException.class),
|
||||
exception, false);
|
||||
|
||||
return getErrorView(request, response);
|
||||
}
|
||||
|
||||
@ExceptionHandler(DataSetException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public String handleAnalysisDataSetException(HttpServletRequest request, HttpServletResponse response,
|
||||
DataSetException exception)
|
||||
{
|
||||
setOperationMessageForThrowable(request, buildMessageCode(DataSetException.class), exception, true,
|
||||
exception.getMessage());
|
||||
|
||||
return getErrorView(request, response);
|
||||
}
|
||||
|
||||
@ExceptionHandler(SaveSchemaUrlPermissionDeniedException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public String handleServicePermissionDeniedException(HttpServletRequest request, HttpServletResponse response,
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.zip.ZipInputStream;
|
|||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.datagear.analysis.Chart;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
|
@ -898,12 +899,15 @@ public class DashboardController extends AbstractDataAnalysisController implemen
|
|||
|
||||
protected WebContext createWebContext(HttpServletRequest request)
|
||||
{
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
String contextPath = getWebContextPath(request).get(request);
|
||||
WebContext webContext = new WebContext(contextPath, contextPath + "/analysis/dashboard/showData",
|
||||
contextPath + "/analysis/dashboard/loadChart");
|
||||
WebContext webContext = new WebContext(contextPath,
|
||||
addJsessionidParam(contextPath + "/analysis/dashboard/showData", session.getId()),
|
||||
addJsessionidParam(contextPath + "/analysis/dashboard/loadChart", session.getId()));
|
||||
|
||||
webContext.setExtraValues(new HashMap<String, Object>());
|
||||
addHeartBeatValue(webContext);
|
||||
addHeartBeatValue(request, webContext);
|
||||
|
||||
return webContext;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.datagear.web.controller;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -20,15 +21,20 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetParam;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.datagear.analysis.support.AbstractFmkTemplateDataSet;
|
||||
import org.datagear.analysis.support.AbstractDataSet;
|
||||
import org.datagear.analysis.support.CsvValueDataSet;
|
||||
import org.datagear.analysis.support.DataSetFmkTemplateResolver;
|
||||
import org.datagear.analysis.support.DataSetParamValueConverter;
|
||||
import org.datagear.analysis.support.JsonDirectoryFileDataSet;
|
||||
import org.datagear.analysis.support.JsonValueDataSet;
|
||||
import org.datagear.analysis.support.SqlDataSet;
|
||||
import org.datagear.analysis.support.TemplateContext;
|
||||
import org.datagear.analysis.support.TemplateResolvedDataSetResult;
|
||||
import org.datagear.management.domain.CsvFileDataSetEntity;
|
||||
import org.datagear.management.domain.CsvValueDataSetEntity;
|
||||
import org.datagear.management.domain.DataSetEntity;
|
||||
import org.datagear.management.domain.DirectoryFileDataSetEntity;
|
||||
import org.datagear.management.domain.ExcelDataSetEntity;
|
||||
import org.datagear.management.domain.HttpDataSetEntity;
|
||||
import org.datagear.management.domain.JsonFileDataSetEntity;
|
||||
import org.datagear.management.domain.JsonValueDataSetEntity;
|
||||
import org.datagear.management.domain.Schema;
|
||||
|
@ -194,7 +200,130 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
checkSaveJsonFileDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.add(user, dataSet);
|
||||
copyToJsonFileDataSetEntityDirectoryIf(dataSet, "");
|
||||
copyToDirectoryFileDataSetEntityDirectoryIf(dataSet, "");
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
||||
@RequestMapping("/addForExcel")
|
||||
public String addForExcel(HttpServletRequest request, org.springframework.ui.Model model)
|
||||
{
|
||||
ExcelDataSetEntity dataSet = new ExcelDataSetEntity();
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
model.addAttribute("dataSet", dataSet);
|
||||
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "dataSet.addDataSet");
|
||||
model.addAttribute(KEY_FORM_ACTION, "saveAddForExcel");
|
||||
|
||||
return buildFormView(dataSet.getDataSetType());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/saveAddForExcel", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResponseEntity<OperationMessage> saveAddForExcel(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody ExcelDataSetEntity dataSet) throws Throwable
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
dataSet.setId(IDUtil.randomIdOnTime20());
|
||||
dataSet.setCreateUser(User.copyWithoutPassword(user));
|
||||
|
||||
checkSaveExcelDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.add(user, dataSet);
|
||||
copyToDirectoryFileDataSetEntityDirectoryIf(dataSet, "");
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
||||
@RequestMapping("/addForCsvValue")
|
||||
public String addForCsvValue(HttpServletRequest request, org.springframework.ui.Model model)
|
||||
{
|
||||
CsvValueDataSetEntity dataSet = new CsvValueDataSetEntity();
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
model.addAttribute("dataSet", dataSet);
|
||||
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "dataSet.addDataSet");
|
||||
model.addAttribute(KEY_FORM_ACTION, "saveAddForCsvValue");
|
||||
|
||||
return buildFormView(dataSet.getDataSetType());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/saveAddForCsvValue", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResponseEntity<OperationMessage> saveAddForCsvValue(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody CsvValueDataSetEntity dataSet)
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
dataSet.setId(IDUtil.randomIdOnTime20());
|
||||
dataSet.setCreateUser(User.copyWithoutPassword(user));
|
||||
|
||||
checkSaveCsvValueDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.add(user, dataSet);
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
||||
@RequestMapping("/addForCsvFile")
|
||||
public String addForCsvFile(HttpServletRequest request, org.springframework.ui.Model model)
|
||||
{
|
||||
CsvFileDataSetEntity dataSet = new CsvFileDataSetEntity();
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
model.addAttribute("dataSet", dataSet);
|
||||
model.addAttribute("availableCharsetNames", getAvailableCharsetNames());
|
||||
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "dataSet.addDataSet");
|
||||
model.addAttribute(KEY_FORM_ACTION, "saveAddForCsvFile");
|
||||
|
||||
return buildFormView(dataSet.getDataSetType());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/saveAddForCsvFile", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResponseEntity<OperationMessage> saveAddForCsvFile(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody CsvFileDataSetEntity dataSet) throws Throwable
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
dataSet.setId(IDUtil.randomIdOnTime20());
|
||||
dataSet.setCreateUser(User.copyWithoutPassword(user));
|
||||
|
||||
checkSaveCsvFileDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.add(user, dataSet);
|
||||
copyToDirectoryFileDataSetEntityDirectoryIf(dataSet, "");
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
||||
@RequestMapping("/addForHttp")
|
||||
public String addForHttp(HttpServletRequest request, org.springframework.ui.Model model)
|
||||
{
|
||||
HttpDataSetEntity dataSet = new HttpDataSetEntity();
|
||||
|
||||
model.addAttribute("dataSet", dataSet);
|
||||
model.addAttribute("availableCharsetNames", getAvailableCharsetNames());
|
||||
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "dataSet.addDataSet");
|
||||
model.addAttribute(KEY_FORM_ACTION, "saveAddForHttp");
|
||||
|
||||
return buildFormView(dataSet.getDataSetType());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/saveAddForHttp", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResponseEntity<OperationMessage> saveAddForHttp(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody HttpDataSetEntity dataSet)
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
dataSet.setId(IDUtil.randomIdOnTime20());
|
||||
dataSet.setCreateUser(User.copyWithoutPassword(user));
|
||||
|
||||
checkSaveHttpDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.add(user, dataSet);
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
@ -216,7 +345,9 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "dataSet.editDataSet");
|
||||
model.addAttribute(KEY_FORM_ACTION, "saveEditFor" + dataSet.getDataSetType());
|
||||
|
||||
if (DataSetEntity.DATA_SET_TYPE_JsonFile.equals(dataSet.getDataSetType()))
|
||||
if (DataSetEntity.DATA_SET_TYPE_JsonFile.equals(dataSet.getDataSetType())
|
||||
|| DataSetEntity.DATA_SET_TYPE_CsvFile.equals(dataSet.getDataSetType())
|
||||
|| DataSetEntity.DATA_SET_TYPE_Http.equals(dataSet.getDataSetType()))
|
||||
model.addAttribute("availableCharsetNames", getAvailableCharsetNames());
|
||||
|
||||
return buildFormView(dataSet.getDataSetType());
|
||||
|
@ -261,7 +392,67 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
checkSaveJsonFileDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.update(user, dataSet);
|
||||
copyToJsonFileDataSetEntityDirectoryIf(dataSet, originalFileName);
|
||||
copyToDirectoryFileDataSetEntityDirectoryIf(dataSet, originalFileName);
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/saveEditFor" + DataSetEntity.DATA_SET_TYPE_Excel, produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResponseEntity<OperationMessage> saveEditForExcel(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody ExcelDataSetEntity dataSet, @RequestParam("originalFileName") String originalFileName)
|
||||
throws Throwable
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
checkSaveExcelDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.update(user, dataSet);
|
||||
copyToDirectoryFileDataSetEntityDirectoryIf(dataSet, originalFileName);
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/saveEditFor" + DataSetEntity.DATA_SET_TYPE_CsvValue, produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResponseEntity<OperationMessage> saveEditForCsvValue(HttpServletRequest request,
|
||||
HttpServletResponse response, @RequestBody CsvValueDataSetEntity dataSet)
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
checkSaveCsvValueDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.update(user, dataSet);
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/saveEditFor" + DataSetEntity.DATA_SET_TYPE_CsvFile, produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResponseEntity<OperationMessage> saveEditForCsvFile(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody CsvFileDataSetEntity dataSet, @RequestParam("originalFileName") String originalFileName)
|
||||
throws Throwable
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
checkSaveCsvFileDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.update(user, dataSet);
|
||||
copyToDirectoryFileDataSetEntityDirectoryIf(dataSet, originalFileName);
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/saveEditFor" + DataSetEntity.DATA_SET_TYPE_Http, produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResponseEntity<OperationMessage> saveEditForHttp(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody HttpDataSetEntity dataSet)
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
checkSaveHttpDataSetEntity(dataSet);
|
||||
|
||||
this.dataSetEntityService.update(user, dataSet);
|
||||
|
||||
return buildOperationMessageSaveSuccessResponseEntity(request, dataSet);
|
||||
}
|
||||
|
@ -294,6 +485,35 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
return results;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/downloadFile")
|
||||
public void downloadFile(HttpServletRequest request, HttpServletResponse response, @RequestParam("id") String id)
|
||||
throws Exception
|
||||
{
|
||||
User user = WebUtils.getUser(request, response);
|
||||
|
||||
DataSetEntity dataSet = this.dataSetEntityService.getById(user, id);
|
||||
|
||||
if (dataSet == null)
|
||||
throw new RecordNotFoundException();
|
||||
|
||||
if (!(dataSet instanceof DirectoryFileDataSetEntity))
|
||||
throw new IllegalInputException();
|
||||
|
||||
DirectoryFileDataSetEntity dataSetEntity = (DirectoryFileDataSetEntity) dataSet;
|
||||
|
||||
File dataSetDirectory = getDataSetEntityService().getDataSetDirectory(dataSetEntity.getId());
|
||||
File entityFile = FileUtil.getFile(dataSetDirectory, dataSetEntity.getFileName());
|
||||
|
||||
String displayName = dataSetEntity.getDisplayName();
|
||||
displayName = new String(displayName.getBytes("UTF-8"), "ISO-8859-1");
|
||||
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setHeader("Content-Disposition", "attachment; filename=" + displayName + "");
|
||||
OutputStream out = response.getOutputStream();
|
||||
|
||||
IOUtil.write(entityFile, out);
|
||||
}
|
||||
|
||||
@RequestMapping("/view")
|
||||
public String view(HttpServletRequest request, HttpServletResponse response, org.springframework.ui.Model model,
|
||||
@RequestParam("id") String id)
|
||||
|
@ -311,7 +531,9 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
model.addAttribute(KEY_TITLE_MESSAGE_KEY, "dataSet.viewDataSet");
|
||||
model.addAttribute(KEY_READONLY, true);
|
||||
|
||||
if (DataSetEntity.DATA_SET_TYPE_JsonFile.equals(dataSet.getDataSetType()))
|
||||
if (DataSetEntity.DATA_SET_TYPE_JsonFile.equals(dataSet.getDataSetType())
|
||||
|| DataSetEntity.DATA_SET_TYPE_CsvFile.equals(dataSet.getDataSetType())
|
||||
|| DataSetEntity.DATA_SET_TYPE_Http.equals(dataSet.getDataSetType()))
|
||||
model.addAttribute("availableCharsetNames", getAvailableCharsetNames());
|
||||
|
||||
return buildFormView(dataSet.getDataSetType());
|
||||
|
@ -463,8 +685,8 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
{
|
||||
JsonValueDataSet dataSet = preview.getDataSet();
|
||||
|
||||
Map<String, Object> convertedParamValues = getDataSetParamValueConverter()
|
||||
.convert(preview.getParamValues(), dataSet.getParams());
|
||||
Map<String, Object> convertedParamValues = getDataSetParamValueConverter().convert(preview.getParamValues(),
|
||||
dataSet.getParams());
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(convertedParamValues);
|
||||
|
||||
|
@ -474,22 +696,85 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
@RequestMapping(value = "/previewJsonFile", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResolvedDataSetResult previewJsonFile(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, @RequestBody JsonDirectoryFileDataSetPreview preview)
|
||||
org.springframework.ui.Model springModel, @RequestBody JsonFileDataSetEntityPreview preview)
|
||||
throws Throwable
|
||||
{
|
||||
JsonDirectoryFileDataSet dataSet = preview.getDataSet();
|
||||
setJsonDirectoryFileDataSetDirectory(dataSet, preview.getOriginalFileName());
|
||||
JsonFileDataSetEntity dataSet = preview.getDataSet();
|
||||
setDirectoryFileDataSetDirectory(dataSet, preview.getOriginalFileName());
|
||||
|
||||
Map<String, Object> convertedParamValues = getDataSetParamValueConverter()
|
||||
.convert(preview.getParamValues(), dataSet.getParams());
|
||||
Map<String, Object> convertedParamValues = getDataSetParamValueConverter().convert(preview.getParamValues(),
|
||||
dataSet.getParams());
|
||||
|
||||
ResolvedDataSetResult result = dataSet.resolve(convertedParamValues);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean copyToJsonFileDataSetEntityDirectoryIf(JsonFileDataSetEntity entity, String originalFileName)
|
||||
throws IOException
|
||||
@RequestMapping(value = "/previewExcel", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResolvedDataSetResult previewExcel(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, @RequestBody ExcelDataSetEntityPreview preview) throws Throwable
|
||||
{
|
||||
ExcelDataSetEntity dataSet = preview.getDataSet();
|
||||
setDirectoryFileDataSetDirectory(dataSet, preview.getOriginalFileName());
|
||||
|
||||
Map<String, Object> convertedParamValues = getDataSetParamValueConverter().convert(preview.getParamValues(),
|
||||
dataSet.getParams());
|
||||
|
||||
ResolvedDataSetResult result = dataSet.resolve(convertedParamValues);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/previewCsvValue", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public TemplateResolvedDataSetResult previewCsvValue(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, @RequestBody CsvValueDataSetPreview preview) throws Throwable
|
||||
{
|
||||
CsvValueDataSet dataSet = preview.getDataSet();
|
||||
|
||||
Map<String, Object> convertedParamValues = getDataSetParamValueConverter().convert(preview.getParamValues(),
|
||||
dataSet.getParams());
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(convertedParamValues);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/previewCsvFile", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public ResolvedDataSetResult previewCsvFile(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, @RequestBody CsvFileDataSetEntityPreview preview) throws Throwable
|
||||
{
|
||||
CsvFileDataSetEntity dataSet = preview.getDataSet();
|
||||
setDirectoryFileDataSetDirectory(dataSet, preview.getOriginalFileName());
|
||||
|
||||
Map<String, Object> convertedParamValues = getDataSetParamValueConverter().convert(preview.getParamValues(),
|
||||
dataSet.getParams());
|
||||
|
||||
ResolvedDataSetResult result = dataSet.resolve(convertedParamValues);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/previewHttp", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public TemplateResolvedDataSetResult previewHttp(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, @RequestBody HttpDataSetEntityPreview preview) throws Throwable
|
||||
{
|
||||
HttpDataSetEntity dataSet = preview.getDataSet();
|
||||
dataSet.setHttpClient(getDataSetEntityService().getHttpClient());
|
||||
|
||||
Map<String, Object> convertedParamValues = getDataSetParamValueConverter().convert(preview.getParamValues(),
|
||||
dataSet.getParams());
|
||||
|
||||
TemplateResolvedDataSetResult result = dataSet.resolve(convertedParamValues);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean copyToDirectoryFileDataSetEntityDirectoryIf(DirectoryFileDataSetEntity entity,
|
||||
String originalFileName) throws IOException
|
||||
{
|
||||
String fileName = entity.getFileName();
|
||||
|
||||
|
@ -510,7 +795,7 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
return true;
|
||||
}
|
||||
|
||||
protected void setJsonDirectoryFileDataSetDirectory(JsonDirectoryFileDataSet dataSet, String originalFileName)
|
||||
protected void setDirectoryFileDataSetDirectory(DirectoryFileDataSetEntity dataSet, String originalFileName)
|
||||
{
|
||||
String fileName = dataSet.getFileName();
|
||||
|
||||
|
@ -538,7 +823,7 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
|
||||
protected DataSetFmkTemplateResolver getDataSetFmkTemplateResolver()
|
||||
{
|
||||
return AbstractFmkTemplateDataSet.TEMPLATE_RESOLVER;
|
||||
return AbstractDataSet.FMK_TEMPLATE_RESOLVER;
|
||||
}
|
||||
|
||||
protected void checkSaveEntity(DataSetEntity dataSet)
|
||||
|
@ -586,6 +871,44 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
throw new IllegalInputException();
|
||||
}
|
||||
|
||||
protected void checkSaveExcelDataSetEntity(ExcelDataSetEntity dataSet)
|
||||
{
|
||||
checkSaveEntity(dataSet);
|
||||
|
||||
if (isEmpty(dataSet.getFileName()))
|
||||
throw new IllegalInputException();
|
||||
|
||||
if (isEmpty(dataSet.getDisplayName()))
|
||||
throw new IllegalInputException();
|
||||
}
|
||||
|
||||
protected void checkSaveCsvValueDataSetEntity(CsvValueDataSetEntity dataSet)
|
||||
{
|
||||
checkSaveEntity(dataSet);
|
||||
|
||||
if (isEmpty(dataSet.getValue()))
|
||||
throw new IllegalInputException();
|
||||
}
|
||||
|
||||
protected void checkSaveCsvFileDataSetEntity(CsvFileDataSetEntity dataSet)
|
||||
{
|
||||
checkSaveEntity(dataSet);
|
||||
|
||||
if (isEmpty(dataSet.getFileName()))
|
||||
throw new IllegalInputException();
|
||||
|
||||
if (isEmpty(dataSet.getDisplayName()))
|
||||
throw new IllegalInputException();
|
||||
}
|
||||
|
||||
protected void checkSaveHttpDataSetEntity(HttpDataSetEntity dataSet)
|
||||
{
|
||||
checkSaveEntity(dataSet);
|
||||
|
||||
if (isEmpty(dataSet.getUri()))
|
||||
throw new IllegalInputException();
|
||||
}
|
||||
|
||||
public static class AbstractDataSetPreview<T extends DataSet>
|
||||
{
|
||||
private T dataSet;
|
||||
|
@ -641,35 +964,17 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
|
||||
public static class JsonValueDataSetPreview extends AbstractDataSetPreview<JsonValueDataSet>
|
||||
{
|
||||
private String value;
|
||||
|
||||
public JsonValueDataSetPreview()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public JsonValueDataSetPreview(String value)
|
||||
{
|
||||
super();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class JsonDirectoryFileDataSetPreview extends AbstractDataSetPreview<JsonDirectoryFileDataSet>
|
||||
public static class JsonFileDataSetEntityPreview extends AbstractDataSetPreview<JsonFileDataSetEntity>
|
||||
{
|
||||
private String originalFileName;
|
||||
|
||||
public JsonDirectoryFileDataSetPreview()
|
||||
public JsonFileDataSetEntityPreview()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
@ -685,6 +990,62 @@ public class DataSetController extends AbstractSchemaConnController
|
|||
}
|
||||
}
|
||||
|
||||
public static class ExcelDataSetEntityPreview extends AbstractDataSetPreview<ExcelDataSetEntity>
|
||||
{
|
||||
private String originalFileName;
|
||||
|
||||
public ExcelDataSetEntityPreview()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public String getOriginalFileName()
|
||||
{
|
||||
return originalFileName;
|
||||
}
|
||||
|
||||
public void setOriginalFileName(String originalFileName)
|
||||
{
|
||||
this.originalFileName = originalFileName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CsvValueDataSetPreview extends AbstractDataSetPreview<CsvValueDataSet>
|
||||
{
|
||||
public CsvValueDataSetPreview()
|
||||
{
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
public static class CsvFileDataSetEntityPreview extends AbstractDataSetPreview<CsvFileDataSetEntity>
|
||||
{
|
||||
private String originalFileName;
|
||||
|
||||
public CsvFileDataSetEntityPreview()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public String getOriginalFileName()
|
||||
{
|
||||
return originalFileName;
|
||||
}
|
||||
|
||||
public void setOriginalFileName(String originalFileName)
|
||||
{
|
||||
this.originalFileName = originalFileName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class HttpDataSetEntityPreview extends AbstractDataSetPreview<HttpDataSetEntity>
|
||||
{
|
||||
public HttpDataSetEntityPreview()
|
||||
{
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResolveSqlParam
|
||||
{
|
||||
private String sql;
|
||||
|
|
|
@ -37,6 +37,11 @@ public class WebUtils
|
|||
|
||||
public static final String COOKIE_PAGINATION_SIZE = "PAGINATION_PAGE_SIZE";
|
||||
|
||||
/**
|
||||
* Servlet规范中参数会话ID名称,当客户端不支持cookie时,则应使用此参数传递会话ID,格式为:/aa/bb;jsessionid=[id]
|
||||
*/
|
||||
public static final String PARAM_JSESSIONID = "jsessionid";
|
||||
|
||||
/** Servlet环境中存储操作消息的关键字 */
|
||||
public static final String KEY_OPERATION_MESSAGE = "operationMessage";
|
||||
|
||||
|
@ -189,7 +194,8 @@ public class WebUtils
|
|||
* @param name
|
||||
* @param value
|
||||
* @param age
|
||||
* @param path 为{@code null}时则设置为应用根路径
|
||||
* @param path
|
||||
* 为{@code null}时则设置为应用根路径
|
||||
*/
|
||||
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String name, String value,
|
||||
int age, String path)
|
||||
|
@ -503,4 +509,19 @@ public class WebUtils
|
|||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指定URL添加{@linkplain #PARAM_JSESSIONID}参数。
|
||||
* <p>
|
||||
* 当要保持会话而客户端不支持cookie时,应使用此方法为URL添加会话ID参数。
|
||||
* </p>
|
||||
*
|
||||
* @param url
|
||||
* @param sessionId
|
||||
* @return
|
||||
*/
|
||||
public static String addJsessionidParam(String url, String sessionId)
|
||||
{
|
||||
return url + ";" + PARAM_JSESSIONID + "=" + sessionId;
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -249,3 +249,26 @@ DataGear版本更新日志
|
|||
改进:匿名用户创建的数据集、图表、看板在登录后将被迁移至登录用户;
|
||||
改进:SQL数据集预览SQL出错时给出友好提示;
|
||||
改进:导入看板模板文件不存在时给出友好提示;
|
||||
|
||||
|
||||
-----------------------------------------
|
||||
--v1.12.0
|
||||
-----------------------------------------
|
||||
|
||||
新增:新增CSV文本、CSV文件数据集;
|
||||
新增:新增Excel数据集;
|
||||
新增:新增HTTP接口数据集;
|
||||
修复:修复地图图表在有缩放比例或拖动时刷新地图会出现空白的BUG;
|
||||
修复:修复图表、看板在嵌入外部网页的iframe时,对于禁用跨域cookie的浏览器无法正常展示的BUG;
|
||||
修复:修复数据集参数设置表单的年份输入框在焦点移开后无法保存新设置年份的BUG;
|
||||
修复:修复数据集预览、表格图表展示时没有处理XSS的问题;
|
||||
修复:修复保存JSON文件数据集时编码未保存的BUG;
|
||||
改进:雷达图添加列式数据结构支持,可简化雷达图定义;
|
||||
改进:图表联动设置支持数据属性路径,例如:{target: '...', data:{'column[0]': 0}};
|
||||
改进:数据集参数设置表单的年份格式输入框改为专门的年份选择器;
|
||||
改进:改进SQL数据集的数据类型兼容性,仅禁止查询二进制数据列;
|
||||
改进:JSON文件数据集新增JSON数据路径设置项,用于读取文件中指定JSON路径的数据而非整个文件;
|
||||
改进:文件类数据集表单页面新增下载文件功能;
|
||||
改进:数据集预览时参数化语句解析结果改为通过按钮点击后显示浮动面板,避免影响页面布局;
|
||||
改进:图表、数据集页面日期类的参数输入框禁用浏览器自动补全功能,避免遮挡日期选择器;
|
||||
改进:看板编辑页编辑区最大化按钮移至底部;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
<value>org.datagear.web.locales.datagear</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="defaultEncoding" value="UTF-8" />
|
||||
</bean>
|
||||
|
||||
<bean id="driverEntityManagerRootDirectoryFactory" class="org.datagear.web.util.DirectoryFactory" init-method="init">
|
||||
|
@ -225,12 +226,15 @@
|
|||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="httpClient" class="org.apache.hc.client5.http.impl.classic.HttpClients" factory-method="createDefault" />
|
||||
|
||||
<bean id="dataSetEntityService" class="org.datagear.management.service.impl.DataSetEntityServiceImpl">
|
||||
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
|
||||
<property name="connectionSource" ref="connectionSource" />
|
||||
<property name="schemaService" ref="schemaService" />
|
||||
<property name="authorizationService" ref="authorizationService" />
|
||||
<property name="dataSetRootDirectory" ref="dataSetRootDirectory" />
|
||||
<property name="httpClient" ref="httpClient" />
|
||||
</bean>
|
||||
|
||||
<bean id="directoryHtmlChartPluginManager" class="org.datagear.analysis.support.html.DirectoryHtmlChartPluginManager">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#--UTF-8 file--
|
||||
|
||||
#系统版本号
|
||||
version=1.11.1
|
||||
version=1.12.0
|
||||
|
||||
#构建日期
|
||||
buildDate=${buildtimestamp}
|
File diff suppressed because it is too large
Load Diff
|
@ -269,6 +269,17 @@
|
|||
-webkit-transform:rotate(90deg);
|
||||
-o-transform:rotate(90deg);
|
||||
}
|
||||
.xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year{
|
||||
width: auto;
|
||||
padding: 0.3em 1em;
|
||||
margin-top: 3px;
|
||||
margin-right: 0.6em;
|
||||
float: right;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
}
|
||||
|
||||
/*看板表单*/
|
||||
.dg-dashboard-form.dg-dspv-form,
|
||||
|
|
|
@ -97,6 +97,18 @@ form .form-content .form-item .form-item-label label{
|
|||
width: 95%;
|
||||
overflow: hidden;
|
||||
}
|
||||
form .form-content .form-item .form-item-label label[title]{
|
||||
position: relative;
|
||||
}
|
||||
form .form-content .form-item .form-item-label label[title]::after{
|
||||
content: "?";
|
||||
position: absolute;
|
||||
margin-left: 0.2em;
|
||||
font-size: 0.6em;
|
||||
top: 0.3em;
|
||||
opacity: 0.5;
|
||||
filter: Alpha(Opacity=50);
|
||||
}
|
||||
form .form-content .form-item .form-item-value{
|
||||
display: inline-block;
|
||||
width: 80%;
|
||||
|
@ -146,7 +158,21 @@ form .form-content .form-item .input-desc{
|
|||
display: inline-block;
|
||||
}
|
||||
form .form-content .form-item .input-desc-date{
|
||||
|
||||
}
|
||||
form .form-content .form-item .form-item-value .form-item{
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
margin-left: 2em;
|
||||
}
|
||||
form .form-content .form-item .form-item-value .form-item .form-item-label{
|
||||
width: auto;
|
||||
}
|
||||
form .form-content .form-item .form-item-value .form-item .form-item-label label{
|
||||
width: auto;
|
||||
}
|
||||
form .form-content .form-item .form-item-value .form-item .form-item-value{
|
||||
width: auto;
|
||||
margin-left: 1em;
|
||||
}
|
||||
form .form-foot{
|
||||
text-align: center;
|
||||
|
@ -309,6 +335,33 @@ form .form-foot .ui-button{
|
|||
font-size: small;
|
||||
}
|
||||
|
||||
/*轻型选显卡*/
|
||||
.ui-tabs.light-tabs{
|
||||
margin: 0 0;
|
||||
padding: 0 0;
|
||||
}
|
||||
.ui-tabs.light-tabs.ui-widget.ui-widget-content{
|
||||
border: 0;
|
||||
}
|
||||
.ui-tabs.light-tabs .ui-tabs-nav{
|
||||
border: 0;
|
||||
background: none;
|
||||
opacity: 0.8;
|
||||
filter: Alpha(Opacity=80);
|
||||
}
|
||||
.ui-tabs.light-tabs .ui-tabs-nav .ui-tabs-anchor{
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
}
|
||||
.ui-tabs.light-tabs .ui-tabs-panel{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
top: 2.2em;
|
||||
bottom: 0px;
|
||||
padding: 0 0;
|
||||
}
|
||||
|
||||
/*jquery.layout*/
|
||||
.ui-layout-pane{
|
||||
border: 1px solid #c5c5c5;
|
||||
|
@ -2111,68 +2164,92 @@ table.dataTable tbody tr td select{
|
|||
}
|
||||
|
||||
.page-form-dataSet{}
|
||||
.page-form-dataSet .workspace-editor-wrapper{
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
.page-form-dataSet .workspace{
|
||||
position: relative;
|
||||
}
|
||||
.page-form-dataSet .form-content{
|
||||
overflow: auto;
|
||||
}
|
||||
.page-form-dataSet .workspace .form-item .form-item-label{
|
||||
vertical-align:top;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
.page-form-dataSet .workspace .form-item .form-item-value{
|
||||
width: 39%;
|
||||
position: relative;
|
||||
padding-bottom: 1.4em;
|
||||
}
|
||||
.page-form-dataSet .workspace .form-item .form-item-value.no-padding-bottom{
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.page-form-dataSet .workspace .form-item .form-item-value input[type=text],
|
||||
.page-form-dataSet .workspace .form-item .form-item-value input[type=password],
|
||||
.page-form-dataSet .workspace .form-item .form-item-value textarea,
|
||||
.page-form-dataSet .workspace .form-item .form-item-value .input{
|
||||
width: 90%;
|
||||
}
|
||||
.page-form-dataSet .workspace .form-item .form-item-value input.file-display-name{
|
||||
width: 60%;
|
||||
}
|
||||
.page-form-dataSet .workspace .form-item .form-item-value .fileinput-wrapper{
|
||||
padding-top: 0.41em;
|
||||
}
|
||||
.page-form-dataSet .workspace .form-item label.error{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.page-form-dataSet .workspace .workspace-editor-wrapper{
|
||||
height: 10em;
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
.page-form-dataSet .workspace-editor-wrapper .workspace-editor{
|
||||
.page-form-dataSet .workspace .workspace-editor-wrapper .workspace-editor{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper{
|
||||
position: relative;
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper{
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 48%;
|
||||
width: 41%;
|
||||
top: 0.3em;
|
||||
right: 0;
|
||||
height: 10em;
|
||||
vertical-align: top;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper.ui-widget.ui-widget-content{
|
||||
border: 0;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper.ui-tabs{
|
||||
margin: 0 0;
|
||||
padding: 0 0;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper.ui-tabs .ui-tabs-nav{
|
||||
border: 0;
|
||||
background: none;
|
||||
opacity: 0.8;
|
||||
filter: Alpha(Opacity=80);
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper.ui-tabs .ui-tabs-nav .ui-tabs-anchor{
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper.ui-tabs .ui-tabs-panel{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
top: 2.2em;
|
||||
bottom: 0px;
|
||||
padding: 0 0;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper .operation{
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper .operation{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: -1.5em;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper .operation .ui-button.ui-button-icon-only{
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper .operation .ui-button.ui-button-icon-only,
|
||||
.page-form-dataSet .workspace .show-resolved-source-button{
|
||||
height: 1.2em;
|
||||
width: 2.5em;
|
||||
vertical-align: top;
|
||||
border: 0px;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper .preview-result-table-wrapper .result-resolved-source{
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper .preview-result-table-wrapper .result-resolved-source{
|
||||
position: relative;
|
||||
top: 0.1em;
|
||||
display: none;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper .preview-result-table-wrapper .result-resolved-source-panel{
|
||||
position: absolute;
|
||||
display: none;
|
||||
bottom: -4em;
|
||||
height: 3.5em;
|
||||
right: 0;
|
||||
left: 0;
|
||||
width: 90%;
|
||||
height: 8em;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper .preview-result-table-wrapper .result-resolved-source textarea{
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper .preview-result-table-wrapper .result-resolved-source-panel-content{
|
||||
position: absolute;
|
||||
left: 0.41em;
|
||||
top: 0.41em;
|
||||
right: 0.41em;
|
||||
bottom: 0.41em;
|
||||
}
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper .preview-result-table-wrapper .result-resolved-source-panel-content textarea{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 0;
|
||||
|
@ -2180,16 +2257,13 @@ table.dataTable tbody tr td select{
|
|||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper .input-in-table{
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper .input-in-table{
|
||||
width: 90%!important;
|
||||
}
|
||||
.page-form-dataSet .workspace-operation-wrapper .input-in-table.readonly{
|
||||
.page-form-dataSet .workspace .workspace-operation-wrapper .input-in-table.readonly{
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
.page-form-dataSet .form-item-workspace .error{
|
||||
display: block;
|
||||
}
|
||||
.page-form-dataSet .preview-param-value-panel{
|
||||
position: absolute;
|
||||
display: none;
|
||||
|
@ -2212,20 +2286,15 @@ table.dataTable tbody tr td select{
|
|||
.page-form-dataSet .form-foot-placeholder{
|
||||
height: 2.5em;
|
||||
}
|
||||
.page-form-dataSet-jsonFile{}
|
||||
.page-form-dataSet-jsonFile .form-item-workspace .form-item-label{
|
||||
vertical-align:top;
|
||||
margin-top: 0.3em;
|
||||
.page-form-dataSet .encoding-selectmenu-menu .ui-menu{
|
||||
height: 10em;
|
||||
}
|
||||
.page-form-dataSet-jsonFile .form-item-workspace .form-item-value .file-display-name{
|
||||
width: 60% !important;
|
||||
}
|
||||
.page-form-dataSet-jsonFile .form-item-workspace .form-item-value .fileinput-wrapper{
|
||||
margin-top: 0.41em;
|
||||
}
|
||||
.page-form-dataSet-jsonFile .encoding-selectmenu-menu .ui-menu{
|
||||
max-height: 14em;
|
||||
overflow: auto;
|
||||
.page-form-dataSet-Http .form-item-value-requestMethod .ui-selectmenu-button,
|
||||
.page-form-dataSet-Http .form-item-value-requestContentType .ui-selectmenu-button,
|
||||
.page-form-dataSet-Http .form-item-value-requestContentCharset .ui-selectmenu-button,
|
||||
.page-form-dataSet-Http .form-item-value-responseContentType .ui-selectmenu-button{
|
||||
width: auto;
|
||||
min-width: 6em;
|
||||
}
|
||||
|
||||
.page-form-chart .chart-plugin{
|
||||
|
@ -2663,7 +2732,7 @@ table.dataTable tbody tr td select{
|
|||
position: absolute;
|
||||
display: inline-block;
|
||||
z-index: 10;
|
||||
top: -0.6em;
|
||||
bottom: -1em;
|
||||
}
|
||||
.page-form-dashboard .form-item-value-template .resize-editor-wrapper.resize-left{
|
||||
left: -0.6em;
|
||||
|
@ -2672,9 +2741,9 @@ table.dataTable tbody tr td select{
|
|||
right: -0.6em;
|
||||
}
|
||||
.page-form-dashboard .form-item-value-template .resize-editor-wrapper .ui-button.ui-button-icon-only{
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
padding: 0.3em 0.3em;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
padding: 0 0.3em;
|
||||
border: 0;
|
||||
}
|
||||
.page-form-dashboard .show-button{
|
||||
|
|
|
@ -1323,7 +1323,7 @@
|
|||
*
|
||||
* @param chartDataSet 图表数据集对象
|
||||
* @param dataSign 数据标记对象、标记名称
|
||||
* @return {...}
|
||||
* @return {...}、undefined
|
||||
*/
|
||||
chartBase.dataSetPropertyOfSign = function(chartDataSet, dataSign)
|
||||
{
|
||||
|
@ -1825,7 +1825,7 @@
|
|||
* 图表事件支持函数:获取/设置图表事件对象的数据(chartEvent.data)。
|
||||
*
|
||||
* @param chartEvent 图表事件对象
|
||||
* @param data 可选,要设置的数据对象
|
||||
* @param data 可选,要设置的数据对象,绘制图表条目的数据对象:{ 数据标记名 : 数据值, ... }
|
||||
*/
|
||||
chartBase.eventData = function(chartEvent, data)
|
||||
{
|
||||
|
@ -1839,7 +1839,7 @@
|
|||
* 图表事件支持函数:获取/设置图表事件对象的原始数据(chartEvent.originalData)。
|
||||
*
|
||||
* @param chartEvent 图表事件对象
|
||||
* @param originalData 可选,要设置的原始数据对象
|
||||
* @param originalData 可选,要设置的原始数据,绘制图表条目的原始数据集结果数据,可以是单个数据对象、数据对象数组
|
||||
*/
|
||||
chartBase.eventOriginalData = function(chartEvent, originalData)
|
||||
{
|
||||
|
@ -1850,7 +1850,7 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* 图表事件支持函数:获取/设置图表事件对象的原始数据对应的图表数据集索引((chartEvent.originalChartDataSetIndex))。
|
||||
* 图表事件支持函数:获取/设置图表事件对象的原始数据对应的图表数据集索引(chartEvent.originalChartDataSetIndex)。
|
||||
*
|
||||
* @param chartEvent 图表事件对象
|
||||
* @param originalChartDataSetIndex 可选,要设置的图表数据集索引数值
|
||||
|
@ -1864,10 +1864,11 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* 图表事件支持函数:获取/设置图表事件对象的原始数据对应的结果数据索引((chartEvent.originalResultDataIndex))。
|
||||
* 图表事件支持函数:获取/设置图表事件对象的原始数据在数据集结果数据中的索引((chartEvent.originalResultDataIndex))。
|
||||
*
|
||||
* @param chartEvent 图表事件对象
|
||||
* @param originalResultDataIndex 可选,要设置的结果数据索引数值
|
||||
* @param originalResultDataIndex 可选,要设置的结果数据索引,当chartEvent.originalData为单个对象时,应是单个索引值;
|
||||
* 当chartEvent.originalData为对象数组时,应是与之对应的索引值数组
|
||||
*/
|
||||
chartBase.eventOriginalResultDataIndex = function(chartEvent, originalResultDataIndex)
|
||||
{
|
||||
|
@ -1877,6 +1878,41 @@
|
|||
chartEvent["originalResultDataIndex"] = originalResultDataIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
* 图表事件支持函数:设置图表事件对象的原始图表数据集索引、原始数据、原始数据索引。
|
||||
*
|
||||
* @param chartEvent 图表事件对象
|
||||
* @param originalChartDataSetIndex 原始图表数据集索引
|
||||
* @param originalResultDataIndex 原始数据索引,格式允许:数值、数值数组
|
||||
*/
|
||||
chartBase.eventOriginalInfo = function(chartEvent, originalChartDataSetIndex, originalResultDataIndex)
|
||||
{
|
||||
var result = this.resultAt(this.getUpdateResults(), originalChartDataSetIndex);
|
||||
var resultDatas = (result == null ? [] : this.resultDatas(result));
|
||||
|
||||
var originalData = undefined;
|
||||
|
||||
var rdi = originalResultDataIndex;
|
||||
|
||||
//索引数值
|
||||
if(typeof(rdi) == "number")
|
||||
{
|
||||
originalData = resultDatas[rdi];
|
||||
}
|
||||
//索引数值数组
|
||||
else if($.isArray(rdi))
|
||||
{
|
||||
originalData = [];
|
||||
|
||||
for(var i=0; i<rdi.length; i++)
|
||||
originalData.push(resultDatas[rdi[i]]);
|
||||
}
|
||||
|
||||
this.eventOriginalData(chartEvent, originalData);
|
||||
this.eventOriginalChartDataSetIndex(chartEvent, originalChartDataSetIndex);
|
||||
this.eventOriginalResultDataIndex(chartEvent, rdi);
|
||||
};
|
||||
|
||||
/**
|
||||
* 图表事件支持函数:绑定图表事件处理函数代理。
|
||||
* 注意:此函数在图表渲染完成后才可调用。
|
||||
|
@ -2278,6 +2314,38 @@
|
|||
return "dataGearClientElement" + nextIdSeq;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 将给定值按照HTML规范转义,如果不是字符串,直接返回原值。
|
||||
*/
|
||||
chartFactory.escapeHtml = function(value)
|
||||
{
|
||||
if(typeof(value) != "string")
|
||||
return value;
|
||||
|
||||
var epn = "";
|
||||
|
||||
for(var i=0; i<value.length; i++)
|
||||
{
|
||||
var c = value.charAt(i);
|
||||
|
||||
if(c == '<')
|
||||
epn += '<';
|
||||
else if(c == '>')
|
||||
epn += '>';
|
||||
else if(c == '&')
|
||||
epn += '&';
|
||||
else if(c == '"')
|
||||
epn += '"';
|
||||
else if(c == '\'')
|
||||
epn += ''';
|
||||
else
|
||||
epn += c;
|
||||
}
|
||||
|
||||
return epn;
|
||||
};
|
||||
|
||||
/**
|
||||
* 记录异常日志。
|
||||
*
|
||||
|
|
|
@ -62,6 +62,9 @@
|
|||
}
|
||||
});
|
||||
|
||||
//是否禁用日期组件输入框的浏览器自动完成功能,浏览器自动完成功能会阻挡日期选择框,默认禁用
|
||||
chartForm.disableDateAwareInputAutocomplete = (chartForm.disableDateAwareInputAutocomplete || true);
|
||||
|
||||
/**
|
||||
* 渲染数据集参数值表单。
|
||||
*
|
||||
|
@ -397,6 +400,9 @@
|
|||
var $input = $("<input type='text' class='dg-dspv-form-input' />").attr("name", dataSetParam.name)
|
||||
.attr("value", (value || "")).appendTo($parent);
|
||||
|
||||
if(chartForm.disableDateAwareInputAutocomplete)
|
||||
$input.attr("autocomplete", "off");
|
||||
|
||||
if((dataSetParam.required+"") == "true")
|
||||
$input.attr("dg-validation-required", "true");
|
||||
|
||||
|
@ -435,6 +441,9 @@
|
|||
var $input = $("<input type='text' class='dg-dspv-form-input' />").attr("name", dataSetParam.name)
|
||||
.attr("value", (value || "")).appendTo($parent);
|
||||
|
||||
if(chartForm.disableDateAwareInputAutocomplete)
|
||||
$input.attr("autocomplete", "off");
|
||||
|
||||
if((dataSetParam.required+"") == "true")
|
||||
$input.attr("dg-validation-required", "true");
|
||||
|
||||
|
@ -472,6 +481,9 @@
|
|||
var $input = $("<input type='text' class='dg-dspv-form-input' />").attr("name", dataSetParam.name)
|
||||
.attr("value", (value || "")).appendTo($parent);
|
||||
|
||||
if(chartForm.disableDateAwareInputAutocomplete)
|
||||
$input.attr("autocomplete", "off");
|
||||
|
||||
if((dataSetParam.required+"") == "true")
|
||||
$input.attr("dg-validation-required", "true");
|
||||
|
||||
|
@ -626,6 +638,9 @@
|
|||
|
||||
chartForm.datetimepicker = function($input, datetimepickerOptions, chartTheme)
|
||||
{
|
||||
//在这里检查并重写,避免依赖加载顺序
|
||||
global.overwriteDateFormatter_parseDate();
|
||||
|
||||
if(chartForm._datetimepickerSetLocale !== true)
|
||||
{
|
||||
$.datetimepicker.setLocale('zh');
|
||||
|
@ -652,6 +667,45 @@
|
|||
},
|
||||
datetimepickerOptions);
|
||||
|
||||
//初始化为年份选择器
|
||||
var isOnlySelectYear = ("Y" == datetimepickerOptions.format || "y" == datetimepickerOptions.format);
|
||||
if(isOnlySelectYear)
|
||||
{
|
||||
//显示确定按钮,用于直接选中默认年份
|
||||
datetimepickerOptions.showApplyButton = true;
|
||||
datetimepickerOptions.onGenerate = function(currentValue,$input)
|
||||
{
|
||||
var yearPickerInited = $(this).attr("yearPickerInited");
|
||||
if(!yearPickerInited)
|
||||
{
|
||||
$(this).attr("yearPickerInited", "yes");
|
||||
|
||||
$(".xdsoft_prev", this).hide();
|
||||
$(".xdsoft_today_button", this).hide();
|
||||
$(".xdsoft_month", this).hide();
|
||||
$(".xdsoft_next", this).hide();
|
||||
$(".xdsoft_calendar", this).hide();
|
||||
|
||||
$(".xdsoft_save_selected", this).removeClass("blue-gradient-button")
|
||||
.addClass("xdsoft_save_selected_year ui-button ui-corner-all").html(chartForm.labels.confirm);
|
||||
}
|
||||
};
|
||||
datetimepickerOptions.onShow = function(currentValue,$input)
|
||||
{
|
||||
if(!$input.val())
|
||||
{
|
||||
//这样可以直接点击【确定】按钮选择默认年份
|
||||
this.setOptions({value: currentValue});
|
||||
$input.val("");
|
||||
}
|
||||
};
|
||||
datetimepickerOptions.onChangeYear = function(currentValue,$input)
|
||||
{
|
||||
this.setOptions({value: currentValue});
|
||||
$(".xdsoft_save_selected", this).click();
|
||||
};
|
||||
}
|
||||
|
||||
$input.datetimepicker(datetimepickerOptions);
|
||||
};
|
||||
|
||||
|
@ -738,6 +792,14 @@
|
|||
+" box-shadow: none;"
|
||||
+" -webkit-box-shadow: none;"
|
||||
+"} "
|
||||
+parentSelector + " .xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year{"
|
||||
+" color: "+color+";"
|
||||
+" background: "+bgColor+";"
|
||||
+" border: 1px solid "+borderColor+" !important;"
|
||||
+"} "
|
||||
+parentSelector + " .xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year:hover{"
|
||||
+" background: "+hoverColor+";"
|
||||
+"} "
|
||||
;
|
||||
|
||||
global.chartFactory.createStyleSheet(styleId, cssText);
|
||||
|
@ -1280,4 +1342,139 @@
|
|||
return ($panel.length == 0 || $panel.is(":hidden"));
|
||||
};
|
||||
})
|
||||
(this);
|
||||
|
||||
(function(global)
|
||||
{
|
||||
global.overwriteDateFormatter_parseDate = function()
|
||||
{
|
||||
if(global._overwriteDateFormatter_parseDate == true)
|
||||
return;
|
||||
|
||||
global._overwriteDateFormatter_parseDate = true;
|
||||
|
||||
//重写datetimepicker的DateFormatter.prototype.parseDate函数,
|
||||
//解决当options配置为仅选择年份({format:'Y'})时,选择完毕后输入框blur后,年份会被重置的的BUG
|
||||
DateFormatter.prototype.parseDate = function(e, r) {
|
||||
var n, a, u, i, s, o, c, f, l, h, d = this, g = !1, m = !1, p = d.dateSettings, y = {
|
||||
date: null,
|
||||
year: null,
|
||||
month: null,
|
||||
day: null,
|
||||
hour: 0,
|
||||
min: 0,
|
||||
sec: 0
|
||||
};
|
||||
if (!e)
|
||||
return null;
|
||||
if (e instanceof Date)
|
||||
return e;
|
||||
if ("U" === r)
|
||||
return u = parseInt(e),
|
||||
u ? new Date(1e3 * u) : e;
|
||||
switch (typeof e) {
|
||||
case "number":
|
||||
return new Date(e);
|
||||
case "string":
|
||||
break;
|
||||
default:
|
||||
return null
|
||||
}
|
||||
if (n = r.match(d.validParts),
|
||||
!n || 0 === n.length)
|
||||
throw new Error("Invalid date format definition.");
|
||||
for (a = e.replace(d.separators, "\x00").split("\x00"),
|
||||
u = 0; u < a.length; u++)
|
||||
switch (i = a[u],
|
||||
s = parseInt(i),
|
||||
n[u]) {
|
||||
case "y":
|
||||
case "Y":
|
||||
if (!s)
|
||||
return null;
|
||||
l = i.length,
|
||||
y.year = 2 === l ? parseInt((70 > s ? "20" : "19") + i) : s,
|
||||
g = !0;
|
||||
break;
|
||||
case "m":
|
||||
case "n":
|
||||
case "M":
|
||||
case "F":
|
||||
if (isNaN(s)) {
|
||||
if (o = d.getMonth(i),
|
||||
!(o > 0))
|
||||
return null;
|
||||
y.month = o
|
||||
} else {
|
||||
if (!(s >= 1 && 12 >= s))
|
||||
return null;
|
||||
y.month = s
|
||||
}
|
||||
g = !0;
|
||||
break;
|
||||
case "d":
|
||||
case "j":
|
||||
if (!(s >= 1 && 31 >= s))
|
||||
return null;
|
||||
y.day = s,
|
||||
g = !0;
|
||||
break;
|
||||
case "g":
|
||||
case "h":
|
||||
if (c = n.indexOf("a") > -1 ? n.indexOf("a") : n.indexOf("A") > -1 ? n.indexOf("A") : -1,
|
||||
h = a[c],
|
||||
c > -1)
|
||||
f = t(h, p.meridiem[0]) ? 0 : t(h, p.meridiem[1]) ? 12 : -1,
|
||||
s >= 1 && 12 >= s && f > -1 ? y.hour = s + f - 1 : s >= 0 && 23 >= s && (y.hour = s);
|
||||
else {
|
||||
if (!(s >= 0 && 23 >= s))
|
||||
return null;
|
||||
y.hour = s
|
||||
}
|
||||
m = !0;
|
||||
break;
|
||||
case "G":
|
||||
case "H":
|
||||
if (!(s >= 0 && 23 >= s))
|
||||
return null;
|
||||
y.hour = s,
|
||||
m = !0;
|
||||
break;
|
||||
case "i":
|
||||
if (!(s >= 0 && 59 >= s))
|
||||
return null;
|
||||
y.min = s,
|
||||
m = !0;
|
||||
break;
|
||||
case "s":
|
||||
if (!(s >= 0 && 59 >= s))
|
||||
return null;
|
||||
y.sec = s,
|
||||
m = !0
|
||||
}
|
||||
|
||||
//----添加的内容
|
||||
//如果选择了年份,检查并设置月份、日的初值,使下面的:
|
||||
//if (g === !0 && y.year && y.month && y.day)
|
||||
//逻辑可以执行到
|
||||
if (g === !0 && y.year)
|
||||
{
|
||||
if(!y.month)
|
||||
y.month = 1;
|
||||
if(!y.day)
|
||||
y.day = 1;
|
||||
}
|
||||
//----添加的内容
|
||||
|
||||
if (g === !0 && y.year && y.month && y.day)
|
||||
y.date = new Date(y.year,y.month - 1,y.day,y.hour,y.min,y.sec,0);
|
||||
else {
|
||||
if (m !== !0)
|
||||
return null;
|
||||
y.date = new Date(0,0,0,y.hour,y.min,y.sec,0)
|
||||
}
|
||||
return y.date
|
||||
};
|
||||
}
|
||||
})
|
||||
(this);
|
|
@ -133,6 +133,20 @@
|
|||
return re;
|
||||
};
|
||||
|
||||
/**
|
||||
* 为数组追加单个元素、数组
|
||||
*/
|
||||
chartSupport.appendElement = function(array, eles)
|
||||
{
|
||||
if($.isArray(eles))
|
||||
{
|
||||
for(var i=0; i<eles.length; i++)
|
||||
array.push(eles[i]);
|
||||
}
|
||||
else
|
||||
array.push(eles);
|
||||
};
|
||||
|
||||
/**
|
||||
* 为源数组追加不重复的元素。
|
||||
*
|
||||
|
@ -249,82 +263,164 @@
|
|||
else
|
||||
chart.extValue("signNameMap", signNameMap);
|
||||
};
|
||||
|
||||
chartSupport.KEY_CHART_ORIGINAL_DATA_INFO = "__dataGearChartOriginalDataInfo";
|
||||
|
||||
|
||||
/**
|
||||
* 设置图表数据对象的原始数据信息。
|
||||
* 根据原始数据索引对象设置图表事件对象的原始数据相关信息。
|
||||
*
|
||||
* @param chartData 图表数据对象、对象数组
|
||||
* @param chartDataSetIndex 原始图表数据集索引
|
||||
* @param resultDataIndex 可选,原始图表数据集结果数据索引,默认为0
|
||||
* @param chart
|
||||
* @param chartEvent
|
||||
* @param originalDataIndex 原始数据索引对象,格式为:
|
||||
* {
|
||||
* //图表数据集索引数值
|
||||
* chartDataSetIndex: 数值,
|
||||
*
|
||||
* //图表数据集结果数据索引信息,格式为:
|
||||
* //数值:单条结果数据索引;
|
||||
* //[数值, ...]:多条结果数据索引;
|
||||
* //{start: 数值, end: 数值}:范围结果数据索引;
|
||||
* resultDataIndex: ...
|
||||
* }
|
||||
*/
|
||||
chartSupport.setChartOriginalDataInfo = function(chartData, chartDataSetIndex, resultDataIndex)
|
||||
chartSupport.setChartEventOriginalDataByIndex = function(chart, chartEvent, originalDataIndex)
|
||||
{
|
||||
if(!chartData)
|
||||
return;
|
||||
|
||||
if(resultDataIndex == null)
|
||||
resultDataIndex = 0;
|
||||
|
||||
if($.isArray(chartData))
|
||||
if(!originalDataIndex)
|
||||
{
|
||||
for(var i=0; i<chartData.length; i++)
|
||||
{
|
||||
chartData[i][chartSupport.KEY_CHART_ORIGINAL_DATA_INFO] =
|
||||
{
|
||||
chartDataSetIndex : chartDataSetIndex, resultDataIndex: resultDataIndex+i
|
||||
};
|
||||
}
|
||||
chart.eventOriginalData(chartEvent, null);
|
||||
chart.eventOriginalChartDataSetIndex(chartEvent, null);
|
||||
chart.eventOriginalResultDataIndex(chartEvent, null);
|
||||
return;
|
||||
}
|
||||
else
|
||||
chartData[chartSupport.KEY_CHART_ORIGINAL_DATA_INFO] = { chartDataSetIndex : chartDataSetIndex, resultDataIndex: resultDataIndex };
|
||||
|
||||
var rdi = originalDataIndex.resultDataIndex;
|
||||
|
||||
if(rdi.start != null && rdi.end != null)
|
||||
{
|
||||
var rdiAry = [];
|
||||
|
||||
for(var i=rdi.start; i<rdi.end; i++)
|
||||
rdiAry.push(i);
|
||||
|
||||
rdi = rdiAry;
|
||||
}
|
||||
|
||||
chart.eventOriginalInfo(chartEvent, originalDataIndex.chartDataSetIndex, rdi);
|
||||
};
|
||||
|
||||
chartSupport.setChartEventOriginalDataForChartData = function(chart, chartEvent, chartData)
|
||||
{
|
||||
var index = chartSupport.chartDataOriginalDataIndex(chartData);
|
||||
this.setChartEventOriginalDataByIndex(chart, chartEvent, index);
|
||||
};
|
||||
|
||||
chartSupport.setChartEventOriginalDataForEchartsRange = function(chart, chartEvent, echartsEventParams)
|
||||
{
|
||||
var index = this.getChartOriginalDataIndexForRange(chart, echartsEventParams.seriesIndex, echartsEventParams.dataIndex);
|
||||
this.setChartEventOriginalDataByIndex(chart, chartEvent, index);
|
||||
};
|
||||
|
||||
chartSupport.KEY_ORIGINAL_DATA_INDEX = "__DataGearOriginalDataIndex";
|
||||
|
||||
/**
|
||||
* 获取图表数据对象的原始数据信息。
|
||||
* 获取/设置图表数据对象的原始数据索引对象(originalDataIndex)。
|
||||
*
|
||||
* @param chartData 图表数据对象
|
||||
* @param chartDataSetIndex 原始图表数据集索引
|
||||
* @param resultDataIndex 参考setChartEventOriginalDataByIndex函数的originalDataIndex.resultDataIndex参数说明
|
||||
*/
|
||||
chartSupport.getChartOriginalDataInfo = function(chartData)
|
||||
chartSupport.chartDataOriginalDataIndex = function(chartData, chartDataSetIndex, resultDataIndex)
|
||||
{
|
||||
if(!chartData)
|
||||
return undefined;
|
||||
|
||||
return chartData[chartSupport.KEY_CHART_ORIGINAL_DATA_INFO];
|
||||
if(chartDataSetIndex === undefined)
|
||||
return chartData[chartSupport.KEY_ORIGINAL_DATA_INDEX];
|
||||
|
||||
var index = { chartDataSetIndex : chartDataSetIndex, resultDataIndex: resultDataIndex };
|
||||
chartData[chartSupport.KEY_ORIGINAL_DATA_INDEX] = index;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取/设置HTML元素的图表原始数据信息。
|
||||
* 获取/设置DOM元素的原始数据索引对象(originalDataIndex)。
|
||||
*
|
||||
* @param $dom DOM对象
|
||||
* @param chartDataSetIndex 原始图表数据集索引
|
||||
* @param resultDataIndex 参考setChartEventOriginalDataByIndex函数的originalDataIndex.resultDataIndex参数说明
|
||||
*/
|
||||
chartSupport.chartOriginalDataInfoHtml = function($dom, chartDataSetIndex, resultDataIndex)
|
||||
chartSupport.domOriginalDataIndex = function($dom, chartDataSetIndex, resultDataIndex)
|
||||
{
|
||||
if(chartDataSetIndex === undefined && resultDataIndex === undefined)
|
||||
return $dom.data(chartSupport.KEY_CHART_ORIGINAL_DATA_INFO);
|
||||
if(chartDataSetIndex === undefined)
|
||||
return $dom.data(chartSupport.KEY_ORIGINAL_DATA_INDEX);
|
||||
else
|
||||
$dom.data(chartSupport.KEY_CHART_ORIGINAL_DATA_INFO,
|
||||
{
|
||||
chartDataSetIndex : chartDataSetIndex, resultDataIndex: resultDataIndex
|
||||
});
|
||||
{
|
||||
var index = { chartDataSetIndex : chartDataSetIndex, resultDataIndex: resultDataIndex };
|
||||
$dom.data(chartSupport.KEY_ORIGINAL_DATA_INDEX, index);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 设置图表数据范围的原始信息。
|
||||
* 设置图表特定系列的指定数据范围对应的的原始数据索引对象。
|
||||
*
|
||||
* @param chart
|
||||
* @param seriesIndex 图表系列索引
|
||||
* @param dataIndexStart 图表系列数据起始索引
|
||||
* @param dataIndexEnd 图表系列数据结束索引
|
||||
* @param resultDataIndexStart 可选,数据结果起始索引,默认为0
|
||||
* @param dataIndexStart 图表系列的数据范围起始索引
|
||||
* @param dataIndexEnd 图表系列的数据范围结束索引,为null则表示为:dataIndexStart+1
|
||||
* @param resultDataIndexInfo 可选,原始图表数据集结果数据索引信息,格式为:
|
||||
* {
|
||||
* //与图表系列的数据范围顺序对应
|
||||
* type: "ordinal",
|
||||
* //可选,数据集结果数据索引起始索引,默认为0
|
||||
* start: 数值
|
||||
* }
|
||||
* 或者
|
||||
* {
|
||||
* //图表系列的数据范围内都是相同的
|
||||
* type: "identical",
|
||||
* //数据集结果数据索引起始索引
|
||||
* start: 数值,
|
||||
* //可选,数据集结果数据索引结束索引,默认为start+1
|
||||
* end: 数值
|
||||
* }
|
||||
* 或者
|
||||
* {
|
||||
* //图表系列的数据范围内都是相同的
|
||||
* type: "identical",
|
||||
* //数据集结果数据索引值、值数组
|
||||
* value: 数值、[ 数值, ... ]
|
||||
* }
|
||||
* 或者
|
||||
* 数值,表示:{ type: "ordinal", start: 此数值 }
|
||||
*
|
||||
* 如果不设置,则默认为:{ type: "ordinal", start: 0 }
|
||||
*/
|
||||
chartSupport.setChartOriginalDataInfoRange = function(chart, seriesIndex, dataIndexStart, dataIndexEnd,
|
||||
chartDataSetIndex, resultDataIndexStart)
|
||||
chartSupport.setChartOriginalDataIndexForRange = function(chart, seriesIndex, dataIndexStart, dataIndexEnd,
|
||||
chartDataSetIndex, resultDataIndexInfo)
|
||||
{
|
||||
var originObj = chart.extValue("chartOriginalDataInfoRange");
|
||||
dataIndexEnd = (dataIndexEnd == null ? dataIndexStart+1 : dataIndexEnd);
|
||||
|
||||
if(resultDataIndexInfo == null)
|
||||
resultDataIndexInfo = { type: "ordinal", start: 0 };
|
||||
else if(typeof(resultDataIndexInfo) == "number")
|
||||
resultDataIndexInfo = { type: "ordinal", start: resultDataIndexInfo };
|
||||
|
||||
if(resultDataIndexInfo.type == "ordinal")
|
||||
{
|
||||
if(resultDataIndexInfo.start == null)
|
||||
resultDataIndexInfo.start = 0;
|
||||
}
|
||||
else if(resultDataIndexInfo.type == "identical")
|
||||
{
|
||||
if(resultDataIndexInfo.start != null)
|
||||
if(resultDataIndexInfo.end == null)
|
||||
resultDataIndexInfo.end = resultDataIndexInfo.start + 1;
|
||||
}
|
||||
else
|
||||
throw new Error("Unknown type ["+resultDataIndexInfo.type+"]");
|
||||
|
||||
var originObj = chart.extValue("chartOriginalDataIndexForRange");
|
||||
if(originObj == null)
|
||||
{
|
||||
originObj = {};
|
||||
chart.extValue("chartOriginalDataInfoRange", originObj);
|
||||
chart.extValue("chartOriginalDataIndexForRange", originObj);
|
||||
}
|
||||
|
||||
var ary = originObj[seriesIndex];
|
||||
|
@ -334,22 +430,25 @@
|
|||
originObj[seriesIndex] = ary;
|
||||
}
|
||||
|
||||
ary.push({ dataIndexStart: dataIndexStart, dataIndexEnd: dataIndexEnd,
|
||||
ary.push({
|
||||
dataIndexStart: dataIndexStart,
|
||||
dataIndexEnd: dataIndexEnd,
|
||||
chartDataSetIndex: chartDataSetIndex,
|
||||
resultDataIndexStart: (resultDataIndexStart == undefined ? 0 : resultDataIndexStart) });
|
||||
resultDataIndexInfo: resultDataIndexInfo
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取图表数据原始信息。
|
||||
* 获取图表特定系列的指定数据对应的原始数据索引对象。
|
||||
*
|
||||
* @param chart
|
||||
* @param seriesIndex 图表系列索引
|
||||
* @param dataIndex 图表系列数据索引
|
||||
* @return { chartDataSetIndex: ..., resultDataIndex: ... }、undefined
|
||||
* @param dataIndex 图表系列的数据索引
|
||||
* @return 参考setChartEventOriginalDataByIndex函数的originalDataIndex参数说明,可能返回undefined
|
||||
*/
|
||||
chartSupport.getChartOriginalDataInfoForRange = function(chart, seriesIndex, dataIndex)
|
||||
chartSupport.getChartOriginalDataIndexForRange = function(chart, seriesIndex, dataIndex)
|
||||
{
|
||||
var originObj = chart.extValue("chartOriginalDataInfoRange");
|
||||
var originObj = chart.extValue("chartOriginalDataIndexForRange");
|
||||
|
||||
if(!originObj)
|
||||
return undefined;
|
||||
|
@ -364,30 +463,45 @@
|
|||
var ele = ary[i];
|
||||
|
||||
if(ele.dataIndexStart <= dataIndex && ele.dataIndexEnd > dataIndex)
|
||||
return { chartDataSetIndex: ele.chartDataSetIndex, resultDataIndex: dataIndex - ele.dataIndexStart + ele.resultDataIndexStart };
|
||||
{
|
||||
var originalDataIndex=
|
||||
{
|
||||
chartDataSetIndex: ele.chartDataSetIndex
|
||||
};
|
||||
|
||||
var indexInfo = ele.resultDataIndexInfo;
|
||||
|
||||
if(indexInfo.type == "ordinal")
|
||||
{
|
||||
originalDataIndex.resultDataIndex = dataIndex - ele.dataIndexStart + indexInfo.start;
|
||||
}
|
||||
else if(indexInfo.type == "identical")
|
||||
{
|
||||
if(indexInfo.value != null)
|
||||
originalDataIndex.resultDataIndex = indexInfo.value;
|
||||
else
|
||||
originalDataIndex.resultDataIndex = { start: indexInfo.start , end: indexInfo.end };
|
||||
}
|
||||
else
|
||||
throw new Error("Unknown type ["+indexInfo.type+"]");
|
||||
|
||||
return originalDataIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* 清除图表数据范围的原始信息。
|
||||
* 清除图表所有数据范围对应的的原始数据索引对象。
|
||||
*
|
||||
* @param chart
|
||||
*/
|
||||
chartSupport.clearChartOriginalDataInfoRange = function(chart)
|
||||
chartSupport.clearChartOriginalDataIndexForRange = function(chart)
|
||||
{
|
||||
chart.extValue("chartOriginalDataInfoRange", null);
|
||||
chart.extValue("chartOriginalDataIndexForRange", null);
|
||||
};
|
||||
|
||||
chartSupport.getChartOriginalDataInfoForRangeEcharts = function(chart, echartsEventParams)
|
||||
{
|
||||
if(!echartsEventParams)
|
||||
return undefined;
|
||||
|
||||
return this.getChartOriginalDataInfoForRange(chart, echartsEventParams.seriesIndex, echartsEventParams.dataIndex);
|
||||
}
|
||||
|
||||
chartSupport.bindChartEventHandlerDelegationEcharts = function(chart, eventType, chartEventHanlder, chartEventDataSetter)
|
||||
{
|
||||
var echartsEventHandler = function(params)
|
||||
|
@ -419,36 +533,6 @@
|
|||
}
|
||||
};
|
||||
|
||||
chartSupport.setChartEventOriginalDataForEchartsRange = function(chart, chartEvent, echartsEventParams)
|
||||
{
|
||||
var originDataInfo = this.getChartOriginalDataInfoForRangeEcharts(chart, echartsEventParams);
|
||||
this.setChartEventOriginalDataByInfo(chart, chartEvent, originDataInfo);
|
||||
};
|
||||
|
||||
chartSupport.setChartEventOriginalDataForChartData = function(chart, chartEvent, chartData)
|
||||
{
|
||||
var originDataInfo = chartSupport.getChartOriginalDataInfo(chartData);
|
||||
this.setChartEventOriginalDataByInfo(chart, chartEvent, originDataInfo);
|
||||
};
|
||||
|
||||
chartSupport.setChartEventOriginalDataByInfo = function(chart, chartEvent, originDataInfo)
|
||||
{
|
||||
if(!originDataInfo)
|
||||
{
|
||||
chart.eventOriginalData(chartEvent, null);
|
||||
chart.eventOriginalChartDataSetIndex(chartEvent, null);
|
||||
chart.eventOriginalResultDataIndex(chartEvent, null);
|
||||
return;
|
||||
}
|
||||
|
||||
var resultDatas = chart.resultDatas(chart.resultAt(chart.getUpdateResults(), originDataInfo.chartDataSetIndex));
|
||||
var originalData = resultDatas[originDataInfo.resultDataIndex];
|
||||
|
||||
chart.eventOriginalData(chartEvent, originalData);
|
||||
chart.eventOriginalChartDataSetIndex(chartEvent, originDataInfo.chartDataSetIndex);
|
||||
chart.eventOriginalResultDataIndex(chartEvent, originDataInfo.resultDataIndex);
|
||||
};
|
||||
|
||||
//折线图
|
||||
|
||||
chartSupport.lineRender = function(chart, nameSign, valueSign, options)
|
||||
|
@ -507,7 +591,7 @@
|
|||
|
||||
var isCategory = (initOptions.xAxis.type == "category");
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var xAxisData = [];
|
||||
|
@ -540,7 +624,7 @@
|
|||
legendData.push(legendName);
|
||||
series.push(mySeries);
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, series.length-1, 0, data.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, series.length-1, 0, data.length, i);
|
||||
|
||||
//类目轴需要设置data,不然图表刷新数据有变化时,类目轴坐标不能自动更新
|
||||
if(isCategory)
|
||||
|
@ -668,7 +752,7 @@
|
|||
|
||||
var isCategory = ((horizontal ? initOptions.yAxis.type : initOptions.xAxis.type) == "category");
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var axisData = [];
|
||||
|
@ -700,7 +784,7 @@
|
|||
legendData.push(legendName);
|
||||
series.push(mySeries);
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, series.length-1, 0, data.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, series.length-1, 0, data.length, i);
|
||||
|
||||
//类目轴需要设置data,不然图表刷新数据有变化时,类目轴坐标不能自动更新
|
||||
if(isCategory)
|
||||
|
@ -810,7 +894,7 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var seriesName = "";
|
||||
|
@ -832,7 +916,7 @@
|
|||
seriesName = dataSetName;
|
||||
seriesData = seriesData.concat(nvv);
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, 0, seriesData.length - nvv.length, seriesData.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, 0, seriesData.length - nvv.length, seriesData.length, i);
|
||||
}
|
||||
|
||||
var series = [ chartSupport.optionsSeries(initOptions, 0, {name: seriesName, data: seriesData}) ];
|
||||
|
@ -913,7 +997,7 @@
|
|||
var chartDataSet = chart.chartDataSetFirst();
|
||||
var result = chart.resultFirst(results);
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var seriesName = chart.chartDataSetName(chartDataSet);
|
||||
|
||||
|
@ -927,7 +1011,7 @@
|
|||
|
||||
var seriesData = [ { value: value, name: chart.dataSetPropertyLabel(vp), min: min, max: max } ];
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, 0, 0, seriesData.length, 0);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, 0, 0, seriesData.length, 0);
|
||||
|
||||
var options = { series : [ { name: seriesName, min: min, max: max, data: seriesData } ]};
|
||||
|
||||
|
@ -1030,7 +1114,7 @@
|
|||
|
||||
var isCategory = (initOptions.xAxis.type == "category");
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var xAxisData = [];
|
||||
|
@ -1070,7 +1154,7 @@
|
|||
legendData.push(legendName);
|
||||
series.push(mySeries);
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, series.length-1, 0, data.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, series.length-1, 0, data.length, i);
|
||||
|
||||
//类目轴需要设置data,不然图表刷新数据有变化时,类目轴坐标不能自动更新
|
||||
if(isCategory)
|
||||
|
@ -1197,7 +1281,7 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var series = [];
|
||||
|
@ -1231,7 +1315,7 @@
|
|||
legendData.push(dataSetName);
|
||||
series.push(mySeries);
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, series.length-1, 0, data.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, series.length-1, 0, data.length, i);
|
||||
}
|
||||
|
||||
if(min != null && max != null && max <= min)
|
||||
|
@ -1387,11 +1471,11 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var indicatorData = [];
|
||||
var series = [];
|
||||
var seriesData = [];
|
||||
|
||||
for(var i=0; i<chartDataSets.length; i++)
|
||||
{
|
||||
|
@ -1400,46 +1484,109 @@
|
|||
var result = chart.resultAt(results, i);
|
||||
|
||||
var ip = chart.dataSetPropertyOfSign(chartDataSet, signNameMap.item);
|
||||
var iv = chart.resultColumnArrays(result, ip);
|
||||
legendData = legendData.concat(iv);
|
||||
|
||||
if(i == 0)
|
||||
//行式雷达网数据,必设置【雷达网条目名称】标记
|
||||
if(ip)
|
||||
{
|
||||
var dnp = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.name);
|
||||
var dnpv = chart.resultRowArrays(result, dnp, 0, 1);
|
||||
dnpv = (dnpv.length > 0 ? dnpv[0] : []);
|
||||
var dmp = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.max);
|
||||
var dmpv = chart.resultRowArrays(result, dmp, 0, 1);
|
||||
dmpv = (dmpv.length > 0 ? dmpv[0] : []);
|
||||
|
||||
var indicatorLen = Math.min(dnp.length, dmp.length);
|
||||
|
||||
for(var j=0; j<indicatorLen; j++)
|
||||
{
|
||||
var indicator = {name: dnpv[j], max: dmpv[j]};
|
||||
indicatorData[j] = indicator;
|
||||
}
|
||||
chartSupport.radarUpdateForRowData(chart, results, signNameMap, initOptions,
|
||||
chartDataSet, i, result, legendData, indicatorData, seriesData)
|
||||
}
|
||||
|
||||
var dvp = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.value);
|
||||
var dvpv = chart.resultRowArrays(result, dvp);
|
||||
|
||||
for(var j=0; j<iv.length; j++)
|
||||
//列式雷达网数据
|
||||
else
|
||||
{
|
||||
var seriesData = [ { name: iv[j], value: dvpv[j] } ];
|
||||
|
||||
series.push(chartSupport.optionsSeries(initOptions, i*iv.length+j, { data: seriesData }));
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, series.length-1, 0, seriesData.length, i, j);
|
||||
chartSupport.radarUpdateForColumnData(chart, results, signNameMap, initOptions,
|
||||
chartDataSet, i, result, legendData, indicatorData, seriesData)
|
||||
}
|
||||
}
|
||||
|
||||
var series = [ { data: seriesData } ];
|
||||
var options = { legend: {data: legendData}, radar: {indicator: indicatorData}, series: series };
|
||||
chart.echartsOptions(options);
|
||||
|
||||
chart.extValue("radarIndicatorData", indicatorData);
|
||||
};
|
||||
|
||||
//行式雷达网数据处理,一行数据表示一条雷达网,行式结构为:雷达网条目名称, [指标名, 指标值, 指标上限值]*n
|
||||
chartSupport.radarUpdateForRowData = function(chart, results, signNameMap, initOptions,
|
||||
chartDataSet, chartDataSetIdx, result, legendData, indicatorData, seriesData)
|
||||
{
|
||||
var ip = chart.dataSetPropertyOfSign(chartDataSet, signNameMap.item);
|
||||
var iv = chart.resultColumnArrays(result, ip);
|
||||
chartSupport.appendElement(legendData, iv);
|
||||
|
||||
//仅使用第一个数据集构建指示器
|
||||
if(chartDataSetIdx == 0)
|
||||
{
|
||||
var np = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.name);
|
||||
var npv = chart.resultRowArrays(result, np, 0, 1);
|
||||
npv = (npv.length > 0 ? npv[0] : []);
|
||||
|
||||
var mp = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.max);
|
||||
var mpv = chart.resultRowArrays(result, mp, 0, 1);
|
||||
mpv = (mpv.length > 0 ? mpv[0] : []);
|
||||
|
||||
var indicatorLen = Math.min(np.length, mp.length);
|
||||
|
||||
for(var j=0; j<indicatorLen; j++)
|
||||
{
|
||||
var indicator = {name: npv[j], max: mpv[j]};
|
||||
indicatorData.push(indicator);
|
||||
}
|
||||
}
|
||||
|
||||
var vp = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.value);
|
||||
var vpv = chart.resultRowArrays(result, vp);
|
||||
|
||||
for(var j=0; j<iv.length; j++)
|
||||
{
|
||||
var myData = { name: iv[j], value: vpv[j] };
|
||||
seriesData.push(myData);
|
||||
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, 0, seriesData.length-1, seriesData.length, chartDataSetIdx, j);
|
||||
}
|
||||
};
|
||||
|
||||
//列式雷达网数据处理,一列【指标值】数据表示一条雷达网,列式结构为:指标名, 指标上限值, [指标值]*n,其中【指标值】列名将作为雷达网条目名称
|
||||
chartSupport.radarUpdateForColumnData = function(chart, results, signNameMap, initOptions,
|
||||
chartDataSet, chartDataSetIdx, result, legendData, indicatorData, seriesData)
|
||||
{
|
||||
//仅使用第一个数据集构建指示器
|
||||
if(chartDataSetIdx == 0)
|
||||
{
|
||||
var np = chart.dataSetPropertyOfSign(chartDataSet, signNameMap.name);
|
||||
var nv = chart.resultColumnArrays(result, np);
|
||||
var mp = chart.dataSetPropertyOfSign(chartDataSet, signNameMap.max);
|
||||
var mv = chart.resultColumnArrays(result, mp);
|
||||
|
||||
var indicatorLen = Math.min(nv.length, mv.length);
|
||||
|
||||
for(var i=0; i<indicatorLen; i++)
|
||||
{
|
||||
var indicator = {name: nv[i], max: mv[i]};
|
||||
indicatorData.push(indicator);
|
||||
}
|
||||
}
|
||||
|
||||
var vp = chart.dataSetPropertiesOfSign(chartDataSet, signNameMap.value);
|
||||
var vv = chart.resultColumnArrays(result, vp);
|
||||
|
||||
for(var i=0; i<vv.length; i++)
|
||||
{
|
||||
var name = chart.dataSetPropertyLabel(vp[i]);
|
||||
chartSupport.appendElement(legendData, name);
|
||||
|
||||
var myData = { name: name, value: vv[i] };
|
||||
seriesData.push(myData);
|
||||
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, 0, seriesData.length-1, seriesData.length, chartDataSetIdx,
|
||||
{
|
||||
type: "identical",
|
||||
start: 0,
|
||||
end: indicatorData.length//所有行数据
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
chartSupport.radarResize = function(chart)
|
||||
{
|
||||
chartSupport.resizeChartEcharts(chart);
|
||||
|
@ -1540,7 +1687,7 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var seriesName = "";
|
||||
|
@ -1564,7 +1711,7 @@
|
|||
seriesName = dataSetName;
|
||||
seriesData = seriesData.concat(nvv);
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, 0, seriesData.length - nvv.length, seriesData.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, 0, seriesData.length - nvv.length, seriesData.length, i);
|
||||
}
|
||||
|
||||
for(var i=0; i<seriesData.length; i++)
|
||||
|
@ -1664,11 +1811,12 @@
|
|||
map = (updateOptions.geo ? updateOptions.geo.map : undefined);
|
||||
else
|
||||
map = (updateOptions.series && updateOptions.series.length > 0 ? updateOptions.series[0].map : undefined);
|
||||
|
||||
var presetMap = chart.extValue("presetMap");
|
||||
|
||||
if(!map)
|
||||
{
|
||||
var currentMap = chart.map();
|
||||
var presetMap = chart.extValue("presetMap");
|
||||
|
||||
//通过chart.map(...)设置了新的地图
|
||||
if(currentMap && currentMap != presetMap)
|
||||
|
@ -1694,6 +1842,21 @@
|
|||
}
|
||||
}
|
||||
|
||||
//如果更新了地图,则要重置缩放比例和中心位置,避免出现某些地图无法显示的情况
|
||||
if(map && map != presetMap)
|
||||
{
|
||||
if(isGeo)
|
||||
{
|
||||
updateOptions.geo.center = null;
|
||||
updateOptions.geo.zoom = 1;//此项非必须
|
||||
}
|
||||
else
|
||||
{
|
||||
updateOptions.series[0].center = null;
|
||||
updateOptions.series[0].zoom = 1;//此项非必须
|
||||
}
|
||||
}
|
||||
|
||||
//没有更新地图、或者更新的地图已注册
|
||||
if(!map || chart.echartsMapRegistered(map))
|
||||
{
|
||||
|
@ -1763,7 +1926,7 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var min = undefined;
|
||||
var max = undefined;
|
||||
|
@ -1797,7 +1960,7 @@
|
|||
|
||||
seriesData = seriesData.concat(nvv);
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, 0, seriesData.length - nvv.length, seriesData.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, 0, seriesData.length - nvv.length, seriesData.length, i);
|
||||
|
||||
if(nvv && nvv.length)
|
||||
{
|
||||
|
@ -1910,7 +2073,7 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var series = [];
|
||||
|
@ -1958,7 +2121,7 @@
|
|||
legendData[i] = dataSetName;
|
||||
series[i] = chartSupport.optionsSeries(initOptions, i, { name: dataSetName, data: data });
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, series.length-1, 0, data.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, series.length-1, 0, data.length, i);
|
||||
}
|
||||
|
||||
if(min != null && max != null && max <= min)
|
||||
|
@ -2080,7 +2243,7 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var seriesName = "";
|
||||
|
@ -2183,7 +2346,7 @@
|
|||
//新插入
|
||||
if(sidx == seriesData.length - 1 && seriesData[seriesData.length - 1] === sd)
|
||||
{
|
||||
chartSupport.setChartOriginalDataInfo(sd, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(sd, i, j);
|
||||
}
|
||||
|
||||
var tidx = chartSupport.appendDistinct(seriesData, td, (tip ? "id" : "name"));
|
||||
|
@ -2191,7 +2354,7 @@
|
|||
//新插入
|
||||
if(tidx == seriesData.length - 1 && seriesData[seriesData.length - 1] === td)
|
||||
{
|
||||
chartSupport.setChartOriginalDataInfo(td, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(td, i, j);
|
||||
}
|
||||
|
||||
//如果使用id值表示关系,对于数值型id,echarts会误当做数据索引,所以这里直接使用数据索引
|
||||
|
@ -2199,7 +2362,7 @@
|
|||
link.source = sidx;
|
||||
link.target = tidx;
|
||||
|
||||
chartSupport.setChartOriginalDataInfo(link, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(link, i, j);
|
||||
|
||||
seriesLinks.push(link);
|
||||
}
|
||||
|
@ -2364,7 +2527,7 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var legendData = [];
|
||||
var series = [];
|
||||
|
@ -2383,7 +2546,8 @@
|
|||
chart.dataSetPropertyOfSign(chartDataSet, signNameMap.max)
|
||||
]);
|
||||
|
||||
chartSupport.setChartOriginalDataInfo(data, i);
|
||||
for(var j=0; j<data.length; j++)
|
||||
chartSupport.chartDataOriginalDataIndex(data[j], i, j);
|
||||
|
||||
series.push(chartSupport.optionsSeries(initOptions, i, {name: dataSetName, data: data}));
|
||||
}
|
||||
|
@ -2509,7 +2673,7 @@
|
|||
var initOptions= chartSupport.initOptions(chart);
|
||||
var chartDataSets = chart.chartDataSetsNonNull();
|
||||
|
||||
chartSupport.clearChartOriginalDataInfoRange(chart);
|
||||
chartSupport.clearChartOriginalDataIndexForRange(chart);
|
||||
|
||||
var xAxisData = [];
|
||||
var yAxisData = [];
|
||||
|
@ -2543,7 +2707,7 @@
|
|||
|
||||
seriesData = seriesData.concat(data);
|
||||
|
||||
chartSupport.setChartOriginalDataInfoRange(chart, 0, seriesData.length - data.length, seriesData.length, i);
|
||||
chartSupport.setChartOriginalDataIndexForRange(chart, 0, seriesData.length - data.length, seriesData.length, i);
|
||||
}
|
||||
|
||||
if(min == undefined)
|
||||
|
@ -2897,7 +3061,7 @@
|
|||
chartSupport.treeNodeEvalValueMark(node);
|
||||
}
|
||||
|
||||
chartSupport.setChartOriginalDataInfo(node, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(node, i, j);
|
||||
|
||||
var added = false;
|
||||
for(var k=0; k<seriesData.length; k++)
|
||||
|
@ -3065,14 +3229,14 @@
|
|||
if(tvp)
|
||||
td.value = chart.resultRowCell(data[j], tvp);
|
||||
|
||||
chartSupport.setChartOriginalDataInfo(sd, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(sd, i, j);
|
||||
|
||||
var sidx = chartSupport.appendDistinct(seriesData, sd, "name");
|
||||
|
||||
//新插入
|
||||
if(sidx == seriesData.length - 1 && seriesData[seriesData.length - 1] === sd)
|
||||
{
|
||||
chartSupport.setChartOriginalDataInfo(sd, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(sd, i, j);
|
||||
}
|
||||
|
||||
var tidx = chartSupport.appendDistinct(seriesData, td, "name");
|
||||
|
@ -3080,7 +3244,7 @@
|
|||
//新插入
|
||||
if(tidx == seriesData.length - 1 && seriesData[seriesData.length - 1] === td)
|
||||
{
|
||||
chartSupport.setChartOriginalDataInfo(td, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(td, i, j);
|
||||
}
|
||||
|
||||
var link = {};
|
||||
|
@ -3091,7 +3255,7 @@
|
|||
link._sourceIndex = sidx;
|
||||
link._targetIndex = tidx;
|
||||
|
||||
chartSupport.setChartOriginalDataInfo(link, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(link, i, j);
|
||||
|
||||
seriesLinks.push(link);
|
||||
}
|
||||
|
@ -3305,7 +3469,7 @@
|
|||
//新插入
|
||||
if(sidx == seriesData.length - 1 && seriesData[seriesData.length - 1] === sd)
|
||||
{
|
||||
chartSupport.setChartOriginalDataInfo(sd, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(sd, i, j);
|
||||
}
|
||||
|
||||
var tidx = chartSupport.appendDistinct(seriesData, td, (tip ? "id" : "name"));
|
||||
|
@ -3313,7 +3477,7 @@
|
|||
//新插入
|
||||
if(tidx == seriesData.length - 1 && seriesData[seriesData.length - 1] === td)
|
||||
{
|
||||
chartSupport.setChartOriginalDataInfo(td, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(td, i, j);
|
||||
}
|
||||
|
||||
//如果使用id值表示关系,对于数值型id,echarts会误当做数据索引,所以这里直接使用数据索引
|
||||
|
@ -3324,7 +3488,7 @@
|
|||
if(vp)
|
||||
link.value = chart.resultRowCell(data[j], vp);
|
||||
|
||||
chartSupport.setChartOriginalDataInfo(link, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(link, i, j);
|
||||
|
||||
seriesLinks.push(link);
|
||||
}
|
||||
|
@ -3541,10 +3705,10 @@
|
|||
{
|
||||
min = (min == undefined ? data[j].value : Math.min(min, data[j].value));
|
||||
max = (max == undefined ? data[j].value : Math.max(max, data[j].value));
|
||||
|
||||
chartSupport.chartDataOriginalDataIndex(data[j], i, j);
|
||||
}
|
||||
|
||||
chartSupport.setChartOriginalDataInfo(data, i);
|
||||
|
||||
seriesData = seriesData.concat(data);
|
||||
}
|
||||
|
||||
|
@ -3663,9 +3827,9 @@
|
|||
}
|
||||
},
|
||||
//单元格内容渲染函数
|
||||
renderValue: function(value, type, row, meta)
|
||||
renderValue: function(value, name, rowIndex, columnIndex, row, meta)
|
||||
{
|
||||
return value;
|
||||
return chartFactory.escapeHtml(value);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -3810,7 +3974,7 @@
|
|||
for(var j=0; j<resultDatas.length; j++)
|
||||
{
|
||||
var data = $.extend({}, resultDatas[j]);
|
||||
chartSupport.setChartOriginalDataInfo(data, i, j);
|
||||
chartSupport.chartDataOriginalDataIndex(data, i, j);
|
||||
datas.push(data);
|
||||
}
|
||||
}
|
||||
|
@ -3862,7 +4026,7 @@
|
|||
var dataTable = chartSupport.tableGetChartDataTable(chart);
|
||||
|
||||
var chartData = dataTable.row(rowElement).data();
|
||||
var originalDataInfo = chartSupport.getChartOriginalDataInfo(chartData);
|
||||
var originalDataInfo = chartSupport.chartDataOriginalDataIndex(chartData);
|
||||
|
||||
var data = {};
|
||||
|
||||
|
@ -3878,7 +4042,7 @@
|
|||
}
|
||||
|
||||
chart.eventData(chartEvent, data);
|
||||
chartSupport.setChartEventOriginalDataByInfo(chart, chartEvent, originalDataInfo);
|
||||
chartSupport.setChartEventOriginalDataByIndex(chart, chartEvent, originalDataInfo);
|
||||
};
|
||||
|
||||
chartSupport.tableChartEventDelegationEventBinder =
|
||||
|
@ -4039,7 +4203,7 @@
|
|||
$label.removeClass("dg-chart-label-item-pending");
|
||||
|
||||
$label.data("_dgChartLabelChartData", { name: name, value: value });
|
||||
chartSupport.chartOriginalDataInfoHtml($label, i, j);
|
||||
chartSupport.domOriginalDataIndex($label, i, j);
|
||||
|
||||
var $labelName = $(".label-name", $label);
|
||||
var $labelValue = $(".label-value", $label);
|
||||
|
@ -4115,7 +4279,7 @@
|
|||
{
|
||||
var signNameMap = chartSupport.chartSignNameMap(chart);
|
||||
|
||||
var originalDataInfo = chartSupport.chartOriginalDataInfoHtml($label);
|
||||
var originalDataInfo = chartSupport.domOriginalDataIndex($label);
|
||||
var chartData = $label.data("_dgChartLabelChartData");
|
||||
|
||||
var data = {};
|
||||
|
@ -4127,7 +4291,7 @@
|
|||
}
|
||||
|
||||
chart.eventData(chartEvent, data);
|
||||
chartSupport.setChartEventOriginalDataByInfo(chart, chartEvent, originalDataInfo);
|
||||
chartSupport.setChartEventOriginalDataByIndex(chart, chartEvent, originalDataInfo);
|
||||
};
|
||||
|
||||
chartSupport.labelChartEventDelegationEventBinder =
|
||||
|
|
|
@ -206,6 +206,44 @@
|
|||
webContext: "webContext"
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取对象的指定属性路径的值。
|
||||
*
|
||||
* @param obj
|
||||
* @param propertyPath 属性路径,示例:order、order.product、[0].name、order['product'].name
|
||||
* @return 属性路径值,属性路径不存在则返回undefined
|
||||
*/
|
||||
dashboardFactory.getPropertyPathValue = function(obj, propertyPath)
|
||||
{
|
||||
if(obj == null)
|
||||
return undefined;
|
||||
|
||||
var value = undefined;
|
||||
|
||||
//简单属性值
|
||||
value = obj[propertyPath];
|
||||
|
||||
if(value !== undefined)
|
||||
return value;
|
||||
|
||||
//构建eval表达式
|
||||
if(propertyPath.charAt(0) == '[')
|
||||
propertyPath = "obj" + propertyPath;
|
||||
else
|
||||
propertyPath = "obj." + propertyPath;
|
||||
|
||||
try
|
||||
{
|
||||
value = eval(propertyPath);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
value = undefined;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
//----------------------------------------
|
||||
// chartBaseExt start
|
||||
//----------------------------------------
|
||||
|
@ -382,9 +420,10 @@
|
|||
originalData: this.eventOriginalData(chartEvent),
|
||||
getValue: function(name)
|
||||
{
|
||||
var val = this.data[name];
|
||||
//需支持属性路径格式的name
|
||||
var val = dashboardFactory.getPropertyPathValue(this.data, name);
|
||||
if(val === undefined && this.originalData != null)
|
||||
val = this.originalData[name];
|
||||
val = dashboardFactory.getPropertyPathValue(this.originalData, name);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -1326,6 +1365,8 @@
|
|||
* }
|
||||
* }
|
||||
*
|
||||
* 上述【源参数名】可以是简单参数名,例如:"name"、"value",也可以是源参数对象的属性路径,例如:"order.name"、"[0].name"、"['order'].product.name"
|
||||
*
|
||||
* 图表数据集参数索引对象用于确定源参数值要设置到的目标图表数据集参数,格式为:
|
||||
* {
|
||||
* //可选,目标图表在批量设置对象的target数组中的索引数值,默认为:0
|
||||
|
@ -1344,7 +1385,7 @@
|
|||
* }
|
||||
* 或者,可简写为上述图表数据集参数索引对象的"param"属性值
|
||||
*
|
||||
* @param sourceData 源参数值对象,格式为:{ 源参数名 : 源参数值, ...} 或者 { getValue: function(name){ return ...; } }
|
||||
* @param sourceData 源参数值对象,格式为:{ 源参数名 : 源参数值, ...} 或者 { getValue: function(name){ return ...; } }(需支持属性路径)
|
||||
* @param batchSet 批量设置对象
|
||||
* @param sourceValueContext 可选,传递给图表数据集参数索引对象的value函数sourceValueContext参数的对象,如果为数组,则传递多个参数,默认为sourceData
|
||||
* @return 批量设置的图表对象数组
|
||||
|
@ -1367,7 +1408,8 @@
|
|||
|
||||
for(var name in map)
|
||||
{
|
||||
var dataValue = (hasGetValueFunc ? sourceData.getValue(name) : sourceData[name]);
|
||||
var dataValue = (hasGetValueFunc ? sourceData.getValue(name)
|
||||
: dashboardFactory.getPropertyPathValue(sourceData, name));
|
||||
|
||||
var indexes = map[name];
|
||||
if(!$.isArray(indexes))
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -246,4 +246,15 @@ table.dataTable.display tbody > tr > .selected:hover {
|
|||
background-color: #f99117;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
/**年份选择器确定按钮*/
|
||||
.xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year{
|
||||
color: #eeeeee !important;
|
||||
border: 1px solid #666666 !important;
|
||||
background: #555555 !important;
|
||||
}
|
||||
.xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year:hover{
|
||||
color: #ffffff !important;
|
||||
border: 1px solid #59b4d4 !important;
|
||||
background: #0078a3 !important;
|
||||
}
|
|
@ -246,4 +246,15 @@ table.dataTable.display tbody > tr > .selected:hover {
|
|||
background: #59c908;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
/**年份选择器确定按钮*/
|
||||
.xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year{
|
||||
color: #ffffff !important;
|
||||
border: 1px solid #45930b !important;
|
||||
background: #3c8009 !important;
|
||||
}
|
||||
.xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year:hover{
|
||||
color: #ffffff !important;
|
||||
border: 1px solid #6cc510 !important;
|
||||
background: #459e05 !important;
|
||||
}
|
|
@ -246,4 +246,15 @@ table.dataTable.display tbody > tr > .selected:hover {
|
|||
background-color: #007FFF;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
/**年份选择器确定按钮*/
|
||||
.xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year{
|
||||
color: #454545 !important;
|
||||
border: 1px solid #c5c5c5 !important;
|
||||
background: #f6f6f6 !important;
|
||||
}
|
||||
.xdsoft_datetimepicker .xdsoft_save_selected.xdsoft_save_selected_year:hover{
|
||||
color: #2b2b2b !important;
|
||||
border: 1px solid #cccccc !important;
|
||||
background: #ededed !important;
|
||||
}
|
|
@ -41,7 +41,9 @@ readonly 是否只读操作,允许为null
|
|||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item-label">
|
||||
<label><@spring.message code='chart.chartDataSets' /></label>
|
||||
<label title="<@spring.message code='chart.chartDataSets.desc' />">
|
||||
<@spring.message code='chart.chartDataSets' />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-item-value form-item-value-chartDataSet">
|
||||
<input type="text" name="dataSignValidation" style="display: none" />
|
||||
|
@ -64,7 +66,9 @@ readonly 是否只读操作,允许为null
|
|||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item-label">
|
||||
<label><@spring.message code='chart.updateInterval' /></label>
|
||||
<label title="<@spring.message code='chart.updateInterval.desc' />">
|
||||
<@spring.message code='chart.updateInterval' />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-item-value">
|
||||
<div class="updateInterval-radios">
|
||||
|
|
|
@ -132,7 +132,7 @@ readonly 是否只读操作,允许为null
|
|||
{
|
||||
return "${contextPath}/analysis/dashboard/" + action;
|
||||
};
|
||||
|
||||
|
||||
po.getLastTagText = function(text)
|
||||
{
|
||||
if(!text)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue