目录
java
1.报文基础信息与适用范围
2.全量必填 / 选填字段清单(分层:AppHdr、GrpHdr、CdtTrfTxInf)
3.SWIFT MT103 与 pacs.008 V08 字段一一映射表
4.生产级强制校验规则(CBPR + 跨境标准)
5.异常与合规校验清单(反洗钱 / 制裁筛查)
6.XSD 引用、XML 编码、日期金额统一规范
1 报文基础信息
1.1 标准标识
java
报文名称:FIToFICustomerCreditTransferV08
报文 ID:`pacs.008.001.08`
命名空间:`urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08`
XSD 文件名:`pacs.008.001.08.xsd`
业务定位:行间客户贷记转账,替代 SWIFT MT103,CBPR + 跨境支付强制报文
1.2 参与方与流转
java
1.企业下发 pain.001 → 付款行
2.付款行内部记账,组装 pacs.008.001.08
3.SWIFT / 清算系统转发中间行
4.收款行解析报文入账
5.回执:pacs.002 交易状态回执
1.3 硬性约束(CBPR+)
java
1.单报文仅允许 1 条 `<CdtTrfTxInf>`,多笔必须拆多份报文
2.UETR 全局 36 位 UUID,跨境场景**强制必填**
3.收付款人、最终收付款人身份结构化字段不可使用纯自由文本
4.行间清算金额与客户交易金额分离,禁止混用
2 分层字段清单(M = 必选 O = 可选 C = 条件必填)
2.1 顶层结构
xml
<Document>
<AppHdr/> <!-- 应用头:路由层,所有场景M -->
<FIToFICstmrCdtTrf>
<GrpHdr/> <!-- 批次组头,M -->
<CdtTrfTxInf/> <!-- 交易明细,M,仅1条 -->
</FIToFICstmrCdtTrf>
</Document>
2.2 AppHdr 应用报文头

2.3 GrpHdr 批次组头(整批公共信息)

2.4 CdtTrfTxInf 单笔交易核心
2.4.1 交易标识 PmtId

2.4.2 清算、费用、金额

2.4.3 付款人 Dbtr(付款客户)M
强制结构化字段(跨境全部 M)
- Nm:姓名 / 企业全称 M
- PstlAdr:结构化地址(StrtNm/BldgNb/PstCd/TwnNm/Ctry)C
- Id:身份证件 / 法人 LEI C
- 自然人:PrvtId (IdCardTp/IdNb/DtOfBirth)
- 法人:OrgId/LEI(跨境强制 LEI)
2.4.4 DbtrAcct 付款人账户 M
Id/IBAN:跨境优先 IBAN
Id/Othr/Id:境内本地账号
2.4.5 DbtrAgt 付款行 M
FinInstnId/BICFI:11 位 BICFI
2.4.6 IntrmyAgt1~3 中间行 O
跨境中转时 C,最多 3 级,BICFI 必填
2.4.7 CdtrAgt 收款行 M
BICFI 必填
2.4.8 Cdtr 收款人 M
同 Dbtr 结构化身份规范
2.4.9 CdtrAcct 收款人账户 M
IBAN / 本地账号
2.4.10 UltmtDbtr 最终付款人 C
跨境反洗钱强制 M;多层代付场景必填
2.4.11 UltmtCdtr 最终收款人 C
跨境强制 M
2.4.12 RmtInf 附言 O
- Ustrd:自由文本附言(兼容旧系统)
- Strd:结构化发票 / 订单号(推荐用于自动化对账)
2.4.13 Purp 交易用途 O
交易代码:SALA 工资 / TRADE 贸易 / INVS 投资等
3 MT103 VS pacs.008.001.08 字段映射表

