9.中心数据源

9.1.关于数据源

报表从数据源取数、填充是Supcan Report最重要的功能之一，数据源分二种：中心数据源和临时数据源。
所谓“中心数据源”是指可用的数据源全部都已经预先编排好了，客户编制报表时，只要获得中心数据源目录列表的URL，就能从中挑选本张报表需要的各种数据，例如制作销售统计表时，从数据源中心的数据目录树中挑选和销售有关的数据源即可。 采用中心数据源，报表制作者只要有数据目录的URL，就可以实现不需要程序员帮助的报表制作；对于程序员而言，只要把能提供的数据归并到中心数据目录即可，不必关心具体的报表制作过程，真正实现了数据与格式的分离。
所谓“临时数据源”是指每一个数据源的URL都需要程序员告诉最终的制表者，从哪里去获得数据，没有一个统一的数据发布途经，所以这只是临时的报表制作方案。当然如果对报表的自定义要求不高、报表数量不多的话，临时数据源也能实现和中心数据源同样的功能。此外“临时数据源”支持更多种类的数据格式。
“临时数据源”相对比较简单，您只要按最下面的 "附录.数据源实例" 做一遍，就应该对其有所了解，在此不再作分析。

建议：初学者如果要应用数据源，建议从临时数据源开发入手。如果没有弄清中心数据源的一些细节就直接使用中心数据源，结果可能是一团糟.

9.2.基本协议

中心数据源协议核心是2个协议：目录协议和描述协议，这2种协议其实就是2种格式的XML。建设中心数据源的基础工作，主要就是维护这2种XML文件(或http响应)。
此外，还有根据需要可选的协议，比如单个数据源的描述协议、懒加载协议、搜索协议等。

9.2.1.数据源目录协议

中心数据源首先必须要有一个总的目录，这个目录好比就是电话号码本，里面记载了每个可用数据源的入口。
数据源目录是XML格式的(不支持JSON格式)，必须由程序员预先编排好，XML举例如下：

    <?xml version="1.0" encoding="UTF-8"?">
    <Catalog>
     <Project text="业务数据" tip="货运数据">
      <ds id="1001" descURL="data1.desc.xml" dataURL="data.xml">货运数据</ds>
     </Project>
     <Project text="财务数据" >
      <ds id="2001" descURL="fin.xml" dataURL="serv1?para=1" tip="资产类科目余额">资产</ds>
      <ds id="2002" descURL="fin.xml" dataURL="serv1?para=2" tip="负债类科目余额">负债</ds>
      <ds id="2003" descURL="fin.xml" dataURL="serv1?para=3" tip="权益">权益</ds>
      <ds id="s201" descURL="fin.xml" dataURL="serv2"  pagingPara="rows=30&startRow=@startRow&substr=@data"  tip="测试">测试数据</ds>
     </Project>
     <Project text="以往年度数据" lazyload="old1.aspx?nj=3">
     </Project>
    </Catalog>

协议说明如下：
1.该XML树、子树的级别无限制，树的元素命名也无限制，Supcan Report都能够正确地解析、显示出来；
2.上例中红色部分元素名必须书写正确，黑色部分为可选；
3.上述XML中，带id的行表示某个具体的数据源，其id必须唯一，id可以为英文字母、数字、下划线组合，但不得包含斜杠。该目录树一旦正式发布、投入使用，id不得轻易修改，因为id会被保存在引用了该数据源的报表的XML文件中;
4.descURL表示描述该数据源的XML的URL，数据源描述协议在下面有介绍。该URL可以是绝对URL，也可以是相对URL(相对于中心数据源目录XML)，例子中就是相对URL；
5.dataURL表示该数据源最终数据的URL，对于JavaEE开发者而言，这就象是一个Servlet。该URL可以是绝对URL，也可以是相对URL(相对于中心数据源目录XML)，例子中就是相对URL；
6.LazyLoad表示懒加载，鼠标首次点击让它展开时动态从后端加载子孙;
7.tip表示内容帮助，即鼠标滑过该数据源时会出现的略为详细的黄色说明条;
8.pagingPara表示该数据源支持服务器动态分页查询功能, 如果报表字典管理中启用了该功能, 当最终在发起 http 请求时, 实际的 URL 将会自动在 dataURL 后面附加上这个参数串，当然这个参数串中的 @宏 将会被替换掉, @startRow 表示开始行, @data 表示搜索词; 参数串中其余参数是自定义的，可以自行增加，例如 rows=30 表示分页的每页最大行数，自定义内容和插件无关;
9.黑色加粗部分(即XML的Text)为数据源的含义正文，制表者在挑选数据源时看到的就是这些文字，通常要求简短而含义准确;

