Rdf-File根据协议布局模板和数据定义模板,来进行文件的解析与生成。通过协议布局和数据定义模板,能够明确计算出头尾占用的行数,这样可以更精确的分离出head,body,tail。

目前组件实现的协议布局模板可以分为如下两大类:

  • 开放式基金业务数据交换协议 这种国家标准文件, 数据是以补位后定长形式展示的。 存在缺点有:

  • 文件虽然是文本格式,但是内容肉眼无法看懂。

  • 定长补位导致文件存储浪费。

  • 因为是国家标准,文件内容定义十分全面,但是实际标准定义了六七十个字段, 有用的就十来个, 没用的字段也需要占用存储空间。

  • 字段通过分隔符分割, 字段内容由交互双方约定。优点是用多少就占用多少,缺点是各方文件格式、内容差异可能比较大。


数据定义模版

数据定义模板用来定义数据字段类型,分割符,采用哪种协议等等。

{
  "head":[
     "totalCount|总笔数|Required|Integer",
     "totalAmount|总金额|BigDecimal|Required"
  ],
  "body":[
     "seq|流水号",
     "instSeq|基金公司订单号|Required",
     "gmtApply|订单申请时间|Date:yyyy-MM-dd HH:mm:ss",
     "date|普通日期|Date:yyyyMMdd",
     "dateTime|普通日期时间|Date:yyyyMMdd HH:mm:ss",
     "applyNumber|普通数字|BigDecimal",
     "amount|金额|BigDecimal",
     "age|年龄|Integer",
     "longN|长整型|Long",
     "bol|布尔值|Boolean",
     "memo|备注"
    ],
    "tail": [
      "fileEnd|数据文件尾部字符|default:OFDCFEND"
    ],
    "protocol":"SP",
    "summaryColumnPairs":[
      "totalAmount|amount"
    ],
    "columnSplit":"|@|",
    "lineBreak": "\r",
    "startWithSplit": "body",
    "endWithSplit": "head|body|tail",
    "rowValidators": [
      "com.alipay.rdf.file.validator.RowValidateExample"
    ]
}

数据类型

一:SP

SP是简单格式simple的意思。

sp协议布局模板

<protocol name="sp">
     <head>
         <row>
             <column>
                 <output>${column.value()}</output>
             </column>
         </row>
     </head>
     
     <body>
         <row>
             <column>
                 <output>${column.value()}</output>
             </column>
         </row>
     </body>
     
     <tail>
         <row>
             <column>
                 <output>${column.value()}</output>
             </column>
         </row>
     </tail>
</protocol>
  • 文件布局分为head, body, tail 三部分。
  • head, body, tail字段都是横向输出,根据分隔符连接而成。
  • head,tail 都只有一行。

sp 数据定义模板示例

{
	"head": [
		"totalCount|总笔数|Required|Integer",
		"totalAmount|总金额|BigDecimal|Required"
	],
	"body": [
		"seq|流水号",
		"instSeq|基金公司订单号|Required",
		"gmtApply|订单申请时间|Date:yyyy-MM-dd HH:mm:ss",
		"date|普通日期|Date:yyyyMMdd",
		"dateTime|普通日期时间|Date:yyyyMMdd HH:mm:ss",
		"applyNumber|普通数字|BigDecimal",
		"amount|金额|BigDecimal",
		"age|年龄|Integer",
		"longN|长整型|Long",
		"bol|布尔值|Boolean",
		"memo|备注"
	],
	"tail": [
		"fileEnd|数据文件尾部字符|default:OFDCFEND"
	],
	"protocol": "SP"
}

SP文件示例

100|300.03
seq_0|inst_seq_0|2013-11-09 12:34:56|20131109|20131112 12:23:34|23.33|10.22|22|12345|true|备注1
seq_1|inst_seq_1|2013-11-10 15:56:12|20131110|20131113 12:33:34|23.34|11.88|33|56789|false|
OFDCFEND

二:DE

DE是余额宝与天弘交互格式,作为一种默认实现。

de协议布局模板

<protocol name="de">
     <head>
         <row>
             <column>
                 <output>${column.desc()}</output>
                 <output>:</output>
         <output>${column.value()}</output>
             </column>
         </row>
         <row output="${bodycolumn.horizontal(desc)}" />
     </head>
     
     <body>
         <row>
             <column>
                 <output>${column.value()}</output>
             </column>
         </row>
     </body>
     
     <tail>
         <row>
             <column>
                 <output>${column.value()}</output>
             </column>
         </row>
     </tail>
</protocol>
  • 头部第一行由 字段描述:字段值 在由分隔符连接而成。
  • 头部第二行由 组件函数横向打印出body的字段描述
  • 没有文件尾, 协议可以定义尾部,只要数据定义模板不定义文件尾就行。

de数据定义模板示例

{
  "head":[
     "totalCount|总笔数|Required|Long",
     "totalAmount|总金额|BigDecimal|Required"
  ],
  "body":[
     "seq|流水号",
     "instSeq|基金公司订单号|Required",
     "gmtApply|订单申请时间|Date:yyyy-MM-dd HH:mm:ss",
     "date|普通日期|Date:yyyyMMdd",
     "dateTime|普通日期时间|Date:yyyyMMdd HH:mm:ss",
     "applyNumber|普通数字|BigDecimal",
     "amount|金额|BigDecimal",
     "age|年龄|Integer",
     "longN|长整型|Long",
     "bol|布尔值|Boolean",
     "memo|备注"
    ],
  "protocol":"DE"
}