4 生产级强制校验规则
4.1 基础格式校验
java
1.所有日期时间严格 ISO8601,时区 Z(UTC),禁止本地时间无时区
2.金额:
JPY 小数位 0 位;CNY/USD/EUR 2 位
数值必须大于 0,禁止 0 / 负数
3.币种必须 3 位 ISO4217 大写编码
4.BICFI 固定 11 位,最后三位分支码 XXX,大小写统一大写
5.UETR 正则校验:`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`
4.2 CBPR + 业务强校验(跨境支付必实现)
java
1.GrpHdr.NbOfTxs 必须等于 1
2.AppHdr.UETR 与 CdtTrfTxInf.PmtId.UETR 完全一致
3.Dbtr、Cdtr、UltmtDbtr、UltmtCdtr 必须携带结构化身份,禁止仅传名称无证件 / LEI
4.SttlmMtd 只能取 CLRG / INDA / COVE 三者之一
5.ChrgBr 只能 SHAR / DEBT / CRDT
6.CtrlSum 必须等于 IntrBkSttlmAmt(单笔场景)
4.3 路由校验
- Fr (BICFI) != To (BICFI),禁止自转发报文
- 中间行 BIC 不可与付款行 / 收款行重复,防止循环路由
5 合规 / 反洗钱校验清单(上线必过)
- 法人客户必须携带 LEI 编号(跨境 FATF 强制)
- 自然人必须携带证件类型、证件号、出生日期
- 地址分层填写:街道、门牌号、邮编、城市、国家二字母代码
- 存在代付 / 代收款场景必须填充 UltmtDbtr/UltmtCdtr
- 名称字段禁止特殊非法字符(&<> 等 XML 转义必须处理)
- 禁止姓名、地址、证件号为空或仅空格
6 统一编码与 XML 规范
6.1 编码
- 文件编码:UTF-8
- XML 头部固定:
<?xml version="1.0" encoding="UTF-8"?>
6.2 XSD 校验引入
开发环境校验报文合法性,导入官方 xsd:
pacs.008.001.08.xsd + 公共基础 xsd(iso20022_Common.xsd)
7 完整可校验生产报文(跨境 USD 汇款)
java
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08">
<!-- 应用头 路由层 -->
<AppHdr>
<MsgId>SHANGHAIBANK202608080001</MsgId>
<CreDtTm>2026-08-08T08:30:25Z</CreDtTm>
<Fr>
<BICFI>ABCICNSHXXX</BICFI>
</Fr>
<To>
<BICFI>CHASUSNYXXX</BICFI>
</To>
<MsgTp>pacs.008.001.08</MsgTp>
<BizMsgIdr>TRACK26080800001</BizMsgIdr>
<UETR>550e8400-e29b-41d4-a716-446655440000</UETR>
</AppHdr>
<FIToFICstmrCdtTrf>
<GrpHdr>
<MsgId>GRP00000001</MsgId>
<CreDtTm>2026-08-08T08:30:25Z</CreDtTm>
<NbOfTxs>1</NbOfTxs>
<CtrlSum>15800.50</CtrlSum>
<SttlmInf>
<SttlmMtd>CLRG</SttlmMtd>
<SttlmDt>2026-08-08</SttlmDt>
<TtlIntrBkSttlmAmt Ccy="USD">15800.50</TtlIntrBkSttlmAmt>
</SttlmInf>
</GrpHdr>
<!-- 单笔交易 -->
<CdtTrfTxInf>
<PmtId>
<EndToEndId>ERP-SUP-20260808-001</EndToEndId>
<UETR>550e8400-e29b-41d4-a716-446655440000</UETR>
</PmtId>
<IntrBkSttlmAmt Ccy="USD">15800.50</IntrBkSttlmAmt>
<ChrgBr>SHAR</ChrgBr>
<!-- 付款企业客户 -->
<Dbtr>
<Nm>上海国际贸易有限公司</Nm>
<PstlAdr>
<StrtNm>张江大道</StrtNm>
<BldgNb>1200</BldgNb>
<PstCd>201203</PstCd>
<TwnNm>上海</TwnNm>
<Ctry>CN</Ctry>
</PstlAdr>
<Id>
<OrgId>
<LEI>549300XYZABC12345678</LEI>
</OrgId>
</Id>
</Dbtr>
<DbtrAcct>
<Id>
<Othr>
<Id>0208001234567890</Id>
</Othr>
</Id>
</DbtrAcct>
<DbtrAgt>
<FinInstnId>
<BICFI>ABCICNSHXXX</BICFI>
</FinInstnId>
</DbtrAgt>
<!-- 中间行(可选) -->
<IntrmyAgt1>
<FinInstnId>
<BICFI>BOFAUSNYXXX</BICFI>
</FinInstnId>
</IntrmyAgt1>
<!-- 收款行 -->
<CdtrAgt>
<FinInstnId>
<BICFI>CHASUSNYXXX</BICFI>
</FinInstnId>
</CdtrAgt>
<!-- 境外收款人自然人 -->
<Cdtr>
<Nm>Michael Smith</Nm>
<PstlAdr>
<StrtNm>Park Ave</StrtNm>
<BldgNb>50</BldgNb>
<PstCd>10001</PstCd>
<TwnNm>New York</TwnNm>
<Ctry>US</Ctry>
</PstlAdr>
<Id>
<PrvtId>
<IdCardTp>PASS</IdCardTp>
<IdNb>123456789</IdNb>
<DtOfBirth>1985-03-12</DtOfBirth>
</PrvtId>
</Id>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>US21CHAS01234567890123</IBAN>
</Id>
</CdtrAcct>
<!-- 最终付款人(跨境合规必填) -->
<UltmtDbtr>
<Nm>上海国际贸易有限公司</Nm>
<Id>
<OrgId>
<LEI>549300XYZABC12345678</LEI>
</OrgId>
</Id>
</UltmtDbtr>
<!-- 附言 -->
<RmtInf>
<Ustrd>August 2026 goods payment PO2026070018</Ustrd>
</RmtInf>
<Purp>
<Cd>TRAD</Cd>
</Purp>
</CdtTrfTxInf>
</FIToFICstmrCdtTrf>
</Document>
8 报文校验
xml
<!-- pom.xml -->
<dependencies>
<!-- JAXB jakarta 适配 JDK17+/21 -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.2</version>
<scope>runtime</scope>
</dependency>
<!-- 工具类校验 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
8.1. 顶层文档对象 Document.java
java
package com.iso20022.pacs008.v08.model;
import jakarta.xml.bind.annotation.*;
import lombok.Data;
@Data
@XmlRootElement(name = "Document", namespace = "urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08")
@XmlAccessorType(XmlAccessType.FIELD)
public class Document {
@XmlElement(name = "AppHdr")
private AppHdr appHdr;
@XmlElement(name = "FIToFICstmrCdtTrf")
private FIToFICstmrCdtTrf fiToFiCstmrCdtTrf;
}
8.2. 应用头 AppHdr.java(路由层)
java
package com.iso20022.pacs008.v08.model;
import jakarta.xml.bind.annotation.*;
import lombok.Data;
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class AppHdr {
@XmlElement(name = "MsgId")
private String msgId;
@XmlElement(name = "CreDtTm")
private String creDtTm;
@XmlElement(name = "Fr")
private BicFi fr;
@XmlElement(name = "To")
private BicFi to;
@XmlElement(name = "MsgTp")
private String msgTp;
@XmlElement(name = "BizMsgIdr")
private String bizMsgIdr;
@XmlElement(name = "UETR")
private String uetr;
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class BicFi {
@XmlElement(name = "BICFI")
private String bicfi;
}
8.3. 外层业务主体 FIToFICstmrCdtTrf.java
java
package com.iso20022.pacs008.v08.model;
import jakarta.xml.bind.annotation.*;
import lombok.Data;
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class FIToFICstmrCdtTrf {
@XmlElement(name = "GrpHdr")
private GrpHdr grpHdr;
@XmlElement(name = "CdtTrfTxInf")
private CdtTrfTxInf cdtTrfTxInf;
}
8.4. 批次组头 GrpHdr.java
java
package com.iso20022.pacs008.v08.model;
import jakarta.xml.bind.annotation.*;
import lombok.Data;
import java.math.BigDecimal;
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class GrpHdr {
@XmlElement(name = "MsgId")
private String msgId;
@XmlElement(name = "CreDtTm")
private String creDtTm;
@XmlElement(name = "NbOfTxs")
private Integer nbOfTxs;
@XmlElement(name = "CtrlSum")
private BigDecimal ctrlSum;
@XmlElement(name = "SttlmInf")
private SttlmInf sttlmInf;
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class SttlmInf {
@XmlElement(name = "SttlmMtd")
private String sttlmMtd;
@XmlElement(name = "SttlmDt")
private String sttlmDt;
@XmlElement(name = "TtlIntrBkSttlmAmt")
private Amount ttlIntrBkSttlmAmt;
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class Amount {
@XmlAttribute(name = "Ccy")
private String ccy;
@XmlValue
private BigDecimal value;
}
8.5. 核心交易明细 CdtTrfTxInf.java
java
package com.iso20022.pacs008.v08.model;
import jakarta.xml.bind.annotation.*;
import lombok.Data;
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class CdtTrfTxInf {
@XmlElement(name = "PmtId")
private PmtId pmtId;
@XmlElement(name = "IntrBkSttlmAmt")
private Amount intrBkSttlmAmt;
@XmlElement(name = "ChrgBr")
private String chrgBr;
// 付款人
@XmlElement(name = "Dbtr")
private Party dbtr;
// 付款人账户
@XmlElement(name = "DbtrAcct")
private Account dbtrAcct;
// 付款行
@XmlElement(name = "DbtrAgt")
private FinInstAgt dbtrAgt;
// 中间行1
@XmlElement(name = "IntrmyAgt1")
private FinInstAgt intrmyAgt1;
// 收款行
@XmlElement(name = "CdtrAgt")
private FinInstAgt cdtrAgt;
// 收款人
@XmlElement(name = "Cdtr")
private Party cdtr;
// 收款人账户
@XmlElement(name = "CdtrAcct")
private Account cdtrAcct;
// 最终付款人
@XmlElement(name = "UltmtDbtr")
private Party ultmtDbtr;
// 最终收款人
@XmlElement(name = "UltmtCdtr")
private Party ultmtCdtr;
// 附言
@XmlElement(name = "RmtInf")
private RmtInf rmtInf;
// 交易用途
@XmlElement(name = "Purp")
private Purp purp;
}
// 交易流水标识
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class PmtId {
@XmlElement(name = "EndToEndId")
private String endToEndId;
@XmlElement(name = "UETR")
private String uetr;
@XmlElement(name = "InstrId")
private String instrId;
}
// 机构行(付款行/收款行/中间行)
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class FinInstAgt {
@XmlElement(name = "FinInstnId")
private BicFi finInstnId;
}
// 收付款人主体(自然人/企业)
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class Party {
@XmlElement(name = "Nm")
private String nm;
@XmlElement(name = "PstlAdr")
private PostalAddr pstlAdr;
@XmlElement(name = "Id")
private PartyId id;
}
// 结构化地址
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class PostalAddr {
@XmlElement(name = "StrtNm")
private String strtNm;
@XmlElement(name = "BldgNb")
private String bldgNb;
@XmlElement(name = "PstCd")
private String pstCd;
@XmlElement(name = "TwnNm")
private String twnNm;
@XmlElement(name = "Ctry")
private String ctry;
}
// 客户身份:企业LEI / 自然人证件
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class PartyId {
@XmlElement(name = "OrgId")
private OrgId orgId;
@XmlElement(name = "PrvtId")
private PrvtId prvtId;
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class OrgId {
@XmlElement(name = "LEI")
private String lei;
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class PrvtId {
@XmlElement(name = "IdCardTp")
private String idCardTp;
@XmlElement(name = "IdNb")
private String idNb;
@XmlElement(name = "DtOfBirth")
private String dtOfBirth;
}
// 账户信息 IBAN/本地账号
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class Account {
@XmlElement(name = "Id")
private AccountId id;
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class AccountId {
@XmlElement(name = "IBAN")
private String iban;
@XmlElement(name = "Othr")
private OtherAccount othr;
}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class OtherAccount {
@XmlElement(name = "Id")
private String id;
}
// 附言信息
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class RmtInf {
@XmlElement(name = "Ustrd")
private String ustrd;
}
// 交易用途代码
@Data
@XmlAccessorType(XmlAccessType.FIELD)
class Purp {
@XmlElement(name = "Cd")
private String cd;
}
9 报文统一校验工具类 Pacs008ValidatorUtil
java
package com.iso20022.pacs008.v08.util;
import com.iso20022.pacs008.v08.model.Document;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.regex.Pattern;
public class Pacs008ValidatorUtil {
// UETR UUID正则
private static final Pattern UETR_PATTERN = Pattern.compile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
// BICFI 11位大写字母数字
private static final Pattern BICFI_PATTERN = Pattern.compile("^[A-Z0-9]{11}$");
// 支持币种小数位数配置
private static final Map<String, Integer> CURR_DECIMAL_MAP = new HashMap<>();
// 清算方式枚举
public static final Set<String> VALID_STTL_MTD = Set.of("CLRG", "INDA", "COVE");
// 费用承担枚举
public static final Set<String> VALID_CHARGE_BR = Set.of("SHAR", "DEBT", "CRDT");
static {
CURR_DECIMAL_MAP.put("JPY", 0);
CURR_DECIMAL_MAP.put("USD", 2);
CURR_DECIMAL_MAP.put("CNY", 2);
CURR_DECIMAL_MAP.put("EUR", 2);
CURR_DECIMAL_MAP.put("GBP", 2);
}
// 1. UETR 格式校验
public static boolean validUetr(String uetr) {
if (uetr == null || uetr.isBlank()) return false;
return UETR_PATTERN.matcher(uetr).matches();
}
// 2. BICFI 11位校验
public static boolean validBicFi(String bic) {
if (bic == null || bic.isBlank()) return false;
return BICFI_PATTERN.matcher(bic).matches();
}
// 3. 金额校验:正数、小数位匹配币种
public static String validAmount(BigDecimal amt, String ccy) {
if (amt == null) return "金额不能为空";
if (amt.compareTo(BigDecimal.ZERO) <= 0) return "金额必须大于0";
int expectDec = CURR_DECIMAL_MAP.getOrDefault(ccy, 2);
BigDecimal scaled = amt.setScale(expectDec, RoundingMode.FLOOR);
if (!scaled.equals(amt)) {
return String.format("币种%s仅允许%d位小数", ccy, expectDec);
}
return null;
}
// 4. 校验ISO8601 UTC时间格式 CreDtTm
public static boolean validIsoDateTime(String dtStr) {
if (dtStr == null || dtStr.isBlank()) return false;
try {
OffsetDateTime.parse(dtStr, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
return true;
} catch (DateTimeParseException e) {
return false;
}
}
// 5. 交割日校验 yyyy-MM-dd
public static boolean validSttlmDate(String dateStr) {
if (dateStr == null || dateStr.isBlank()) return false;
try {
LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE);
return true;
} catch (DateTimeParseException e) {
return false;
}
}
// 6. XML特殊字符转义(避免报文解析报错)
public static String xmlEscape(String text) {
if (text == null) return "";
return text.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'");
}
// 7. CBPR+ 全量业务校验入口,返回异常信息列表
public static List<String> cbprFullCheck(Document doc) {
List<String> errList = new ArrayList<>();
if (doc == null) {
errList.add("报文根节点Document为空");
return errList;
}
// 7.1 AppHdr 校验
var appHdr = doc.getAppHdr();
if (appHdr == null) errList.add("AppHdr应用头缺失");
else {
if (!validIsoDateTime(appHdr.getCreDtTm())) errList.add("AppHdr.CreDtTm时间格式非法");
if (!validBicFi(appHdr.getFr().getBicfi())) errList.add("发送行Fr.BICFI格式错误");
if (!validBicFi(appHdr.getTo().getBicfi())) errList.add("接收行To.BICFI格式错误");
if (!"pacs.008.001.08".equals(appHdr.getMsgTp())) errList.add("MsgTp必须为pacs.008.001.08");
// CBPR+强制UETR
if (!validUetr(appHdr.getUetr())) errList.add("跨境报文UETR格式非法/缺失");
}
// 7.2 GrpHdr 校验
var fiTrf = doc.getFiToFiCstmrCdtTrf();
if (fiTrf == null) {
errList.add("FIToFICstmrCdtTrf业务主体缺失");
return errList;
}
var grp = fiTrf.getGrpHdr();
if (grp == null) errList.add("GrpHdr批次头缺失");
else {
if (!Integer.valueOf(1).equals(grp.getNbOfTxs())) errList.add("CBPR+单报文交易数NbOfTxs必须=1");
var sttlm = grp.getSttlmInf();
if (sttlm == null) errList.add("SttlmInf清算信息缺失");
else {
if (!VALID_STTL_MTD.contains(sttlm.getSttlmMtd())) errList.add("SttlmMtd仅支持CLRG/INDA/COVE");
if (!validSttlmDate(sttlm.getSttlmDt())) errList.add("SttlmDt交割日期格式错误");
var totalAmt = sttlm.getTtlIntrBkSttlmAmt();
String amtErr = validAmount(totalAmt.getValue(), totalAmt.getCcy());
if (amtErr != null) errList.add("批次总金额校验失败:" + amtErr);
}
}
// 7.3 单笔交易校验
var tx = fiTrf.getCdtTrfTxInf();
if (tx == null) {
errList.add("CdtTrfTxInf交易明细缺失");
return errList;
}
// UETR上下一致
if (!appHdr.getUetr().equals(tx.getPmtId().getUetr())) {
errList.add("AppHdr.UETR与PmtId.UETR不一致");
}
// 费用承担
if (!VALID_CHARGE_BR.contains(tx.getChrgBr())) {
errList.add("ChrgBr费用承担仅支持SHAR/DEBT/CRDT");
}
// 交易金额
String txAmtErr = validAmount(tx.getIntrBkSttlmAmt().getValue(), tx.getIntrBkSttlmAmt().getCcy());
if (txAmtErr != null) errList.add("交易清算金额校验失败:" + txAmtErr);
// 付款行/收款行BIC
if (!validBicFi(tx.getDbtrAgt().getFinInstnId().getBicfi())) errList.add("付款行DbtrAgt BICFI非法");
if (!validBicFi(tx.getCdtrAgt().getFinInstnId().getBicfi())) errList.add("收款行CdtrAgt BICFI非法");
return errList;
}
}
10 JAXB 序列化 / 反序列化工具
java
package com.iso20022.pacs008.v08.util;
import com.iso20022.pacs008.v08.model.Document;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;
public class Pacs008XmlUtil {
private static JAXBContext context;
static {
try {
context = JAXBContext.newInstance(Document.class);
} catch (JAXBException e) {
throw new RuntimeException("初始化JAXB上下文失败", e);
}
}
// 对象转XML字符串
public static String marshal(Document doc) throws JAXBException {
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
StringWriter sw = new StringWriter();
marshaller.marshal(doc, sw);
return sw.toString();
}
// XML字符串转POJO对象
public static Document unmarshal(String xml) throws JAXBException {
Unmarshaller unmarshaller = context.createUnmarshaller();
return (Document) unmarshaller.unmarshal(new StringReader(xml));
}
}
java
// 组装Document对象后执行全量校验
List<String> errors = Pacs008ValidatorUtil.cbprFullCheck(document);
if (!errors.isEmpty()) {
throw new RuntimeException("报文校验不通过:" + errors);
}
// 序列化为XML
String xml = Pacs008XmlUtil.marshal(document);