9.2.2.数据描述协议

上述目录中，每条都有一个名为 "descURL" 的属性，这个 descURL 就是指向该数据源的详细描述的XML文本，这就是数据源的描述协议.
该XML描述了各个数据列的属性，描述协议举例如下：

    <?xml version="1.0" encoding="UTF-8"?">
    <cols>
    　<col name="orderID" datatype="int" hyperLink="conID">订单号</col>
    　<col name="orderDate" datatype="date">订单日期</col>
    　<col name="conID">合同号</col>
    </cols>

或如下的 Json 串：

    {
     cols: [
      { name:'orderID', datatype:'int', hyperLink:'conID', text:'订单号'},
      { name:'orderDate', datatype:'date', text:'订单日期'},
      { name:'conID', text:'合同号'}
     ]
    }

协议说明如下：
1.元素名必须书写正确；
2.datatype可以是string、int、double、date、datetime，默认是string(即datatype="string"可以忽略)；
3.hyperLink表示该列允许被超链接，指向超链接的列；

9.2.3.开发要则

如果你实现了上述2个协议，就可以进行中心数据源简单的开发了。
在运行时，页面的 js 必须通过 SetSource 函数指点中心数据源的入口地址，保证在打开报表前指定，如：

     ...
     //先指定中心数据源入口URL
     AF.func("SetSource", "/dataservice/centerEntra.aspx");
     //再打开报表
     AF.func("Build", "/reports/01/private/33.xml");
     ...

如果您已经尝试过临时数据源的开发，你会发现 SetSource 和 Build 的执行次序正好相反，因为它们的原理不一样。
此外，需注意切勿随意切换这个中心数据源的入口URL，因为在进程中，入口URL是唯一的，硕正控件内部是采用 Singleton (单实例模式) 实现的。 按理说，设置中心数据源入口URL，只要执行 SetSource 一遍即可全局生效，但最终用户在浏览你的页面时，你可能无法预知哪个页面是第一次被浏览的，所以建议在 OnReady( )事件中、在 Build 前执行 SetSource 函数。

一旦执行 SetSource 更改了入口地址，那么中心数据源将指向新的入口URL

针对临时数据源的 SetSource 函数，和更改中心数据源入口地址的 SetSource 函数，尽管函数名是一样的，都是 "SetSource"，但其实是相互独立的，双方互不影响.

9.3.参数协议

采用中心数据源后，制表者会倍感轻松，但是也会面临一个问题：参数问题，例如获取销售数据，通常会有时间段的要求，如何获得有指定时间、地点或其它查询条件的数据，通常都采用查询“参数”来解决。
以上述中心数据源目录XML为例，带参数的数据源目录格式举例如下：

    <?xml version="1.0" encoding="UTF-8"?">
    <Project name="业务数据" tip="货运数据">
    　...
    　<ds id="11" para1="月份" para2="组织号" dataURL="data.serv?month=@para1&org=@para2" descURL="data1.desc.xml">货运数据</ds>
    　<ds id="12" para1="搜索串" dataURL="data.serv?search=@para1" descURL="data1.desc.xml" isPost="EncodeURIComponent" contentType="text/html">货运数据</ds>
    　...
    </Project>

这样就实现了带参数的查询，该部分协议规定如下：
1.预先定义的参数，元素名为para1、para2、...，序号从1开始，其内容为参数的含义；
2.若预先定义了参数，dataURL中须有@para1、@para2之类的宏，最终Supcan Report会根据真实的参数拼装出真正的URL，并向服务器发送GET请求.
这是数据源目录中的参数预定义规则，在具体的制表过程中，参数可以通过如下途经设置：
1.直接在公式中输入，例如"=datarow('ds1', 1, '001')";
2.将参数指向某个单元格，例如："=datarow('ds1', C6, '001')"，其中C6是指C6单元格，只要在C6单元格输入了月份数据，数据会立即刷新；
3.在上例中，C6单元格可以制作成下拉，将月份字典表赋予给此单元，最终用户只要从下拉中选择月份，数据也能刷新；
4.在页面中通过js调用Supcan Report的SetParas()函数，直接设置查询条件；
5.isPost 可以是 false / true / encodeURIComponent，默认是false(即 GET)；否则将dataURL中问号(?)后面的内容拆分出来安置在 http Body 中；而"encodeURIComponent"则表示参数内容预先做encodeURIComponent处理，和ajax post处理方式一致;
6.ContentType 用于 isPost 为true 或 encodeURIComponent 的情形;