de文件示例

总笔数:2|总金额:300.03
流水号|基金公司订单号|订单申请时间|普通日期|普通日期时间|普通数字|金额|年龄|长整型|布尔值|备注
seq_0|inst_seq_0|2013-11-09 12:34:56|20131109|20131112 12:23:34|23.33|10.22|22|123|true|备注1 
seq_1|inst_seq_1|2013-11-10 15:56:12|20131110|20131113 12:33:34|23.34|11.88|33|56789|false|

三:fund

国家标准:开放式基金业务数据交换协议

fund协议布局模板

<protocol name="fund" rowsplit="rowSplitByFixedlLength">
    <head>
        <row columnLayout="vertical">
            <column>
                <output>${column.value()}</output>
            </column>
        </row>
        <row output="${bodycolumn.count()}" type="Integer|[3,0]" />
        <row output="${bodycolumn.vertical(name)}" />
        <row output="${totalCount}" type="Integer|[8,0]" />
    </head>
    
    <body>
        <row>
            <column>
                <output>${column.value()}</output>
            </column>
        </row>
    </body>
    
    <tail>
        <row>
            <column>
                <output>${column.value()}</output>
            </column>
        </row>
    </tail>
</protocol>
  • fund协议文件数据是定长而不是通过分隔符分割的,不足的补0
  • protocol标签的name用于指定协议名字,rowsplit属性指定数据字段的分割方式。
  • row标签的columnLayout定义了数据定义模板中的字段布局方式,这里是纵向布局,也就是一个字段一行 (默认是横向布局)。
  • bodycolumn.count() 是组件实现的内置列的数量。
  • bodycolumn.vertical(name)} 输出列的字段名
  • totalCount 组件内置变量,不用在数据定义模板中定义,数据行数
  • row的type属性定义变量的类型和长度。

fund数据定义模板示例

  • OFDCFDAT:开始标志。
  • OFDCFEND:结束标志。
{
  "head":[
    "identity|信息标识|[8,0]|default:OFDCFDAT",
    "version|协议版本号|[4,0]|default:20",
    "msgCreator|信息创建人|[9,0]|default:H0",
    "msgRecipient|信息接收人|[9,0]",
    "sendDate|传送发生日期|[8,0]|Date:yyyyMMdd",
    "summaryTableNo|汇总表号|[3,0]",
    "fileTypeCode|文件类型代码 |[2,0]",
    "sender|发送人|[8,0]|default:H0",
    "recipient|接收人|[8,0]"
  ],
  "body":[
    "TransactionCfmDate|对帐日期|[8,0]|Date:yyyyMMdd",
    "FundCode|基金代码|[8,0]",
    "AvailableVol|基金可用份数|BigDecimal|[6,2]"
  ],
  "tail":[
    "fileEnd|数据文件尾部字符|default:OFDCFEND|[8,0]"
  ],
  "protocol":"FUND"
}

fund文件示例

Map<String, Object> head = new HashMap<String, Object>();
head.put("msgRecipient", "xxx");
head.put("sendDate", "20231122");
head.put("summaryTableNo", "aa");
head.put("fileTypeCode", "bb");
head.put("recipient", "ll");
head.put("totalCount", 1);

Map<String, Object> row = new HashMap<String, Object>();
row.put("TransactionCfmDate", "20231122");
row.put("FundCode", "中国1");
// Integer|[6,2] 总长度6位,小数点2位,输出"004211"
row.put("AvailableVol", 42.11);
OFDCFDAT
20  
H0       
xxx      
20231122
aa 
bb
H0      
ll      
003
TransactionCfmDate
FundCode
AvailableVol
00000001
20231122中国1 004211
OFDCFEND

四:FUND_INDEX

fund_index body数据不是定长数据。

<protocol name="fund_index" rowsplit="rowSplitByFixedlLength">
	<head>
		<row columnLayout="vertical">
			<column>
				<output>${column.value()}</output>
			</column>
		</row>
		<row output="${totalCount}" type="Integer|[3,0]" />
	</head>
	<body>
	<!-- 只有一个字段,定义成vertical 是为了避免调用行分割器, 因为fund_index body数据不是定长数据 -->
		<row columnLayout="vertical">
			<column>
				<output>${column.value()}</output>
			</column>
		</row>
	</body>
	<tail>
		<row>
			<column>
				<output>${column.value()}</output>
			</column>
		</row>
	</tail>
</protocol>

fund_index数据定义模板示例

{
	"head": [
		"identity|信息标识|[8,0]|default:OFDCFIDX",
		"version|协议版本号|[4,0]|default:20",
		"msgCreator|信息创建人|[9,0]|default:H0",
		"msgRecipient|信息接收人|[9,0]",
		"sendDate|传送发生日期|[8,0]|Date:yyyyMMdd"
	],
	"body": [
		"path|基金文件路径"
	],
	"tail": [
		"fileEnd|数据文件尾部字符|default:OFDCFEND|[8,0]"
	],
	"protocol": "FUND_INDEX"
}

fund_index文件示例

OFDCFIDX
20
H0
xxx
20180302
003
aaa/xxx/ccc
bbb/xxx/ccc
ccc/xxx/ccc
OFDCFEND
11-25 05:41