60.2. 注解
创建的注解允许将不同模型概念映射到 POJO,如下所示:
- 记录类型(CSV、键值对(如 FIX 消息)、固定 length …)
- 链接(到另一个对象中的链接对象)
- DataField 及其属性(int、type、…)
- KeyValuePairField (用于 key = value format,如 FIX 交易消息),
- 部分(用于标识标头、正文和页脚部分)
- OneToMany,
- BindyConverter,
- FormatFactories
本节将描述它们。
60.2.1. 1.CsvRecord
CsvRecord 注解用于识别模型的根类。它代表一个 record = "CSV 文件的一行",并可链接到几个子模型类。
注解名称 | 记录类型 | 级别 |
---|---|---|
CsvRecord | CSV | 类 |
参数名称 | 类型 | 必填 | 默认值 | info |
---|---|---|---|---|
分隔符 | 字符串 | ✓ | 用于在令牌中分割记录的分隔符(必需)- 可以是 '、' 或 ';' 或 'anything'。唯一支持的空格字符是标签(\t)。不支持其他空格字符(空格)。这个值被解释为正则表达式。如果要使用在正则表达式中具有特殊含义的符号,如 '|' 符号,则必须屏蔽它,如 '|'。 | |
allowEmptyStream | 布尔值 | false | allowEmptyStream 参数允许调整 CSV 文件的不密集型流。 | |
autospanLine | 布尔值 | false | 最后记录跨越其余行(可选)- 如果启用,则最后一列会自动到行尾,例如,如果其注释,则允许行包含所有字符,还包含分隔符。 | |
CRLF | 字符串 | WINDOWS | 用于在每个记录(可选)后添加cariage 返回的字符 - 允许定义要使用的 carriage 返回字符。如果您指定了之前列出的三个值,则输入的值(custom)将用作 CRLF 字符。可以使用三个值:WINDOWS、UNIX、MAC 或 custom。 | |
endWithLineBreak | 布尔值 | true | 如果 CSV 文件应该以换行符或不结束(可选)结尾,则 endWithlineBreak 参数标志 | |
generateHeaderColumns | 布尔值 | false | generateHeaderColumns 参数允许在 CSV 中添加,生成包含列名称的标头 | |
isOrdered | 布尔值 | false | 指明消息是否在输出中排序 | |
name | 字符串 | 描述记录的名称(可选) | ||
quote | 字符串 | " | 是否使用给定引号字符(可选) marshal 列 - 允许在生成 CSV 时指定字段的引号字符。此注解与模型的根类关联,必须一次声明。 | |
quoting | 布尔值 | false | 指定在 marshaling 时是否必须加引号值(可选) | |
quotingEscaped | 布尔值 | false | 指定在引用时是否必须转义值(可选) | |
removeQuotes | 布尔值 | true | 如果 unmarshalling 应该尝试删除每个字段的引号,则 remove quote 参数标记 | |
skipField | 布尔值 | false | skipField 参数将允许跳过 CSV 文件的字段。如果不需要一些字段,可以跳过它们。 | |
skipFirstLine | 布尔值 | false | skipFirstline 参数将允许跳过 CSV 文件的第一行。这个行通常包含列定义 |
case 1 : separator = ','
用于隔离 CSV 记录中的字段的分隔符是
:
10, J, Pauline, M, XD12345678, Fortis Dynamic 15/15, 2500, USD, 08-01-2009
@CsvRecord( separator = "," ) public Class Order { }
case 2 : separator = ';'
与上一个情况进行比较,这里的分隔符是 ;
而不是 、
10; J; Pauline; M; XD12345678; Fortis Dynamic 15/15; 2500; USD; 08-01-2009
@CsvRecord( separator = ";" ) public Class Order { }
case 3 : separator = '|'
与上一个情况进行比较,这里的分隔符是 |
而不是 ;
:
10| J| Pauline| M| XD12345678| Fortis Dynamic 15/15| 2500| USD| 08-01-2009
@CsvRecord( separator = "\\|" ) public Class Order { }
case 4 : separator = '\",\"'
适用于 Camel 2.8.2 或更早版本
当 CSV 记录解析的字段包含 ,
或 ;
(也用作分隔符)时,应该找到另一个策略来告知 camel bindy 如何处理此问题单。要使用逗号定义包含数据的字段,您可以使用单引号或双引号作为分隔符(例如 : '10', 'Street 10, NY', 'USA' 或 "10", "Street 10, NY", "USA")。
__ | 在这种情况下,作为单引号或双引号的行的前和最后一个字符将通过 bindy 删除。 |
"10","J","Pauline"," M","XD12345678","Fortis Dynamic 15,15","2500","USD","08-01-2009"
@CsvRecord( separator = "\",\"" ) public Class Order { }
bindy 会自动检测记录是否用单引号或双引号括起来,并在从 CSV 到对象取消编译时自动删除这些引号。因此 ,不要在 分隔符中包含引号,但如下所示:
"10","J","Pauline"," M","XD12345678","Fortis Dynamic 15,15","2500","USD","08-01-2009"
@CsvRecord( separator = "," ) public Class Order { }
请注意,如果要从对象到 CSV 并使用引号,则需要使用 @CsvRecord
上的 quote
属性来指定要使用的字符,如下所示:
@CsvRecord( separator = ",", quote = "\"" ) public Class Order { }
问题单 5:分隔符和跳过行
当客户端想要在文件的第一行中时,这个功能值得注意,数据字段的名称:
order id, client id, first name, last name, isin code, instrument name, quantity, currency, date
要告知绑定此第一行必须在解析过程中跳过,然后我们使用属性 :
@CsvRecord(separator = ",", skipFirstLine = true) public Class Order { }
case 6 : generateHeaderColumns
要在生成的 CSV 的第一行中添加,在注解中必须将属性 generateHeaderColumns 设置为 true,如下所示:
@CsvRecord( generateHeaderColumns = true ) public Class Order { }
因此,在 unmarshaling 过程中绑定将生成 CSV,如下所示:
order id, client id, first name, last name, isin code, instrument name, quantity, currency, date 10, J, Pauline, M, XD12345678, Fortis Dynamic 15/15, 2500, USD, 08-01-2009
问题单 7:cariage 返回
如果运行 camel-bindy 的平台不是 Windows,但 Macintosh 或 Unix,您可以更改 crlf 属性,如下所示。三个值可用:WINDOWS、UNIX 或 MAC
@CsvRecord(separator = ",", crlf="MAC") public Class Order { }
另外,如果您需要添加不同的行结尾字符,您可以选择使用 crlf 参数指定它。在以下示例中,我们可以使用逗号结尾行,后跟换行符:
@CsvRecord(separator = ",", crlf=",\n") public Class Order { }
case 8 : isOrdered
有时,从模型创建 CSV 记录期间遵循的顺序与解析过程中使用的顺序不同。然后,在这种情况下,我们可以使用属性 isOrdered = true
来将这个属性与 DataField 注解的属性 位置
结合使用。
@CsvRecord(isOrdered = true) public Class Order { @DataField(pos = 1, position = 11) private int orderNr; @DataField(pos = 2, position = 10) private String clientNr; }
__ |
|
60.2.2. 2.Link
link 注解允许将对象链接在一起。
注解名称 | 记录类型 | 级别 |
---|---|---|
Link | all | 类和属性 |
参数名称 | 类型 | 必填 | 默认值 | info |
---|---|---|---|---|
linkType | LinkType | OneToOne | 标识类间关系的链接类型 |
从当前版本中,只允许一对一的关系。
例如:如果模型类客户端链接到 Order 类,请在 Order 类中使用注解链接,如下所示:
属性链接
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @Link private Client client; }
对于类客户端:
类链接
@Link public class Client { }
60.2.3. 3.DataField
DataField 注释定义字段的属性。每个 datafield 都由记录中的位置、类型(字符串、int、date、…)以及可选的模式来标识。
注解名称 | 记录类型 | 级别 |
---|---|---|
DataField | all | 属性 |
参数名称 | 类型 | 必填 | 默认值 | info |
---|---|---|---|---|
pos | int | ✓ | 在输入记录中数据的位置,必须从 1 开始(必需)。请参阅 position 参数。 | |
校准 | 字符串 | R | 将文本与右或左处对齐。使用 <tt>R</tt> 或 <tt>L</tt> 的值。 | |
Clip | 布尔值 | false | 如果在使用固定长度时超过允许的长度,则指示在字段中清除数据。 | |
columnName | 字符串 |
标题栏的名称(可选)。使用属性的名称作为默认值。仅在 | ||
decimalSeparator | 字符串 | 与数字一起使用的十进制 9 月 | ||
defaultValue | 字符串 | 如果没有设置值,则字段的默认值 | ||
delimiter | 字符串 | 如果字段具有变量长度,则使用可选分隔符 | ||
groupingSeparator | 字符串 | 当我们想将/解析分成带有分组(例如 123,456.789 )的数字时,将分号号分组到数字中 | ||
impliedDecimalSeparator | 布尔值 | false | 指明在指定位置是否表示十进制点 | |
length | int | 0 | 如果记录设置为固定长度,则数据块的长度(字符数) | |
lengthPos | int | 0 | 标识记录中为此字段定义预期固定长度的 data 字段 | |
方法 | 字符串 | 调用在 DataField 上应用此类自定义的方法名称。这必须是 datafield 本身的方法,或者您必须提供类方法的静态完全限定名称,例如:查看 test org.apache.camel.dataformat.bindy.csv.BindySimpleCsvFunctionWithExternalMethodTest.replaceToBar | ||
name | 字符串 | 字段的名称(可选) | ||
paddingChar | char | 如果记录被设置为固定长度,则 char to pad | ||
pattern | 字符串 | Java 格式化器(示例为SimpleDateFormat)的模式将用于转换数据(可选)。如果使用模式,则建议在绑定数据格式上设置区域设置。设置为已知区域设置,如 "us" 或使用 "default" 来使用平台默认区域设置。 | ||
position | int | 0 | 生成输出消息中的字段位置(从 1 开始)。当 CSV 生成的字段的位置(输出消息)必须与输入位置(可能)进行比较时,必须使用。请参阅 pos 参数。 | |
精度 | int | 0 | 要创建的 \{@link java.math.BigDecimal} 编号的精度 | |
required | 布尔值 | false | 指明字段是否是必需的 | |
舍入 | 字符串 | CEILING | 用于舍入/scale 定制值 : UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_UP, HALF_DOWN,HALF_EVEN, UNNECESSARY e.g : Number = 123456.789, Precision = 2, Rounding = CEILING Result : 123456.79 | |
timezone | 字符串 | 要使用的时区。 | ||
trim | 布尔值 | false | 指明值是否应修剪 |
问题单 1:pos
此参数/属性代表 CSV 记录中字段的位置。
position
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 5) private String isinCode; }
如本例中看到的那样,位置从 1
开始,但从类顺序中的 5
开始。类客户端中定义了从 2
到 4
的数字(请参阅 之后)。
位置继续在另一个模型类中
public class Client { @DataField(pos = 2) private String clientNr; @DataField(pos = 3) private String firstName; @DataField(pos = 4) private String lastName; }
问题单 2:模式
该模式可用于增强或验证您的数据格式
pattern
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 5) private String isinCode; @DataField(name = "Name", pos = 6) private String instrumentName; @DataField(pos = 7, precision = 2) private BigDecimal amount; @DataField(pos = 8) private String currency; // pattern used during parsing or when the date is created @DataField(pos = 9, pattern = "dd-MM-yyyy") private Date orderDate; }
问题单 3:精度
当您要定义数字的十进制部分时,精度很有用。
精度
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @Link private Client client; @DataField(pos = 5) private String isinCode; @DataField(name = "Name", pos = 6) private String instrumentName; @DataField(pos = 7, precision = 2) private BigDecimal amount; @DataField(pos = 8) private String currency; @DataField(pos = 9, pattern = "dd-MM-yyyy") private Date orderDate; }
问题单 4:输出中的位置不同
location 属性将告知绑定如何将字段放在生成的 CSV 记录中。默认情况下,使用的位置对应于通过属性 pos
定义的位置。如果位置不同(这意味着,我们有一个 asymetric 进程与 unmarshaling 的 marshaling 的比较),则我们可以使用 位置
来指示这一点。
下面是一个示例:
位置在输出中有所不同
@CsvRecord(separator = ",", isOrdered = true) public class Order { // Positions of the fields start from 1 and not from 0 @DataField(pos = 1, position = 11) private int orderNr; @DataField(pos = 2, position = 10) private String clientNr; @DataField(pos = 3, position = 9) private String firstName; @DataField(pos = 4, position = 8) private String lastName; @DataField(pos = 5, position = 7) private String instrumentCode; @DataField(pos = 6, position = 6) private String instrumentNumber; }
注释 @DataField
的此属性必须与注解 @CsvRecord
的属性 isOrdered = true
结合使用。
问题单 5:必需
如果字段是必需的,只需使用 所需的
属性设为 true。
必填
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 2, required = true) private String clientNr; @DataField(pos = 3, required = true) private String firstName; @DataField(pos = 4, required = true) private String lastName; }
如果记录中没有此字段,则解析器将引发一个错误,其中包含以下信息:
Some fields are missing (optional or mandatory), line :
case 6 : trim
如果字段有前导和/或尾随空格,则应在处理前删除它们,只需使用属性 trim
set 为 true。
Trim
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1, trim = true) private int orderNr; @DataField(pos = 2, trim = true) private Integer clientNr; @DataField(pos = 3, required = true) private String firstName; @DataField(pos = 4) private String lastName; }
问题单 7:defaultValue
如果没有定义字段,则使用 defaultValue
属性表示的值。
默认值
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 2) private Integer clientNr; @DataField(pos = 3, required = true) private String firstName; @DataField(pos = 4, defaultValue = "Barin") private String lastName; }
问题单 8 : columnName
仅在 @CsvRecord
带有注解 generateHeaderColumns = true
时指定属性的列名称。
列名称
@CsvRecord(separator = ",", generateHeaderColumns = true) public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 5, columnName = "ISIN") private String isinCode; @DataField(name = "Name", pos = 6) private String instrumentName; }
此属性仅适用于可选字段。
60.2.4. 4.FixedLengthRecord
FixedLengthRecord 注解用于识别模型的根类。它代表一个 record = "一个文件/消息行,其中包含数据固定长度(字符数)格式,并可链接到几个子模型类。这种格式是特定于位的,因为字段的数据可以与右侧或左处一致。
当数据大小没有完全填写字段长度时,我们可以添加"平板"字符。
注解名称 | 记录类型 | 级别 |
---|---|---|
FixedLengthRecord | FIXED | 类 |
参数名称 | 类型 | 必填 | 默认值 | info |
---|---|---|---|---|
countGrapheme | 布尔值 | false | 指明如何计算计费 | |
CRLF | 字符串 | WINDOWS | 用于在每个记录后(可选)添加cariage 返回的字符。可能的值:WINDOWS、UNIX、MAC 或 custom。这个选项仅在 marshalling 期间使用,unmarshalling 使用系统默认的 JDK 提供行分隔符,除非自定义 eol。 | |
EOL | 字符串 | 在未记录时考虑每个记录之后的字符(可选 - default: "",它可帮助使用默认的 JDK 提供行分隔符),除非提供了任何其他值,否则此选项仅在 unmarshalling 时使用,其中 marshalling 使用系统默认提供的行分隔符,除非提供了任何其他值。 | ||
footer | 类 | void | 表示此类型的记录后面可以跟随一个页记录(在文件的末尾) | |
header | 类 | void | 表示此类型的记录可以在文件开头的单个标头记录前面。 | |
ignoreMissingChars | 布尔值 | false | 指明是否忽略了太短行 | |
ignoreTrailingChars | 布尔值 | false | 表示在未记录/解析时,可以忽略超过最后一个映射文件的字符。此注解与模型的根类关联,必须一次声明。 | |
length | int | 0 | 记录的固定长度(字符数)。这意味着,记录始终为使用 \{114paddingChar ()} 的长添加 | |
name | 字符串 | 描述记录的名称(可选) | ||
paddingChar | char | 平板的费用。 | ||
skipFooter | 布尔值 | false | 配置数据格式,以跳过页脚记录的 marshalling / unmarshalling。在主记录上配置此参数(例如,不是标头或页脚)。 | |
skipHeader | 布尔值 | false | 配置数据格式,以跳过标头记录的 marshalling / unmarshalling。在主记录上配置此参数(例如,不是标头或页脚)。 |
记录可能不是标头/页脚和主固定长度记录。
问题单 1:简单固定长度记录
这个简单示例演示了如何设计模型来解析/格式化固定消息
10A9PaulineMISINXD12345678BUYShare2500.45USD01-08-2009
fixed-simple
@FixedLengthRecord(length=54, paddingChar=' ') public static class Order { @DataField(pos = 1, length=2) private int orderNr; @DataField(pos = 3, length=2) private String clientNr; @DataField(pos = 5, length=7) private String firstName; @DataField(pos = 12, length=1, align="L") private String lastName; @DataField(pos = 13, length=4) private String instrumentCode; @DataField(pos = 17, length=10) private String instrumentNumber; @DataField(pos = 27, length=3) private String orderType; @DataField(pos = 30, length=5) private String instrumentType; @DataField(pos = 35, precision = 2, length=7) private BigDecimal amount; @DataField(pos = 42, length=3) private String currency; @DataField(pos = 45, length=10, pattern = "dd-MM-yyyy") private Date orderDate; }
问题单 2:使用校准和 padding修复长度记录
这个更详细的示例演示了如何为字段定义对齐以及如何分配为 '' here 的
padding 字符:
10A9 PaulineM ISINXD12345678BUYShare2500.45USD01-08-2009
fixed-padding-align
@FixedLengthRecord(length=60, paddingChar=' ') public static class Order { @DataField(pos = 1, length=2) private int orderNr; @DataField(pos = 3, length=2) private String clientNr; @DataField(pos = 5, length=9) private String firstName; @DataField(pos = 14, length=5, align="L") // align text to the LEFT zone of the block private String lastName; @DataField(pos = 19, length=4) private String instrumentCode; @DataField(pos = 23, length=10) private String instrumentNumber; @DataField(pos = 33, length=3) private String orderType; @DataField(pos = 36, length=5) private String instrumentType; @DataField(pos = 41, precision = 2, length=7) private BigDecimal amount; @DataField(pos = 48, length=3) private String currency; @DataField(pos = 51, length=10, pattern = "dd-MM-yyyy") private Date orderDate; }
问题单 3:字段 padding
有时,为记录定义的默认 padding不能应用于字段,因为我们有数字格式,其中我们想使用 '0' 而不是 '0' 而不是 '。在这种情况下,您可以在模型中使用 @DataField
上的属性 paddingChar
来设置此值。
10A9 PaulineM ISINXD12345678BUYShare000002500.45USD01-08-2009
fixed-padding-field
@FixedLengthRecord(length = 65, paddingChar = ' ') public static class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 3, length = 2) private String clientNr; @DataField(pos = 5, length = 9) private String firstName; @DataField(pos = 14, length = 5, align = "L") private String lastName; @DataField(pos = 19, length = 4) private String instrumentCode; @DataField(pos = 23, length = 10) private String instrumentNumber; @DataField(pos = 33, length = 3) private String orderType; @DataField(pos = 36, length = 5) private String instrumentType; @DataField(pos = 41, precision = 2, length = 12, paddingChar = '0') private BigDecimal amount; @DataField(pos = 53, length = 3) private String currency; @DataField(pos = 56, length = 10, pattern = "dd-MM-yyyy") private Date orderDate; }
问题单 4:使用分隔符修复长度记录
固定长度记录有时在记录中以分隔的内容。firstName 和 lastName 字段使用以下示例中的 ^
字符分隔:
10A9Pauline^M^ISINXD12345678BUYShare000002500.45USD01-08-2009
固定分隔
@FixedLengthRecord public static class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 2, length = 2) private String clientNr; @DataField(pos = 3, delimiter = "^") private String firstName; @DataField(pos = 4, delimiter = "^") private String lastName; @DataField(pos = 5, length = 4) private String instrumentCode; @DataField(pos = 6, length = 10) private String instrumentNumber; @DataField(pos = 7, length = 3) private String orderType; @DataField(pos = 8, length = 5) private String instrumentType; @DataField(pos = 9, precision = 2, length = 12, paddingChar = '0') private BigDecimal amount; @DataField(pos = 10, length = 3) private String currency; @DataField(pos = 11, length = 10, pattern = "dd-MM-yyyy") private Date orderDate; }
固定长度记录中的 pos
值可以选择使用正数、顺序值而不是精确列号来定义。
问题单 5:使用记录定义字段长度修复长度记录
有时,一个固定长度记录可能会包含一个字段,该字段定义同一记录中另一个字段的预期长度。在以下示例中,detect Number 字段值
的长度由记录中的 detect NumberLen
字段的值定义。
10A9Pauline^M^ISIN10XD12345678BUYShare000002500.45USD01-08-2009
固定分隔
@FixedLengthRecord public static class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 2, length = 2) private String clientNr; @DataField(pos = 3, delimiter = "^") private String firstName; @DataField(pos = 4, delimiter = "^") private String lastName; @DataField(pos = 5, length = 4) private String instrumentCode; @DataField(pos = 6, length = 2, align = "R", paddingChar = '0') private int instrumentNumberLen; @DataField(pos = 7, lengthPos=6) private String instrumentNumber; @DataField(pos = 8, length = 3) private String orderType; @DataField(pos = 9, length = 5) private String instrumentType; @DataField(pos = 10, precision = 2, length = 12, paddingChar = '0') private BigDecimal amount; @DataField(pos = 11, length = 3) private String currency; @DataField(pos = 12, length = 10, pattern = "dd-MM-yyyy") private Date orderDate; }
问题单 6:使用标头和页脚修复长度记录
bindy 将发现配置为模型一部分的固定长度标头和页脚记录 - 如果注解类与主 @FixedLengthRecord
类或配置在一个配置的扫描软件包之一中存在。以下文本演示了两个固定长度记录,它们由标头记录和页脚记录阻止。
101-08-2009 10A9 PaulineM ISINXD12345678BUYShare000002500.45USD01-08-2009 10A9 RichN ISINXD12345678BUYShare000002700.45USD01-08-2009 9000000002
fixed-header-and-footer-main-class
@FixedLengthRecord(header = OrderHeader.class, footer = OrderFooter.class) public class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 2, length = 2) private String clientNr; @DataField(pos = 3, length = 9) private String firstName; @DataField(pos = 4, length = 5, align = "L") private String lastName; @DataField(pos = 5, length = 4) private String instrumentCode; @DataField(pos = 6, length = 10) private String instrumentNumber; @DataField(pos = 7, length = 3) private String orderType; @DataField(pos = 8, length = 5) private String instrumentType; @DataField(pos = 9, precision = 2, length = 12, paddingChar = '0') private BigDecimal amount; @DataField(pos = 10, length = 3) private String currency; @DataField(pos = 11, length = 10, pattern = "dd-MM-yyyy") private Date orderDate; } @FixedLengthRecord public class OrderHeader { @DataField(pos = 1, length = 1) private int recordType = 1; @DataField(pos = 2, length = 10, pattern = "dd-MM-yyyy") private Date recordDate; } @FixedLengthRecord public class OrderFooter { @DataField(pos = 1, length = 1) private int recordType = 9; @DataField(pos = 2, length = 9, align = "R", paddingChar = '0') private int numberOfRecordsInTheFile; }
问题单 7:在解析固定长度记录时跳过内容
通常与提供固定长度记录的系统集成,它们包含比目标用例所需信息更多的信息。在这种情况下,可以跳过那些我们不需要的字段的声明和解析。为此,如果下一个声明字段的 pos
值超过最后一个解析字段的光标位置,则 Bindy 将跳过转发到记录中的下一个映射字段。对感兴趣的字段使用绝对 pos
位置(而不是 ordinal 值)会导致 Bindy 在两个字段之间跳过内容。
同样,可能不包括一些字段以外的任何内容是值得关注的。在这种情况下,您可以通过在 @FixedLengthRecord
声明上设置 ignoreTrailingChars
属性来告知 Bindy 来跳过除最后一个映射字段外的所有内容的解析。
@FixedLengthRecord(ignoreTrailingChars = true) public static class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 3, length = 2) private String clientNr; // any characters that appear beyond the last mapped field will be ignored }
60.2.5. 5.消息
Message 注解用于识别模型的类,它们将包含键值对字段。这种类型的格式主要用于电信交换协议消息(FIX)。但是,此注解可用于通过键识别数据的任何其他格式。密钥对值通过分隔符相互分隔,可以是类似标签页的特殊字符(unicode 表示: \u0009
)或标题起始(unicode 表示: \u0001
)
要使用 FIX 消息,模型必须包含链接到根消息类的标头和 Trailer 类,该类可以是 Order 类。这并不是必须的,但当您将 camel-bindy 与 camel-fix 结合使用时,这是基于快速Fix 项目的修复网关时非常有用。
注解名称 | 记录类型 | 级别 |
---|---|---|
消息 | 键值对 | 类 |
参数名称 | 类型 | 必填 | 默认值 | info |
---|---|---|---|---|
keyValuePairSeparator | 字符串 | ✓ | 键值对分隔符用于从其键(必需)中分割值。可以是 '\u0001'、'\u0009'、'Evolution' 或 'anything'。 | |
pairSeparator | 字符串 | ✓ | 用于在令牌中分割键值对的对分隔符(必需)。可以是 '='、';' 或 'anything'。 | |
CRLF | 字符串 | WINDOWS | 用于在每个记录后(可选)添加cariage 返回的字符。可能的值 = WINDOWS、UNIX、MAC 或 custom。如果您指定了之前列出的三个值,则输入的值(custom)将用作 CRLF 字符。 | |
isOrdered | 布尔值 | false | 指明消息必须在输出中排序。此注解与模型的消息类关联,必须一次声明。 | |
name | 字符串 | 描述消息的名称(可选) | ||
type | 字符串 | FIX | type 用于定义消息的类型(如 FIX、EMX、…)(可选) | |
version | 字符串 | 4.1 | version 定义消息的版本(如 4.1、…)(可选) |
case 1 : separator = 'u0001'
用于隔离 FIX 消息中的键值对字段的分隔符是 ASCII 01
字符或 unicode 格式 \u0001
。必须再次转义此字符,以避免 java 运行时错误。下面是一个示例:
8=FIX.4.1 9=20 34=1 35=0 49=INVMGR 56=BRKR 1=BE.CHM.001 11=CHM0001-01 22=4 ...
如何使用注解:
FIX - 消息
@Message(keyValuePairSeparator = "=", pairSeparator = "\u0001", type="FIX", version="4.1") public class Order { }
查看测试问题单
选项卡等 ASCII 字符 … 无法在 WIKI 页面中显示。因此,有一个 camel-bindy 的测试问题单,以查看 FIX 消息看起来如何(https://github.com/apache/camel/blob/main/components/camel-bindy/src/test/data/fix/fix.txt)和 Order,Trailer, Header 类(https://github.com/apache/camel/blob/main/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/fix/simple/Order.java)。
60.2.6. 6.KeyValuePairField
KeyValuePairField 注释定义键值对字段的属性。每个 KeyValuePairField 都由标签(= key)及其值关联、类型(字符串、int、date、…)标识,可选模式,如果需要该字段。
注解名称 | 记录类型 | 级别 |
---|---|---|
KeyValuePairField | 关键价值 - FIX | 属性 |
参数名称 | 类型 | 必填 | 默认值 | info |
---|---|---|---|---|
tag | int | ✓ | 标签标识消息中的字段(必需)- 必须是唯一的 | |
impliedDecimalSeparator | 布尔值 | false | <b>Camel 2.11:</b> 指示一个十进制点,代表在指定位置上代表的十进制点 | |
name | 字符串 | 字段的名称(可选) | ||
pattern | 字符串 | 格式器将用于转换数据的模式(可选) | ||
position | int | 0 | 生成的消息中的字段位置 - 当 FIX 消息中的键/标签的位置必须不同 | |
精度 | int | 0 | 要创建的 BigDecimal 数的精度 | |
required | 布尔值 | false | 指明字段是否是必需的 | |
timezone | 字符串 | 要使用的时区。 |
问题单 1:标签
此参数表示消息中字段的键:
FIX 消息 - Tag
@Message(keyValuePairSeparator = "=", pairSeparator = "\u0001", type="FIX", version="4.1") public class Order { @Link Header header; @Link Trailer trailer; @KeyValuePairField(tag = 1) // Client reference private String Account; @KeyValuePairField(tag = 11) // Order reference private String ClOrdId; @KeyValuePairField(tag = 22) // Fund ID type (Sedol, ISIN, ...) private String IDSource; @KeyValuePairField(tag = 48) // Fund code private String SecurityId; @KeyValuePairField(tag = 54) // Movement type ( 1 = Buy, 2 = sell) private String Side; @KeyValuePairField(tag = 58) // Free text private String Text; }
问题单 2: 输出中的不同位置
如果我们放入 FIX 消息的 tag/keys 必须根据预定义的顺序进行排序,则使用注解 @KeyValuePairField
的属性 位置
。
FIX message - Tag - sort
@Message(keyValuePairSeparator = "=", pairSeparator = "\\u0001", type = "FIX", version = "4.1", isOrdered = true) public class Order { @Link Header header; @Link Trailer trailer; @KeyValuePairField(tag = 1, position = 1) // Client reference private String account; @KeyValuePairField(tag = 11, position = 3) // Order reference private String clOrdId; }
60.2.7. 7.部分
在固定长度记录的 FIX 消息中,通常以信息 : header, body 和 部分表示不同部分。注释 @Section
的目的是告知绑定模型的类代表标头(= section 1)、正文(= section 2)和页脚(= section 3)
此注解只有一个属性/参数。
注解名称 | 记录类型 | 级别 |
---|---|---|
部分 | FIX | 类 |
参数名称 | 类型 | 必填 | 默认值 | info |
---|---|---|---|---|
number | int | ✓ | 部分的数量 |
问题单 1:部分
header 部分的定义:
FIX message - Section - Header
@Section(number = 1) public class Header { @KeyValuePairField(tag = 8, position = 1) // Message Header private String beginString; @KeyValuePairField(tag = 9, position = 2) // Checksum private int bodyLength; }
body 部分的定义:
FIX message - Section - Body
@Section(number = 2) @Message(keyValuePairSeparator = "=", pairSeparator = "\\u0001", type = "FIX", version = "4.1", isOrdered = true) public class Order { @Link Header header; @Link Trailer trailer; @KeyValuePairField(tag = 1, position = 1) // Client reference private String account; @KeyValuePairField(tag = 11, position = 3) // Order reference private String clOrdId;
footer 部分的定义:
FIX 消息 - 第 - Footer
@Section(number = 3) public class Trailer { @KeyValuePairField(tag = 10, position = 1) // CheckSum private int checkSum; public int getCheckSum() { return checkSum; }
60.2.8. 8.OneToMany
注解 @OneToMany
的目的是允许使用 List<?&
gt; 字段定义 POJO 类或包含重复组的记录。
一个ToMany
的限制会小心,到许多绑定者的限制不允许处理在多个层次结构级别上定义的重复副本。
在以下情况下,关系 oneToMany WORKS:
- 读取包含重复组的 FIX 消息(= 标签/密钥组)
- 使用重复数据生成 CSV
注解名称 | 记录类型 | 级别 |
---|---|---|
OneToMany | all | 属性 |
参数名称 | 类型 | 必填 | 默认值 | info |
---|---|---|---|---|
mappedTo | 字符串 | 与 Class> 的 List<Type 类型关联的类名称 |
问题单 1:使用重复数据生成 CSV
以下是我们需要的 CSV 输出:
Claus,Ibsen,Camel in Action 1,2010,35 Claus,Ibsen,Camel in Action 2,2012,35 Claus,Ibsen,Camel in Action 3,2013,35 Claus,Ibsen,Camel in Action 4,2014,35
重复数据涉及本书的标题及其发布日期,而第一个、姓氏和年龄是通用的,用于建模这一点的类。Author 类包含书签列表。
使用重复数据生成 CSV
@CsvRecord(separator=",") public class Author { @DataField(pos = 1) private String firstName; @DataField(pos = 2) private String lastName; @OneToMany private List<Book> books; @DataField(pos = 5) private String Age; } public class Book { @DataField(pos = 3) private String title; @DataField(pos = 4) private String year; }
问题单 2:读取包含标签/密钥组的 FIX 消息
以下是在我们的模型中处理的消息:
8=FIX 4.19=2034=135=049=INVMGR56=BRKR 1=BE.CHM.00111=CHM0001-0158=this is a camel - bindy test 22=448=BE000124567854=1 22=548=BE000987654354=2 22=648=BE000999999954=3 10=220
标签 22、48 和 54 会被重复。
和代码:
读取包含标签/密钥组的 FIX 消息
public class Order { @Link Header header; @Link Trailer trailer; @KeyValuePairField(tag = 1) // Client reference private String account; @KeyValuePairField(tag = 11) // Order reference private String clOrdId; @KeyValuePairField(tag = 58) // Free text private String text; @OneToMany(mappedTo = "org.apache.camel.dataformat.bindy.model.fix.complex.onetomany.Security") List<Security> securities; } public class Security { @KeyValuePairField(tag = 22) // Fund ID type (Sedol, ISIN, ...) private String idSource; @KeyValuePairField(tag = 48) // Fund code private String securityCode; @KeyValuePairField(tag = 54) // Movement type ( 1 = Buy, 2 = sell) private String side; }
60.2.9. 9.BindyConverter
注释 @BindyConverter
的目的是定义一个在字段级别使用的转换器。提供的类必须实施 Format 接口。
@FixedLengthRecord(length = 10, paddingChar = ' ') public static class DataModel { @DataField(pos = 1, length = 10, trim = true) @BindyConverter(CustomConverter.class) public String field1; } public static class CustomConverter implements Format<String> { @Override public String format(String object) throws Exception { return (new StringBuilder(object)).reverse().toString(); } @Override public String parse(String string) throws Exception { return (new StringBuilder(string)).reverse().toString(); } }
60.2.10. 10.FormatFactories
注释 @FormatFactories
的目的是在记录级别定义一组转换器。提供的类必须实施 FormatFactoryInterface
接口。
@CsvRecord(separator = ",") @FormatFactories({OrderNumberFormatFactory.class}) public static class Order { @DataField(pos = 1) private OrderNumber orderNr; @DataField(pos = 2) private String firstName; } public static class OrderNumber { private int orderNr; public static OrderNumber ofString(String orderNumber) { OrderNumber result = new OrderNumber(); result.orderNr = Integer.valueOf(orderNumber); return result; } } public static class OrderNumberFormatFactory extends AbstractFormatFactory { { supportedClasses.add(OrderNumber.class); } @Override public Format<?> build(FormattingOptions formattingOptions) { return new Format<OrderNumber>() { @Override public String format(OrderNumber object) throws Exception { return String.valueOf(object.orderNr); } @Override public OrderNumber parse(String string) throws Exception { return OrderNumber.ofString(string); } }; } }