9.4.单个数据源描述协议

“单个数据源描述协议”是一个可选的协议, 服务端返回的XML结构举例如下：

    <?xml version="1.0" encoding="UTF-8"?">
    <cols dataURL="data.serv?month=@para1&org=@para2" para1="月份" para2="组织号" text="订单数据" >
    　<col name="orderID" datatype="int" hyperLink="conID">订单号</col>
    　<col name="orderDate" datatype="date">订单日期</col>
    　<col name="conID">合同号</col>
    </cols>

它相当于将dataURL、para参数和列信息统统写在一起了。
该协议的使用场景如下：
假如某张报表已经使用了中心数据源，假设其数据源 id 为 "1001", 当硕正报表打开这张报表后，它会在中心数据源目录URL的后面增加参数“serviceId=1001”，以这个URL访问服务器。其实它是试图绕过目录服务，单独取得这个数据源的结构信息.
假如中心数据源目录的URL为 "../serv/centercat.aspx"， 那么单独获取的URL为 "../serv/centercat.aspx?serviceId=1001";
您的后端程序遇到这种请求，有如下2种处理方案：
1.按照本“单个数据源描述协议”，返回该数据源的结构；
2.不理会本协议，直接返回整个数据源目录，相当于是无视“serviceId=1001”这个参数；
不管您返回上述哪种XML，硕正报表都能正确辨认，达到取得该数据源的结构的目的。
在您的中心数据源目录比较庞大、访问获取时比较耗时的情况下，实现“单个数据源描述协议”能明显提升报表的性能。

9.5.懒加载协议

如果中心数据源目录中条目增多，假如达到数千条，这个XML数据的下载会很慢，为此，我们的目录协议还支持另一种XML格式：采用平面的结果集格式，以 "pid" 属性指定树的上层 id，例如：

    <?xml version="1.0" encoding="UTF-8"?">
    <Catalog treeformat="bypid">
     <ds id="1" text="业务数据" tip="货运数据"/>
     <ds id="1001" pid="1" descURL="data1.desc.xml" dataURL="data.xml" text="货运数据"/>
     <ds id="2" text="财务数据" />
     <ds id="2001" pid="2" descURL="fin.xml" dataURL="serv1?para=1" text="资产"/>
     <ds id"2002" pid="2" descURL="fin.xml" dataURL="serv1?para=2" text="负债"/>
     <ds id="3" text="以往年度数据" lazyload="old1.aspx?nj=3"/>
    </Catalog>

该协议须注意：
1.顶部的<Catalog treeformat="bypid">就表示告诉硕正数据源管理器，目前使用的是byPid格式;
2.第8行的 LazyLoad 属性表示该行是树杈，鼠标点击展开时，会动态从这个URL加载其子孙的;
3.子孙的XML格式也应该和这个XML相似.
如果您准备启用LazyLoad模式，那么您必须同时也实现前述的“单个数据源描述协议”。

9.6.搜索协议

和上述懒加载的情形相似，如果中心数据源编目繁多，为了快速搜索到所需的数据源，还需要补充一个搜索协议。
当实例创建参数增加：DSCenterDialogHeader="search" 时，中心数据源对话框显示如下：
这就需要在硕正控件和后端服务之间设定一个协议，协议很简单：在中心数据源URL后增加search参数，假如中心数据源目录的URL是：
http://loaclhost/datacenter.aspx
那么数据源搜索的URL就是(假如搜索内容是 "仓储"):
http://loaclhost/datacenter.aspx?search=%e4%bb%93%e5%82%a8
其中"%e4%bb%93%e5%82%a8"是中文"仓储"的UTF-8编码.
此外，后端服务也同样需要实现数据源描述服务，即懒加载协议中的 serviceId=ID号 的服务。

9.7.其它说明

1.一张报表中可以有多个数据源，允许中心数据源、临时数据源混合使用；
2.在页面中，应该在打开报表前调用SetSource()，预先设置中心数据源目录的URL;
3.中心数据源的XML协议中，如果需要用到中英文对照，应该以竖线("|")分隔中英文，例如tip="合同号|Contact ID";
4.中心数据源具体的数据格式，支持XML、JSON、TSV-EX;
5.上述XML中的元素名对大小写不敏感;