57.2. 注解


创建的注解允许将模型的不同概念映射到 POJO,如下所示:

  • 记录类型(CSV、键值对(如 FIX 消息)、固定 length …​)
  • 链接(指向另一个对象中的链接对象),
  • DataField 及其属性(int、type、…​)
  • KeyValuePairField (用于 key = value 格式,如我们在修复财务消息中一样)
  • 部分(用于识别标头、正文和页脚部分),
  • OneToMany,
  • BindyConverter,
  • FormatFactories

本节将描述它们。

57.2.1. 1.CsvRecord

CsvRecord 注解用于识别模型的根类。它代表记录 = " CSV 文件行",并可链接到多个子模型类。

注解名称记录类型级别

CsvRecord

CSV

参数名称类型必填默认值info

分隔符

字符串

 

用于在令牌中分割记录的分隔符(必需)- 可以是 ',' 或 ';' 或 'anything'。支持的唯一空格字符是 tab (\t)。不支持其他空格字符(空格)。这个值被解释为正则表达式。如果要使用在正则表达式中具有特殊含义的符号,如 '|' 符号,您必须屏蔽它,如 '|'。

allowEmptyStream

布尔值

 

false

allowEmptyStream 参数将允许 prcoess CSV 文件无法查询的流。

autospanLine

布尔值

 

false

最后一个记录涵盖其余行(可选)- 如果启用,则最后一列会自动跨越行尾,例如,如果其注释,则允许行包含所有字符,也是分隔符字符。

CRLF

字符串

 

WINDOWS

用于在每次记录后(可选)添加回车符的字符 - 允许定义要使用的回车符。如果您指定之前列出的三个值,则您输入的值(custom)将用作 CRLF 字符。可以使用三个值:WINDOWS、UNIX、MAC 或自定义。

endWithLineBreak

布尔值

 

true

如果 CSV 文件应该以换行符或没有行结尾(可选)

generateHeaderColumns

布尔值

 

false

generateHeaderColumns 参数允许在 CSV 中添加,生成的标头包含列的名称

isOrdered

布尔值

 

false

指明信息是否必须在输出中排序

name

字符串

  

描述记录的名称(可选)

quote

字符串

 

"

是否使用给定引号字符(可选)替换列(可选)- 在生成 CSV 时可以指定字段的引号字符。此注解与模型的根类关联,必须一次性声明。

引用

布尔值

 

false

指明值(和标头)是否在 marshaling 时加上引号(可选)

quotingEscaped

布尔值

 

false

指明值在 quoting 时是否必须转义(可选)

removeQuotes

布尔值

 

true

如果 unmarshalling 应该为每个字段删除引号,则 remove quotes 参数标志

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 {

}

case 5 : 分隔符和跳过FirstLine

当客户端要在文件的第一行(数据字段的名称)中时,这个功能非常有趣:

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:回车符

如果运行 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;

}

__

pos 用于解析文件流,而 位置 则用于生成 CSV。

57.2.3. 3.DataField

DataField 注解定义字段的属性。每个 datafield 都由记录中的位置、类型(字符串、int、date、…​)以及可选的模式来标识。

注解名称记录类型级别

DataField

all

属性

参数名称类型必填默认值info

pos

int

 

输入记录中数据的位置,必须从 1 开始(必需)。查看 position 参数。

align

字符串

 

R

将文本与右侧或左对齐。使用值 <tt>R</tt> 或 <tt>L</tt>。

Clip

布尔值

 

false

如果在使用固定长度时超过允许的长度,则指示在字段中允许的数据。

columnName

字符串

  

标头列的名称(可选)。将属性的名称用作默认值。仅在 CsvRecord has generateHeaderColumns = true时才适用

decimalSeparator

字符串

  

用于 BigDecimal 数字的十进制 Separator

defaultValue

字符串

  

如果没有设置值,则字段的默认值

delimiter

字符串

  

如果字段有变量长度,则使用可选分隔符

groupingSeparator

字符串

  

当我们将 Separator 分组到要与 BigDecimal 号一起使用的 Separator,使用分组,例如 123,456.789

impliedDecimalSeparator

布尔值

 

false

指明是否有十进制点代表在指定位置

length

int

 

0

如果记录设置为固定长度,则数据块的长度(字符数)

lengthPos

int

 

0

在记录中标识定义此字段预期的固定长度的 data 字段

方法

字符串

  

在 DataField 上调用以应用此类自定义的方法名称。这必须是 datafield 本身的方法,或者您必须提供类方法的静态完全限定名称,如:请参阅单元测试 org.apache.camel.dataformat.bindy.csv.BindySimpleCsvFunctionWithExternalMethodTest.replaceToBar

