# 数据源开发
# 一、数据格式
暂时支持7种数据格式,其中“个人信息”可以不用配置数据源自动获取当前登陆人的信息,如下表:
数据格式 | 数据编码 | 数据版本 | 说明 |
---|---|---|---|
指标 | 1 | V1 | 统计值(max, min, sum, count) |
快捷入口 | 2 | V1 | |
菜单 | 3 | V1 | |
列表 | 4 | V1 | |
统计列表 | 5 | V1 | |
个人信息 | 6 | V1 | 暂时不支持数据源配置,自动获取当前登陆人信息 |
业务导图 | 7 | V1 | 暂时不支持移动端 |
# 二、数据源类图
# 三、数据源主要API介绍
3.1 名词说明
名称 | 说明 |
---|---|
数据源 | 可等同理解为java.sql.DataSource |
数据集 | 可等同数据库表 |
数据结果 | 可等同理解为“select * from T where a=1”的查询结果 |
3.2 AbstractDataSourceProvider:数据源连接基础封装
方法 | 说明 |
---|---|
DataFormat dataFormat() | 指定数据格式,具体参考DataFormat |
String uuid() | 数据连接唯一码, 可以使用Online UUID Generator (opens new window)在线生成 |
DataSetList getDataSetList(ContextParam contextParam, String[] versions) | 返回数据集的列表,用户可以以此进行数据源绑定 |
isAllow(ContextParam contextParam, DataSetMetadata metadata, Command command) | 判断用户是否有权限访问 |
DataSetResult executeQuery(ContextParam contextParam, DataSetMetadata metadata, String[] versions, Command command) | 获取查询结果 |
::: demo
/**
* @Title: 数据源连接基础封装
* @Description:
* @Company: seeyon.com
* @Team: Seeyon CAP4
* @Date: 2019-06-03 13:36
*/
public abstract class AbstractDataSourceProvider implements InvokeHandler, SortOrderable {
/**
* 数据格式
*
* @return
*/
public abstract DataFormat dataFormat();
/**
* 数据版本
*
* @return
*/
public String[] versions() {
return new String[]{BizPortalConstants.Version.V1.name()};
}
/**
* 数据连接唯一码, 可以使用https://www.uuidgenerator.net/version1在线生成
*
* @return
*/
public abstract String uuid();
/**
* 数据连接名称
*
* @return
*/
public abstract String name();
/**
* 获取数据集列表
*
* @param contextParam
* @param versions
* @return
* @throws BusinessException
*/
public abstract DataSetList getDataSetList(ContextParam contextParam, String[] versions) throws BusinessException;
/**
* 判断是否有权限
*
* @param contextParam
* @param metadata
* @param command
* @return
* @throws BusinessException
*/
public abstract boolean isAllow(ContextParam contextParam, DataSetMetadata metadata, Command command) throws BusinessException;
/**
* 获取数据实际id
*
* @param metadata
* @param k
* @return
* @throws BusinessException
*/
protected Long attrRealLong(Command command, DataSetMetadata metadata, String k) throws BusinessException {
return metadata.attrLong(k);
}
}
:::
3.3 DataSetList:数据集列表
暂时只支持树形结构返回,对应实现类DefaultDataSetList,在使用DefaultDataSetList的时候请确保叶子节点是可绑定的数据集,并设置上metadata属性.
::: demo
/**
* @Title:默认数据集结果
* @Description:
* @Company: seeyon.com
* @Team: Seeyon CAP4
* @Date: 2019-06-03 14:26
*/
public class DefaultDataSetList implements DataSetList {
/**
* 节点列表
*/
private List<Node> list = new ArrayList<Node>();
public List<Node> getList() {
return list;
}
/**
* 添加节点
*
* @param node
*/
public void addNode(Node node) {
list.add(node);
}
/**
* 创建根节点
*
* @param id
* @param name
* @return
*/
public Node createBranchNode(String id, String name) {
Node node = new Node();
node.id = id;
node.name = name;
node.branch = true;
node.parentId = "0";
return node;
}
/**
* 创建枝干节点
*
* @param id
* @param name
* @param parentId
* @return
*/
public Node createBranchNode(String id, String name, String parentId) {
Node node = new Node();
node.id = id;
node.name = name;
node.branch = true;
node.parentId = parentId;
return node;
}
/**
* 创建叶子节点
*
* @param id
* @param name
* @param parentId
* @return
*/
public Node createLeafNode(String id, String name, String parentId) {
Node node = new Node();
node.id = id;
node.name = name;
node.fillName = name;
node.fullName = name;
node.branch = false;
node.parentId = parentId;
return node;
}
/**
* 创建叶子节点
*
* @param id
* @param name
* @param parentId
* @param dataSetMetadata
* @return
*/
public Node createLeafNode(String id, String name, String parentId, DataSetMetadata dataSetMetadata) {
Node node = new Node();
node.id = id;
node.name = name;
node.fillName = name;
node.fullName = name;
node.branch = false;
node.parentId = parentId;
node.metadata = dataSetMetadata;
return node;
}
/**
* 创建叶子节点
*
* @param id
* @param name
* @param parentId
* @param dataSetMetadata
* @return
*/
public Node createLeafNode(String id, String name, String fullName, String parentId, DataSetMetadata dataSetMetadata) {
Node node = new Node();
node.id = id;
node.name = name;
node.fillName = name;
node.fullName = fullName;
node.branch = false;
node.parentId = parentId;
node.metadata = dataSetMetadata;
return node;
}
/**
* 创建叶子节点
*
* @param id
* @param name
* @param parentId
* @param dataSetMetadata
* @return
*/
public Node createLeafNode(String id, String name, String fullName, String fillName, String parentId, DataSetMetadata dataSetMetadata) {
Node node = new Node();
node.id = id;
node.name = name;
node.fillName = fillName;
node.fullName = fullName;
node.branch = false;
node.parentId = parentId;
node.metadata = dataSetMetadata;
return node;
}
/**
* 判断是否有子节点
*
* @param id
* @return
*/
public boolean existChildren(String id) {
for (Node node : list) {
if (StringUtils.equals(id, node.parentId)) {
return true;
}
}
return false;
}
/**
* 数据节点
*/
public static class Node implements Serializable {
/**
* 节点Id
*/
private String id;
/**
* 名称
*/
private String name;
/**
* 回填名称
*/
private String fillName;
/**
* 完整名称
*/
private String fullName;
/**
* 上级节点
*/
private String parentId;
/**
* 是否枝干节点
*/
private boolean branch;
/**
* 元信息
*/
private DataSetMetadata metadata;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFillName() {
return fillName;
}
public void setFillName(String fillName) {
this.fillName = fillName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public boolean isBranch() {
return branch;
}
public void setBranch(boolean branch) {
this.branch = branch;
}
public DataSetMetadata getMetadata() {
return metadata;
}
public void setMetadata(DataSetMetadata metadata) {
this.metadata = metadata;
}
}
}
:::
3.4 DataSetMetadata:数据集元信息
这里记录的数据集的标志信息,确保根据里面内容能反向查询到这个节点,并可以根据里面的内容做查询等操作。
::: demo
/**
* @Title: 数据集元信息
* @Description:
* @Company: seeyon.com
* @Team: Seeyon CAP4
* @Date: 2019-06-03 14:28
*/
public class DataSetMetadata implements Serializable {
/**
* 标志符
* 请与所对应的DataSourceProvider#uuid()保持一致
*/
private String uuid;
/**
* 数据集标志: 用于区分一个数据源中可以获得种数据集的时候判断
*/
private String sign;
/**
* 属性
*/
private Map<String, Object> attributes = new HashMap<String, Object>();
public DataSetMetadata() {
}
public DataSetMetadata(String uuid) {
this.uuid = uuid;
}
public DataSetMetadata(String uuid, String sign) {
this.uuid = uuid;
this.sign = sign;
}
/**
* 设置属性
*
* @param att
* @param val
* @return
*/
public DataSetMetadata attr(String att, Object val) {
attributes.put(att, val);
return this;
}
/**
* 获取属性
*
* @param att
* @return
*/
public Object attr(String att) {
return attributes.get(att);
}
/**
* 获取属性
*
* @param att
* @return
*/
public Long attrLong(String att) {
return MapUtils.getLong(attributes, att);
}
public Integer attrInt(String att) {
return MapUtils.getInteger(attributes, att);
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public Map<String, Object> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, Object> attributes) {
this.attributes = attributes;
}
}
:::
3.5 ContextParam:上下文参数封装
记录了当前用户,当前业务包Id,终端类型(PC还是移动端)信息。
3.6 Command:数据集操作命令
默认op=default,使用场景如下:a) 列表中查看详情;b) 列表中翻页;c) 数据返回和操作不满足客开场景,可以与栏目开发者“协商”好op值和参数格式,并在后端实现一个InvokeHander并注入到对应的数据源接口中即可。
invokeHandlerMap.put("default", new DefaultInvokeHandler());
invokeHandlerMap.put("viewDetail", new DefaultViewDetailInvokeHandler());
# 四、指标数据源开发
4.1 指标数据返回结果
::: demo
public class IndicatorDataSetResult implements DataSetResult {
@Override
public Integer getDataFormat() {
return DataFormat.INDICATOR.getCode();
}
@Override
public String getVersion() {
return Version.V1.name();
}
/**
* 原始值
*/
private Object source;
/**
* 显示值
*/
private Object value;
/**
* 字段类型
* @see FieldType#getKey()
*/
private String fieldType;
public Object getSource() {
return source;
}
public void setSource(Object realValue) {
this.source = realValue;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public String getFieldType() {
return fieldType;
}
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
}
:::
4.2 指标数据源开发参考示例
::: demo
public class DefaultReportIndicatorDataSourceProvider extends DefaultDataSourceProvider {
@Override
public int getSortOrder() {
return 0;
}
@Override
public BizPortalConstants.DataFormat dataFormat() {
return BizPortalConstants.DataFormat.INDICATOR;
}
@Override
public String uuid() {
return "ec18b5ba-2125-410c-89be-5429c53c5810";
}
@Override
public String name() {
return "应用报表指标";
}
@Override
public DefaultDataSetList getDataSetList(ContextParam contextParam, DataSetMetadata dataSetMetadata, String[] versions) throws BusinessException {
DefaultDataSetList dataSetList = new DefaultDataSetList();
BizConfigBean configBean = bizPortalExternAdapterManager.getBizConfigBean(getMultiStepId(dataSetMetadata));
Long bizId = configBean.getId();
// 根节点
DefaultDataSetList.Node rootNode = dataSetList.createBranchNode(bizId.toString(), name());
dataSetList.addNode(rootNode);
// 报表指标
List<ReportIndex> list = bizPortalReportAdapterManager.findReportIndex(ApplicationCategoryEnum.cap4biz.name(), bizId.toString());
if (CollectionUtils.isNotEmpty(list)) {
Multimap<Long, ReportIndex> multimap = Multimaps.index(list, new Function<ReportIndex, Long>() {
@Override
public Long apply(ReportIndex input) {
return input.getReportDesignId();
}
});
List<ReportDesignDefinition> reportConfigs = bizPortalReportAdapterManager.findReportDesignDefinition(Lists.newArrayList(multimap.keySet()));
for (ReportDesignDefinition definition : reportConfigs) {
DefaultDataSetList.Node configNode = dataSetList.createBranchNode(definition.getDesignId().toString(), definition.getTitle(), rootNode.getId());
dataSetList.addNode(configNode);
Function<String, String> fullNameFunction = getFullNameFunction(configBean, definition);
for (ReportIndex ri : multimap.get(definition.getDesignId())) {
// 这个地方非常关键,请务必将下次查询所需要的参数都放进去
DataSetMetadata metadata = new DataSetMetadata(uuid())
.attr(BIZ_ID, bizId)
.attr("designId", definition.getDesignId())
.attr("indexId", ri.getId());
dataSetList.addNode(dataSetList.createLeafNode(getNodeId(ri.getId()), ri.getTitle(), fullNameFunction.apply(ri.getTitle()), configNode.getId(), metadata));
}
}
}
return dataSetList;
}
/**
* 获取统计指标完整名
*
* @param bizConfigBean
* @param designDefinition
* @return
*/
private Function<String, String> getFullNameFunction(final BizConfigBean bizConfigBean, final ReportDesignDefinition designDefinition) {
return new Function<String, String>() {
@Override
public String apply(String input) {
return bizConfigBean.getName() + "-" + designDefinition.getTitle() + "-" + input;
}
};
}
@Override
public boolean isAllow(ContextParam contextParam, DataSetMetadata metadata, Command command) throws BusinessException {
return bizPortalReportAdapterManager.checkAuth(attrRealLong(command, metadata,"designId"), contextParam.getUserId());
}
@Override
public DataSetResult executeQuery(ContextParam contextParam, DataSetMetadata metadata, String[] versions, Command command) throws BusinessException {
// 查询指标结果,这个地方请注意设置fieldType和source和value,有的时候指标的显示需要用原始值
ReportIndexResult indexResult = bizPortalReportAdapterManager.getReportIndexResult(attrRealLong(command, metadata, "indexId"));
if (indexResult != null) {
IndicatorDataSetResult dataSetResult = new IndicatorDataSetResult();
dataSetResult.setFieldType(indexResult.getOriginalField().getDbType());
dataSetResult.setSource(indexResult.getRealValue());
dataSetResult.setValue(indexResult.getDisplay());
return dataSetResult;
}
return null;
}
// 如果要随业务包导出的化,请将所有会变的值全部以下面代码示例转换下
@Override
public DataSetMetadata beforeDataSetMetaBind(String dataId, DataSetMetadata metadata) throws BusinessException {
Long bizId = getBizId(metadata);
metadata.attr("designId", createBizPortalDataRelation(bizId, dataId, metadata.attrLong("designId")));
metadata.attr("indexId", createBizPortalDataRelation(bizId, dataId, metadata.attrLong("indexId")));
return metadata;
}
@Override
protected String getId(Command command, DataSetMetadata metadata) throws BusinessException {
return attrRealLong(command, metadata, "indexId").toString();
}
// fields
private BizPortalReportAdapterManager bizPortalReportAdapterManager;
// setters
public void setBizPortalReportAdapterManager(BizPortalReportAdapterManager bizPortalReportAdapterManager) {
this.bizPortalReportAdapterManager = bizPortalReportAdapterManager;
}
}
:::
# 五、快捷入口数据源开发
5.1 快捷入口数据返回结果
快捷入口返回的数据结果在PC端和移动端是有区别的:1. PC端根据返回URL的直接跳转;2.移动端是优先基于CMP的openAppByApi进行跳转,参数格式为{appId: 应用包Id, openApi : 跳转方法, params: 跳转参数}, 如果不能使用openAppByApi跳转时,则采用URL直接跳转.
5.1.1 PC端返回格式
::: demo
public class LinkDataSetResult implements DataSetResult {
@Override
public Integer getDataFormat() {
return DataFormat.LINK.getCode();
}
@Override
public String getVersion() {
return Version.V1.name();
}
public static LinkDataSetResult of(String href) {
LinkDataSetResult that = new LinkDataSetResult();
that.href = href;
return that;
}
/**
* 连接地址
*/
private String href;
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
}
:::
5.1.2 移动端返回格式
:::demo
public class MobileLinkDataSetResult extends LinkDataSetResult {
/**
* 应用包Id
*/
private String appId;
/**
* 跳转方法
*/
private String openApi;
/**
* 跳转参数
*/
private Map<String, ?> params;
public static MobileLinkDataSetResult of(String appId, String openApi, Map<String, ?> params) {
MobileLinkDataSetResult that = new MobileLinkDataSetResult();
that.appId = appId;
that.openApi = openApi;
that.params = params;
return that;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getOpenApi() {
return openApi;
}
public void setOpenApi(String openApi) {
this.openApi = openApi;
}
public Map<String, ?> getParams() {
return params;
}
public void setParams(Map<String, ?> params) {
this.params = params;
}
}
:::
5.1.2 快捷入口数据源开发参考示例
其他部分与指标数据源开发基本一致,以下代码是查看业务空间的快捷入口示例。
:::demo
@Override
public LinkDataSetResult viewBizPortalSpace(ContextParam contextParam, Long spaceId) throws BusinessException {
LinkDataSetResult dataSetResult;
if (isMobile(contextParam)) {
CAPPortalSpace portalSpace = bizPortalSpaceManager.getCAPPortalSpace(spaceId);
CAPPortalSpaceConfig spaceConfig = bizPortalSpaceManager.getBizPortalSpaceConfig(spaceId, BizPortalConstants.ConfigStatus.RUNNING);
Map<String, Long> map = ImmutableMap.of("bizId", portalSpace.getBizId(), "spaceId", spaceId, "configId", spaceConfig.getId());
// 注意点1:构建移动端openAppByApi的参数格式
dataSetResult = MobileLinkDataSetResult.of(getAppId(ApplicationCategoryEnum.cap4Form), "openBizInfoBySpaceId", map);
} else {
// 注意点2:构建出URL格式
dataSetResult = LinkDataSetResult.of(replaceURL(VIEW_BIZPORTAL_SPACE_PATTERN, ImmutableMap.of("spaceId", spaceId)));
}
return dataSetResult;
}
:::
# 六、列表数据源开发
列表数据源开发与前面数据源格式相比要复杂些,他支持分页获取数据,支持查看详情(如果数据源支持的话)。故命令对象在就至少存在两个:1. default: 默认列表;2. viewDetail:查看单条记录详情。
6.1 op=default:默认列表数据返回格式
:::demo
public class ListDataSetResult implements DataSetResult {
@Override
public Integer getDataFormat() {
return DataFormat.LIST.getCode();
}
@Override
public String getVersion() {
return Version.V1.name();
}
/**
* 列表数据结果
*/
private transient ListDataResult listDataResult;
public static ListDataSetResult of(ListDataResult listDataResult) {
ListDataSetResult that = new ListDataSetResult();
that.listDataResult = listDataResult;
return that;
}
public void setListDataResult(ListDataResult listDataResult) {
this.listDataResult = listDataResult;
}
public List<ListField> getFields() {
return listDataResult.getFields();
}
public List<ListRowData> getData() {
return listDataResult.getData();
}
public int getPage() {
return listDataResult.getPage();
}
public int getPages() {
return listDataResult.getPages();
}
public int getSize() {
return listDataResult.getSize();
}
public int getTotal() {
return listDataResult.getTotal();
}
public Date getExecuteTime (){
return listDataResult.getExecuteTime();
}
}
:::
这里最主要的是初始化出listDataResult这个列表对象,列表对象包含了(字段列表,数据结果,页码,总页数,每页显示数量,总体数,执行时间)等信息。
:::demo
public class ListDataResult implements Serializable {
/**
* id
*/
private String id;
/**
* 字段列表
*/
private List<ListField> fields = new ArrayList<ListField>();
/**
* 数据结果
*/
private List<ListRowData> data = new ArrayList<ListRowData>();
/**
* 页码
*/
private int page;
/**
* 总页数
*/
private int pages;
/**
* 每页数量
*/
private int size;
/**
* 总数
*/
private int total;
/**
* 执行时间
*/
private Date executeTime;
private volatile transient Map<String, String> indexCache;
public void addListField(ListField listField) {
fields.add(listField);
}
public ListRowData newListRowData() {
ListRowData listRowData = new ListRowData();
data.add(listRowData);
return listRowData;
}
public void putListRowData(ListRowData listRowData) {
data.add(listRowData);
}
/**
* 放数据
*
* @param rowData
* @param key
* @param data
*/
public void putListRowData(ListRowData rowData, String key, ListRowData.Data data) {
initIndexCache();
rowData.getData().put(indexCache.get(key), data);
}
/**
* 获取数据行中字段数据
*
* @param rowData
* @param listField
* @return
*/
public Data getData(ListRowData rowData, ListField listField) {
initIndexCache();
return rowData.getData().get(indexCache.get(listField.getKey()));
}
/**
* 初始化key-index对象
*/
private void initIndexCache() {
if (indexCache != null) {
return;
}
Map<String, String> map = Maps.newHashMapWithExpectedSize(fields.size());
for (int i = 0; i < fields.size(); i ++) {
map.put(fields.get(i).getKey(), String.valueOf(i));
}
indexCache = map;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<ListField> getFields() {
return fields;
}
public void setFields(List<ListField> fields) {
this.fields = fields;
}
public List<ListRowData> getData() {
return data;
}
public void setData(List<ListRowData> data) {
this.data = data;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public Date getExecuteTime() {
return executeTime;
}
public void setExecuteTime(Date executeTime) {
this.executeTime = executeTime;
}
}
/**
* @Title: 列表字段
* @Description:
* @Company: seeyon.com
* @Team: Seeyon CAP4
* @Date: 2019-06-11 14:31
*/
public class ListField implements Serializable {
/**
* 枚举ID
*/
public static String ENUM_ID = "enumId";
/**
* 枚举层级
*/
public static String ENUM_LEVEL = "enumLevel";
/**
* 是否末级枚举
*/
public static String IS_FINAL_CHILD= "isFinalChild";
/**
* 字段键值
*/
private String key;
/**
* 字段名称
*/
private String name;
/**
* 控件类型
* com.seeyon.ctp.form.bean.FormFieldComBean.FormFieldComEnum
* com.seeyon.ctp.report.engine.api.ReportConstants.FieldComType
*/
private String inputType;
/**
* 字段类型
* com.seeyon.cap4.form.util.Enums.FieldType
*/
private String fieldType;
/**
* 字段长度
*/
private String length;
/**
* 小数位
*/
private String digitNum = "0";
/**
* 其他属性
*/
private Map<String, Object> attributes = new HashMap<String, Object>();
/**
* 支持操作类型
* com.seeyon.ctp.report.bizportal.Action
*/
private List<String> actions = new ArrayList<String>();
/**
* 报表字段
*/
private transient DisplayField displayField;
/**
* 值对象
*/
private ListRowData.Data data;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInputType() {
return inputType;
}
public void setInputType(String inputType) {
this.inputType = inputType;
}
public String getFieldType() {
return fieldType;
}
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
public List<String> getActions() {
return actions;
}
public void setActions(List<String> actions) {
this.actions = actions;
}
public DisplayField getDisplayField() {
return displayField;
}
public void setDisplayField(DisplayField displayField) {
this.displayField = displayField;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public Long getEnumId() {
return (Long) attributes.get(ENUM_ID);
}
public void setEnumId(Long enumId) {
attr(ENUM_ID, enumId);
}
public Integer getEnumLevel() {
return MapUtils.getInteger(attributes, ENUM_LEVEL);
}
public void setEnumLevel(Integer enumLevel) {
attr(ENUM_LEVEL, enumLevel);
}
public Map<String, Object> getAttributes() {
return attributes;
}
public void attr(String key, Object value) {
this.attributes.put(key, value);
}
public void attr(Map<String, Object> map) {
this.attributes.putAll(map);
}
public Boolean getFinalChild() {
return (Boolean) attributes.get(IS_FINAL_CHILD);
}
public void setFinalChild(Boolean finalChild) {
attr(IS_FINAL_CHILD, finalChild);
}
public String getLength() {
return length;
}
public void setLength(String length) {
this.length = length;
}
public String getDigitNum() {
return digitNum;
}
public void setDigitNum(String digitNum) {
this.digitNum = digitNum;
}
}
/**
* @Title: 列表行数据封装
* @Description:
* @Company: seeyon.com
* @Team: Seeyon CAP4
* @Date: 2019-06-11 14:38
*/
public class ListRowData implements Serializable {
/**
* 数据对象
*/
private Map<String, Data> data = new HashMap<String, Data>();
/**
* 行标志符
*/
private String identifier;
/**
* 行号
*/
private int lineNo;
/**
* 支持操作类型
*/
private List<String> actions = new ArrayList<String>();
public Map<String, Data> getData() {
return data;
}
public void setData(Map<String, Data> data) {
this.data = data;
}
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public List<String> getActions() {
return actions;
}
public void setActions(List<String> actions) {
this.actions = actions;
}
public int getLineNo() {
return lineNo;
}
public void setLineNo(int lineNo) {
this.lineNo = lineNo;
}
/**
* 数据结果封装
*/
public static class Data implements Serializable {
/**
* 原始值
*/
private Object s;
/**
* 显示值
*/
private Object v;
public Data() {
}
public Data(Object value) {
this.v = value;
}
public Data(Object sValue, Object value) {
this.s = sValue;
this.v = value;
}
public Object getS() {
return s;
}
public Object getV() {
return v;
}
}
}
:::
6.2 op=viewDetail:查看记录的详情信息
是否支持viewDetail不是必须的,由op=default列表中ListRowData#actions中是否包含“viewDetail”决定,如果某一行支持查看详情,则必须同时设置ListRowData#identifier属性(在获取查看详情链接的时候会带上identified来作为标志用户查看哪一行的详情)。查看详情的数据结果请求返回的是一个多快捷入口返回格式(有i与单一行可能是由多个信息主体关联而成),格式如下:
:::demo
/**
* @Title: 多超链接返回结果
* @Description: 针对查询和统计一条数据有多个返回链接
* @Company: seeyon.com
* @Team: ouyp Seeyon CAP4
* @Date: 2019/8/28 20:29
*/
public class MultiLinkDataSetResult implements DataSetResult {
@Override
public Integer getDataFormat() {
return BizPortalConstants.DataFormat.LINK.getCode();
}
@Override
public String getVersion() {
return BizPortalConstants.Version.V1.name();
}
public static MultiLinkDataSetResult of(LinkDataSetResult link) {
MultiLinkDataSetResult that = new MultiLinkDataSetResult();
that.links.add(create(link));
return that;
}
public static MultiLinkDataSetResult of(String href) {
return of(LinkDataSetResult.of(href));
}
public static WithLabelLinkDataSet create(LinkDataSetResult linkDataSetResult, String label) {
WithLabelLinkDataSet withLabelLinkDataSet = new WithLabelLinkDataSet();
BizPortalUtils.copyProperties(withLabelLinkDataSet, linkDataSetResult);
withLabelLinkDataSet.label = label;
return withLabelLinkDataSet;
}
public static WithLabelLinkDataSet create(LinkDataSetResult linkDataSetResult) {
return create(linkDataSetResult, StringUtils.EMPTY);
}
/**
* 超链接列表
*/
private List<WithLabelLinkDataSet> links = Lists.newArrayList();
public List<WithLabelLinkDataSet> getLinks() {
return links;
}
public void setLinks(List<WithLabelLinkDataSet> links) {
this.links = links;
}
public static class WithLabelLinkDataSet extends MobileLinkDataSetResult {
private String label;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}
}
:::
6.3 列表数据源开发参考示例
:::demo
/**
* @Title: 数据源连接——列表
* @Description: 应用报表
* @Company: seeyon.com
* @Team: Seeyon CAP4
* @Date: 2019-06-06 10:25
*/
public class DefaultReportListDataSourceProvider extends DefaultDataSourceProvider implements InitializingBean {
// fields
private Map<String, InvokeHandler> invokeHandlerMap = Maps.newHashMap();
private BizPortalReportAdapterManager bizPortalReportAdapterManager;
//setter
public void setInvokeHandlerMap(Map<String, InvokeHandler> invokeHandlerMap) {
this.invokeHandlerMap = invokeHandlerMap;
}
public void setBizPortalReportAdapterManager(BizPortalReportAdapterManager bizPortalReportAdapterManager) {
this.bizPortalReportAdapterManager = bizPortalReportAdapterManager;
}
@Override
public void afterPropertiesSet() throws Exception {
// 注意1: 注入标志产品支持的操作方式,如客开添加其他命令,可以在spring配置文件中设置invokeHandlerMap达到功能增强
invokeHandlerMap.put("default", new DefaultInvokeHandler());
invokeHandlerMap.put("viewDetail", new DefaultViewDetailInvokeHandler());
}
@Override
public BizPortalConstants.DataFormat dataFormat() {
return BizPortalConstants.DataFormat.LIST;
}
@Override
public int getSortOrder() {
return 1;
}
@Override
public String uuid() {
return "56abc264-6cd6-48a8-8967-96b1fd89f2d3";
}
@Override
public String name() {
return "应用报表";
}
@Override
public DefaultDataSetList getDataSetList(ContextParam contextParam, DataSetMetadata dataSetMetadata, String[] versions) throws BusinessException {
DefaultDataSetList dataSetList = new DefaultDataSetList();
BizConfigBean configBean = bizPortalExternAdapterManager.getBizConfigBean(getMultiStepId(dataSetMetadata));
Long bizId = configBean.getId();
// 根节点
DefaultDataSetList.Node rootNode = dataSetList.createBranchNode(bizId.toString(), name());
dataSetList.addNode(rootNode);
// 查询列表
List<ReportDesignDefinition> reportConfigs = bizPortalReportAdapterManager.findReportDesignDefinition(ApplicationCategoryEnum.cap4biz.name(), bizId.toString(), DesignType.QUERY);
if (CollectionUtils.isNotEmpty(reportConfigs)) {
for (ReportDesignDefinition config : reportConfigs) {
DefaultDataSetList.Node leafNode = dataSetList.createLeafNode(getNodeId(config.getDesignId()),
config.getTitle(),
configBean.getName() + "-" + config.getTitle(),
rootNode.getId(),
new DataSetMetadata(uuid()).attr(BIZ_ID, bizId).attr(BIZ_ID, bizId).attr("designId", config.getDesignId()));
dataSetList.addNode(leafNode);
}
}
return dataSetList;
}
@Override
public boolean isAllow(ContextParam contextParam, DataSetMetadata metadata, Command command) throws BusinessException {
return bizPortalReportAdapterManager.checkAuth(getDesignId(command, metadata), contextParam.getUserId());
}
@Override
public DataSetResult executeQuery(ContextParam contextParam, DataSetMetadata metadata, String[] versions, Command command) throws BusinessException {
return getInvokeHandler(command).executeQuery(contextParam, metadata, versions, command);
}
@Override
public DataSetMetadata beforeDataSetMetaBind(String dataId, DataSetMetadata metadata) throws BusinessException {
return metadata.attr("designId", createBizPortalDataRelation(getBizId(metadata), dataId, metadata.attrLong("designId")));
}
@Override
protected String getId(Command command, DataSetMetadata metadata) throws BusinessException {
return getDesignId(command, metadata).toString();
}
private Long getDesignId(Command command, DataSetMetadata metadata) throws BusinessException {
return attrRealLong(command, metadata, "designId");
}
/**
* 获取命令操作类
* @param command
* @return
*/
private InvokeHandler getInvokeHandler(Command command) {
return invokeHandlerMap.get(command.getOp());
}
/**
* 默认命令处理类
*/
private class DefaultInvokeHandler implements InvokeHandler {
@Override
public DataSetResult executeQuery(ContextParam contextParam, DataSetMetadata metadata, String[] versions, Command command) throws BusinessException {
Long designId = getDesignId(command, metadata);
FlipInfo fi = new FlipInfo();
// 注意2:这里是带了分页信息的,列表数据源需要处理分页场景
PaginationParam paginationParam = PaginationParam.of(command);
fi.setPage(paginationParam.getPage());
fi.setSize(paginationParam.getPageSize());
fi.setNeedTotal(true);
UserConditions userConditions = new UserConditions();
ListDataResult list = bizPortalReportAdapterManager.findQueryDataResult(designId, userConditions, fi);
return ListDataSetResult.of(list);
}
}
/**
* 查询穿透查看详情
*/
private class DefaultViewDetailInvokeHandler implements ViewDetailInvokeHandler {
@Override
public MultiLinkDataSetResult executeQuery(ContextParam contextParam, DataSetMetadata metadata, String[] versions, Command command) throws BusinessException {
Long designId = getDesignId(command, metadata);
String extendParams = command.getAttributes().get("identifier").toString();
return bizPortalReportAdapterManager.getQueryPenetrateInfo(contextParam, designId, extendParams);
}
}
}
:::
# 七、数据版本
由于暂时所以的数据格式都只有V1版本,但不排除后期对数据格式有版本升级,故平台建议数据源开发者
1.不要重写AbstractDataSourceProvider#versions方法;2. 返回的数据结果的versio均指定为Version.V1。