name

字符串

  

字段的名称(可选)

paddingChar

char

  

如果记录被设置为固定长度,则带有 char to pad

pattern

字符串

  

Java 格式化器(例如 simpleDateFormat)的模式,它将用于转换数据(可选)。如果使用模式,则建议在绑定数据格式中设置 locale。设置为已知区域设置,如 "us" 或 "default" 来使用平台默认区域设置。

position

int

 

0

生成输出消息中的字段位置(应该从 1 开始)。在 CSV 生成的字段的位置(输出消息)的位置必须与输入位置(pos)不同时,必须使用。请参阅 pos 参数。

精度

int

 

0

要创建的 \{@link java.math.BigDecimal} 号

required

布尔值

 

false

指明字段是否强制

rounding

字符串

 

CEILING

round 模式用于舍入/scale a BigDecimal Values : UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN,HALF_EVEN, UNNECESSARY e.g : Number = 123456.789, Precision = 2, Rounding = CEILING Result: 123456.79.

timezone

字符串

  

要使用的时区。

trim

布尔值

 

false

指明值是否应该修剪

问题单 1:pos

此参数/attribute 代表 CSV 记录中字段的位置。

position

@CsvRecord(separator = ",")
public class Order {

    @DataField(pos = 1)
    private int orderNr;

    @DataField(pos = 5)
    private String isinCode;

}

如本例中所示,位置从 1 开始,但在类 Order 中继续 5。从 24 的数字在类客户端中定义(请参阅之后)。

在另一个模型类中继续

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:位置在输出中有所不同

position 属性将通知如何将字段放在 CSV 记录中。默认情况下,所用的位置与通过属性 pos 定义的位置对应。如果位置不同(这意味着我们有一个身份统计进程与 unmarshaling 的比较),那么我们可以使用 位置 来指明这一点。

下面是一个示例:

在输出中位置不同

@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 的 attribute 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 :

问题单 6:修剪

如果字段在处理前应该删除的前导和/或尾随空格,只需使用属性 trim 设为 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;
}

case 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;
}

case 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;
}

此属性仅适用于可选字段。

57.2.4. 4.FixedLengthRecord

FixedLengthRecord 注解用于识别模型的根类。它代表记录 = "一个文件/消息行包含数据固定长度(字符数)格式",并可链接到多个子模型类。这个格式是有点的,因为字段的数据可以与右侧或左侧一致。

当数据的大小没有完全填满字段的长度时,我们可以添加"平板"字符。

注解名称记录类型级别

FixedLengthRecord

已修复

参数名称类型必填默认值info

countGrapheme

布尔值

 

false

指明如何计算收费

CRLF

字符串

 

WINDOWS

用于在每次记录后添加回车符(可选)。可能的值: WINDOWS、UNIX、MAC 或自定义。这个选项仅在 marshalling 期间使用,除非自定义 eol,否则 unmarshalling 使用系统默认 JDK 提供的行分隔符。

EOL

字符串

  

用来在 unmarshalling 时处理在各个记录后考虑行结尾的字符(可选 - default: "",它有助于使用默认 JDK 提供的行分隔符),除非提供任何其他行分隔符,否则此选项仅在 unmarshalling 期间使用,其中 marshalling 使用系统默认行分隔符作为"WINDOWS",除非提供了任何其他值。

footer

 

void

表示此类型的记录后可以跟随文件末尾的单个页脚记录

header

 

void

表示此类型的记录在文件的开头之间可以加上一个标头记录

ignoreMissingChars

布尔值

 

false

指明是否忽略短行

ignoreTrailingChars

布尔值

 

false

当解压缩 / 解析时,可以忽略超出最后一个映射文件的字符。此注解与模型的根类关联,必须一次性声明。

length

int

 

0

记录的固定长度(字符数)。这意味着记录始终是带有 \{#paddingChar ()} 的较长的 padded。

name

字符串

  

描述记录的名称(可选)

paddingChar

char

  

收费到平板,

skipFooter

布尔值

 

false

配置数据格式以跳过页脚记录的 / unmarshalling。在主记录上配置此参数(例如,而不是标头或页脚)。

skipHeader

布尔值

 

false

配置数据格式以跳过标题记录的 / unmarshalling / 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 的长度记录

这更高级的示例演示了如何为字段定义对齐以及如何分配"这里 "的 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: Field padding

有时,为记录定义的默认 padding 不能应用于字段,因为我们有一个数字格式,我们想使用 '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

fixed- separated

@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;
}

可以使用 ordinal、sequential 值而不是精确的列号来定义固定长度记录中的 pos 值。

案例 5:修复长度的长度记录,记录定义的字段长度

有时,固定长度记录可能包含一个字段,用来定义同一记录中另一个字段的预期长度。在以下示例中,instrumentNumber 字段值的长度由记录中的 instrumentNumberLen 字段的值定义。

10A9Pauline^M^ISIN10XD12345678BUYShare000002500.45USD01-08-2009

fixed- separated

@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;
}

case 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

}

57.2.5. 5.消息

Message 注解用于识别模型的类,它们将包含键值对字段。这种格式主要在财务交换协议消息(FIX)中使用。但是,此注解可用于任何其他格式,其中数据由键标识。密钥对值可以通过分隔符相互分隔,可以是类似 tab delimitor (unicode 表示 : \u0009)或头头(unicode 表示 : \u0001)的特殊字符。

注意

要处理 FIX 消息,模型必须包含链接到根消息类的标头和 Trailer 类,可以是 Order 类。这不是强制性的,但当您结合使用 camel-bindy 与 camel-fix 的组合时,这是基于快速Fix 项目的修复网关。

注解名称记录类型级别

消息

键值对

参数名称类型必填默认值info

keyValuePairSeparator

字符串

 

键值对分隔符用于从其键中分离值(必需)。可以是 '\u0001', '\u0009', '#', 或 'anything'。

pairSeparator

字符串

 

用于分割令牌中的键值对的对分隔符(必需)。可以是 '='、';' 或 'anything'。

CRLF

字符串

 

WINDOWS

用于在每次记录后添加回车符(可选)。可能的值 = WINDOWS、UNIX、MAC 或自定义.如果您指定之前列出的三个值,则您输入的值(custom)将用作 CRLF 字符。

isOrdered

布尔值

 

false

指明消息是否必须在输出中排序。此注解与模型的消息类关联,必须一次性声明。

name

字符串

  

描述消息的名称(可选)

type

字符串

 

修复

type 用于定义消息的类型(如 FIX、EMX、…​)(可选)

version

字符串

 

4.1

version 定义消息的版本(如 4.1、…​)(可选)

问题单 1:分隔符 = '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 class (https://github.com/apache/camel/blob/main/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/fix/simple/Order.java)。

57.2.6. 6.KeyValuePairField

KeyValuePairField 注解定义键值对字段的属性。每个 KeyValuePairField 都由标签(= key)及其值关联、类型(字符串、int、date、…​)标识,可选模式,如果需要该字段。

注解名称记录类型级别

KeyValuePairField

Key Value Pair - FIX

属性

参数名称类型必填默认值info

tag

int

 

标识消息中的字段的标签(必需)- 必须是唯一的

impliedDecimalSeparator

布尔值

 

false

<b>Camel 2.11:</b> 表示是否有十进制点表示在指定位置

name

字符串

  

字段的名称(可选)

pattern

字符串

  

格式器将用于转换数据的模式(可选)

position

int

 

0

生成消息中的字段位置 - 在 FIX 消息中的 key/tag 的位置必须不同时使用

精度

int

 

0

要创建的 BigDecimal 数量的精度

required

布尔值

 

false

指明字段是否强制

timezone

字符串

  

要使用的时区。

问题单 1:标签

此参数代表消息中的字段键:

FIX message - 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 消息中的 tags/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;
}

57.2.7. 7.部分

在修复固定长度记录的消息中,在信息 : header、body 和 部分表示中,通常有不同的部分。注释 @Section 的目的是通知模型的绑定表示标头(= 第 1 节)、正文(= 部分 2)和页脚(= 第 3 节)

此注释仅存在一个属性/参数。

注解名称记录类型级别

部分

修复

参数名称类型必填默认值info

number

int

 

部分的数量

问题单 1:部分

标头部分的定义:

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 message - Section - Footer

@Section(number = 3)
public class Trailer {

    @KeyValuePairField(tag = 10, position = 1)
    // CheckSum
    private int checkSum;

    public int getCheckSum() {
        return checkSum;
    }

57.2.8. 8.OneToMany

注释 @OneToMany 的目的是允许使用 List<?> 字段来定义 POJO 类,或者从包含重复组的记录。

注意

OneToMany
的限制要小心,很多绑定都不允许处理在几个层次结构级别上定义的重复请求。

在以下情况下,关系 oneToMany ONLY 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 类包含 Book 的列表。

使用重复数据生成 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:阅读包含标签/密钥组的消息

以下是要在我们模型中处理的消息:

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 会重复。

和代码:

读取包含 tags/keys 组的 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;
}

57.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();
    }
}

57.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);
            }
        };
    }
}
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.