最近在做一个电子发票开具(现税控接口更改为同步签章)的功能,用到了dom4j来封装及解析xml报文
一. 封装请求报文
1.报文示例如下:
全部报文格式如下,
<?xml version="1.0" encoding="utf-8"?>
<interface xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chinatax.gov.cn/tirip/dataspec/interfaces.xsd" version="DZFP1.0">
<globalInfo>
<appId>ZZSDZFP</appId>
<interfaceCode>EI.FPKJ.U.EC.INTRA</interfaceCode>
<passWord>c8ec925fefRjQzODlFMkZFOTcyODQ2QjEzODk2RjcyNzNEMDNCMjg=</passWord>
<dataExchangeId>77994cabfd9849de9176</dataExchangeId>
<fjh/>
<jqbh/>
<requestCode/>
<requestTime>2019-07-15 11:02:48</requestTime>
<userName>500102191212027426</userName>
<responseCode>144</responseCode>
</globalInfo>
<returnStateInfo>
<returnCode/>
<returnMessage/>
</returnStateInfo>
<Data>
<dataDescription>
<zipCode>0</zipCode>
<encryptCode>0</encryptCode>
<codeType>0</codeType>
</dataDescription>
<content>PFJFUVVFU1RfRlBLSiBjbGFzcz0iUkVRVUVTVF9GUEtKIj48R0hGTUM+5rWL6K+VMDAxPC9HSEZNQz48R0hGX05TUlNCSC8+PEZLRktIWUhfRktGWUhaSC8+PEZLRkRaX0ZLRkRIPjE1ODUzMTYyMzEzPC9GS0ZEWl9GS0ZESD48WEhGRFpfWEhGREg+5ZOI5bCU5ruo5biC5Y2X5bKX5Yy65rGJ5rC06LevMTcy5Y+3ICAgPC9YSEZEWl9YSEZESD48WEhGS0hZSF9TS0ZZSFpIPuW7uuihjOW8gOWPkeWMuuaUr+ihjCAgMjMwMDE4NjY3NTEwNTA1MDM5NDU8L1hIRktIWUhfU0tGWUhaSD48RlBaTF9ETT41MTwvRlBaTF9ETT48WUZQX0RNLz48WUZQX0hNLz48Qlo+55So5oi357yW56CB77yaMTgyMjQ377yb5b6u5L+h5YWs5LyX5Y+377ya5ZOI5oqV5L6b54Ot5YWs5Y+477yb54Ot6LS55ZKo6K+i77yaODcxMTEyMTPvvJvmlYXpmpzmiqXkv67vvJo4NzAwMDExMO+8m+i0ouWKoeWSqOivou+8mjg3MTExMjE2PC9CWj48S1BZPmFkbWluPC9LUFk+PEZIUj7lkLTmoZA8L0ZIUj48U0tZPmFkbWluPC9TS1k+PFhIUUQ+MDwvWEhRRD48RlBRUUxTSD43Nzk5NGNhYmZkOTg0OWRlOTE3NjwvRlBRUUxTSD48S1BMWD4wPC9LUExYPjxKU0hKPjU2NDUuODk8L0pTSEo+PEhKSkU+NTY0NS44OTwvSEpKRT48SEpTRT4wLjAwPC9ISlNFPjxCTUJfQkJIPjE5LjA8L0JNQl9CQkg+PFNQQk1KQ0JaPjI8L1NQQk1KQ0JaPjxCWVpEMS8+PEJZWkQyLz48RlBfS0pNWFMgY2xhc3M9IkZQX0tKTVg7IiBzaXplPSIyIj48RlBfS0pNWD48U1BNQz7lsYXmsJHng63otLk8L1NQTUM+PFNNLz48U0w+MDwvU0w+PEdHWEg+MjAxOC0yMDE5PC9HR1hIPjxKTERXPuW5s+aWueexszwvSkxEVz48U1BTTC8+PFNQREovPjxTUEpFPjQ3MjAuNjQ8L1NQSkU+PEZQSFhaPjA8L0ZQSFhaPjxIU0pCWj4xPC9IU0pCWj48U0U+MC4wMDwvU0U+PFNQQk0+MTEwMDEwMjAxMDEwMDAwMDAwMDwvU1BCTT48WlhCTS8+PFlIWkNCUz4xPC9ZSFpDQlM+PExTTEJTPjE8L0xTTEJTPjxaWlNUU0dMPuWFjeeojjwvWlpTVFNHTD48S0NFLz48QllaRDEvPjxCWVpEMi8+PC9GUF9LSk1YPjxGUF9LSk1YPjxTUE1DPui/nee6pumHkTwvU1BNQz48U00vPjxTTD4wPC9TTD48R0dYSD4yMDE4LTIwMTk8L0dHWEg+PEpMRFc+5bmz5pa557GzPC9KTERXPjxTUFNMLz48U1BESi8+PFNQSkU+OTI1LjI1PC9TUEpFPjxGUEhYWj4wPC9GUEhYWj48SFNKQlo+MTwvSFNKQlo+PFNFPjAuMDA8L1NFPjxTUEJNPjExMDAxMDIwMTAxMDAwMDAwMDA8L1NQQk0+PFpYQk0vPjxZSFpDQlM+MTwvWUhaQ0JTPjxMU0xCUz4xPC9MU0xCUz48WlpTVFNHTD7lhY3nqI48L1paU1RTR0w+PEtDRS8+PEJZWkQxLz48QllaRDIvPjwvRlBfS0pNWD48L0ZQX0tKTVhTPjwvUkVRVUVTVF9GUEtKPg==</content>
</Data>
</interface>
content节点为内部请求报文,使用了Base64进行了转码,未加密前的内部报文如下:
<REQUEST_FPKJ class="REQUEST_FPKJ">
<GHFMC>测试001</GHFMC>
<GHF_NSRSBH/>
<FKFKHYH_FKFYHZH/>
<FKFDZ_FKFDH>15853162313</FKFDZ_FKFDH>
<XHFDZ_XHFDH>海淀区中关村</XHFDZ_XHFDH>
<XHFKHYH_SKFYHZH>建行开发区支行 8888888888</XHFKHYH_SKFYHZH>
<FPZL_DM>51</FPZL_DM>
<YFP_DM/>
<YFP_HM/>
<BZ>用户编码:182247</BZ>
<KPY>admin</KPY>
<FHR>鲁班七号</FHR>
<SKY>admin</SKY>
<XHQD>0</XHQD>
<FPQQLSH>77994cabfd9849de9176</FPQQLSH>
<KPLX>0</KPLX>
<JSHJ>5645.89</JSHJ>
<HJJE>5645.89</HJJE>
<HJSE>0.00</HJSE>
<BMB_BBH>19.0</BMB_BBH>
<SPBMJCBZ>2</SPBMJCBZ>
<BYZD1/>
<BYZD2/>
<FP_KJMXS class="FP_KJMX;" size="2">
<FP_KJMX>
<SPMC>居民热费</SPMC>
<SM/>
<SL>0</SL>
<GGXH>2018-2019</GGXH>
<JLDW>平方米</JLDW>
<SPSL/>
<SPDJ/>
<SPJE>4720.64</SPJE>
<FPHXZ>0</FPHXZ>
<HSJBZ>1</HSJBZ>
<SE>0.00</SE>
<SPBM>1100102010100000000</SPBM>
<ZXBM/>
<YHZCBS>1</YHZCBS>
<LSLBS>1</LSLBS>
<ZZSTSGL>免税</ZZSTSGL>
<KCE/>
<BYZD1/>
<BYZD2/>
</FP_KJMX>
<FP_KJMX>
<SPMC>违约金</SPMC>
<SM/>
<SL>0</SL>
<GGXH>2018-2019</GGXH>
<JLDW>平方米</JLDW>
<SPSL/>
<SPDJ/>
<SPJE>925.25</SPJE>
<FPHXZ>0</FPHXZ>
<HSJBZ>1</HSJBZ>
<SE>0.00</SE>
<SPBM>1100102010100000000</SPBM>
<ZXBM/>
<YHZCBS>1</YHZCBS>
<LSLBS>1</LSLBS>
<ZZSTSGL>免税</ZZSTSGL>
<KCE/>
<BYZD1/>
<BYZD2/>
</FP_KJMX>
</FP_KJMXS>
</REQUEST_FPKJ>
2. 拼内层报文代码:
public static String getKJFPXml(String type,List<?> clsList, Object obj) {
Document document = DocumentHelper.createDocument();
if("开票".equals(type)){//开票
// 发票根节点
Element fpkjElement = document.addElement("REQUEST_FPKJ");
addAttribute(fpkjElement, "class", "REQUEST_FPKJ");
// DzfpBean entityBean = (DzfpBean) obj;
DzfpFptEntity entityBean = (DzfpFptEntity) obj;
addChilds(fpkjElement, "GHFMC", Tools.filterNullString(entityBean
.getGmf_mc()));// "购货方名称"
addChilds(fpkjElement, "GHF_NSRSBH", Tools.filterNullString(entityBean
.getGmf_nsrsbh()));// "购货方识别号"
addChilds(fpkjElement, "FKFKHYH_FKFYHZH", Tools.filterNullString(entityBean
.getGmf_yhzh()));// "付款方银行及账号"
addChilds(fpkjElement, "FKFDZ_FKFDH", Tools.filterNullString(entityBean
.getGmf_dzdh()));// "付款方地址电话"
addChilds(fpkjElement, "XHFKHYH_SKFYHZH", Tools.filterNullString(entityBean
.getXsf_yhzh()));// "销货方银行及账号"
addChilds(fpkjElement, "XHFDZ_XHFDH", Tools.filterNullString(entityBean
.getXsf_dzdh()));// "销货方地址电话"
addChilds(fpkjElement, "FPZL_DM", Tools.filterNullString(entityBean
.getFpzl_dm()));// "发票种类代码"
addChilds(fpkjElement, "YFP_DM", Tools.filterNullString(entityBean
.getYfp_dm()));// "原发票代码"
addChilds(fpkjElement, "YFP_HM", Tools.filterNullString(entityBean
.getYfp_hm()));// "原发票号码"
addChilds(fpkjElement, "BZ", Tools.filterNullString(entityBean
.getBz()));// "备注"
addChilds(fpkjElement, "KPY", Tools.filterNullString(entityBean
.getKpr()));// "开票人"
addChilds(fpkjElement, "FHR", Tools.filterNullString(entityBean
.getFhr()));// "复核人"
addChilds(fpkjElement, "SKY", Tools.filterNullString(entityBean
.getSkr()));// "收款人"
addChilds(fpkjElement, "XHQD", Tools.filterNullString(entityBean
.getQd_bz()));// "清单标识"
addChilds(fpkjElement, "FPQQLSH", Tools.filterNullString(entityBean
.getFpqqlsh()));// "请求流水号"
addChilds(fpkjElement, "KPLX", Tools.filterNullString(entityBean
.getKplx()));// "开票类型"
addChilds(fpkjElement, "JSHJ", Tools.filterNullString(entityBean
.getJshj()));// "价税合计金额"
addChilds(fpkjElement, "HJJE", Tools
.filterNullString(entityBean.getHjje()));// "合计金额"
addChilds(fpkjElement, "HJSE", Tools
.filterNullString(entityBean.getHjse()));// "合计税额"
addChilds(fpkjElement, "BMB_BBH", Tools.filterNullString(entityBean.getBmb_bbh()));// "编码表版本号"
addChilds(fpkjElement, "SPBMJCBZ", Tools.filterNullString(entityBean
.getSpbmjcbz()));// "商品编码简称标志"
addChilds(fpkjElement, "BYZD1", Tools.filterNullString(entityBean
.getByzd1()));// "备用字段 1"
addChilds(fpkjElement, "BYZD2", Tools.filterNullString(entityBean
.getByzd2()));// "备用字段 2"
Element fpxmxxElement = addChild(fpkjElement, "FP_KJMXS", null);
addAttribute(fpxmxxElement, "class", "FP_KJMX;");
addAttribute(fpxmxxElement, "size", "" + clsList.size());
// List<DzfpBean> entityList = (List<DzfpBean>) clsList;
List<DzfpXmxxEntity> entityList = (List<DzfpXmxxEntity>) clsList;
for (DzfpXmxxEntity dzfpBean : entityList) {
Element fpxmxxElements = addChild(fpxmxxElement, "FP_KJMX",
null);
addChilds(fpxmxxElements, "SPMC",Tools.filterNullString(dzfpBean.getXmmc())); // 商品名称
addChilds(fpxmxxElements, "SM",Tools.filterNullString(dzfpBean.getSm())); // 税目
addChilds(fpxmxxElements, "SL",Tools.filterNullString(dzfpBean.getSl()));// 税率
addChilds(fpxmxxElements, "GGXH",Tools.filterNullString(dzfpBean.getGgxh()));// 规格型号
addChilds(fpxmxxElements, "JLDW",Tools.filterNullString(dzfpBean.getJldw())); // 计量单位
addChilds(fpxmxxElements, "SPSL",Tools.filterNullString(dzfpBean.getXmsl()));// 商品数量
addChilds(fpxmxxElements, "SPDJ",Tools.filterNullString(dzfpBean.getXmdj()));// 商品单价
addChilds(fpxmxxElements, "SPJE",Tools.filterNullString(dzfpBean.getXmje()));// 商品金额
addChilds(fpxmxxElements, "FPHXZ",Tools.filterNullString(dzfpBean.getFphxz()));// 发票行性质
addChilds(fpxmxxElements, "HSJBZ",Tools.filterNullString(dzfpBean.getHsbz()));// 含税价标志
addChilds(fpxmxxElements, "SE",Tools.filterNullString(dzfpBean.getSe()));// 税额
addChilds(fpxmxxElements, "SPBM",Tools.filterNullString(dzfpBean.getSpbm()));// 商品编码
addChilds(fpxmxxElements, "ZXBM",Tools.filterNullString(dzfpBean.getZxbm()));// 自行编码
addChilds(fpxmxxElements, "YHZCBS",Tools.filterNullString(dzfpBean.getYhzcbs()));// 优惠政策标识
addChilds(fpxmxxElements, "LSLBS",Tools.filterNullString(dzfpBean.getLslbs()));// 零税率标识
addChilds(fpxmxxElements, "ZZSTSGL",Tools.filterNullString(dzfpBean.getZzstsgl()));// 增值税特殊管理
addChilds(fpxmxxElements, "KCE",Tools.filterNullString(dzfpBean.getKce()));// 扣除额
addChilds(fpxmxxElements, "BYZD1",Tools.filterNullString(dzfpBean.getByzd1()));// 备用字段
addChilds(fpxmxxElements, "BYZD2",Tools.filterNullString(dzfpBean.getByzd2()));// 备用字段
}
}else{//签章
// 发票根节点
Element dzfpElement = document.addElement("REQUEST_FPQZ");
addAttribute(dzfpElement, "class", "REQUEST_FPQZ");
// 发票签章信息
try {
addChilds(dzfpElement, "FPQZ_INFO",Tools.filterNullString(
encodeStr("SJLY"+(char)2+"06"+(char)3+"FPLX"+(char)2+"1")));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//通过键值对的方式来扩展,键与 值之间用(char)2 分隔,键值对 之间用(char)3 分隔。 组装好后,再加一层 base64
// 发票头
Element fptElement = addChild(dzfpElement, "FPQZ_FPT", null);
addAttribute(fptElement, "class", "FPQZ_FPT");
// DzfpBean entityBean = (DzfpBean) obj;
DzfpFptEntity entityBean = (DzfpFptEntity) obj;
addChilds(fptElement, "FPQQLSH", Tools.filterNullString(entityBean
.getFpqqlsh()));// "发票请求流水号"
addChilds(fptElement, "KPLX", Tools.filterNullString(entityBean
.getKplx()));// "开票类型"
addChilds(fptElement, "DKBZ", Tools.filterNullString(entityBean
.getDkbz()));// "代开标志"
addChilds(fptElement, "SGBZ", Tools.filterNullString(entityBean
.getSgbz()));// "收购标志"
addChilds(fptElement, "BMB_BBH", Tools.filterNullString(entityBean
.getBmb_bbh()));// "编码表版本号"
addChilds(fptElement, "QDBZ", Tools.filterNullString(entityBean
.getQd_bz()));// "清单标志"
addChilds(fptElement, "QDXMMC", Tools.filterNullString(entityBean
.getQd_fpxmmc()));// "清单发票项目名称"
addChilds(fptElement, "XSF_NSRSBH", Tools.filterNullString(entityBean
.getXsf_nsrsbh()));// "销售方纳税人识别号"
addChilds(fptElement, "XSF_MC", Tools.filterNullString(entityBean
.getXsf_mc()));// "销售方名称"
addChilds(fptElement, "XSF_DZDH", Tools.filterNullString(entityBean
.getXsf_dzdh()));// "销售方地址、电话"
addChilds(fptElement, "XSF_YHZH", Tools.filterNullString(entityBean
.getXsf_yhzh()));// "销售方银行账号"
addChilds(fptElement, "GMF_NSRSBH", Tools.filterNullString(entityBean
.getGmf_nsrsbh()));// "购买方纳税人识别号"
addChilds(fptElement, "GMF_MC", Tools.filterNullString(entityBean
.getGmf_mc()));// "购买方名称"
addChilds(fptElement, "GMF_DZDH", Tools.filterNullString(entityBean
.getGmf_dzdh()));// "购买方地址、电话"
addChilds(fptElement, "GMF_YHZH", Tools.filterNullString(entityBean
.getGmf_yhzh()));// "购买方银行账号"
addChilds(fptElement, "GMF_SJ", Tools.filterNullString(entityBean
.getGmf_sj()));// "购买方手机"
addChilds(fptElement, "GMF_EMAIL", Tools.filterNullString(entityBean
.getGmf_email()));// "购买方邮箱"
addChilds(fptElement, "KPR", Tools
.filterNullString(entityBean.getKpr()));// "开票人"
addChilds(fptElement, "SKR", Tools
.filterNullString(entityBean.getSkr()));// "收款人"
addChilds(fptElement, "FHR", Tools
.filterNullString(entityBean.getFhr()));// "复核人"
addChilds(fptElement, "YFP_DM", Tools.filterNullString(entityBean
.getYfp_dm()));// "原发票代码"
addChilds(fptElement, "YFP_HM", Tools.filterNullString(entityBean
.getYfp_hm()));// "原发票号码"
addChilds(fptElement, "JSHJ", Tools.filterNullString(entityBean
.getJshj()));// "价税合计"
addChilds(fptElement, "HJJE", Tools.filterNullString(entityBean
.getHjje()));// "合计金额"
addChilds(fptElement, "HJSE", Tools.filterNullString(entityBean
.getHjse()));// "合计税额"
addChilds(fptElement, "BZ", Tools.filterNullString(entityBean.getBz()));// "备注"
addChilds(fptElement, "FPZT", Tools.filterNullString("0"));// "发票状态 0:正常发票"
addChilds(fptElement, "JQBH", PropertiesUtil.getProperNameKey("dzfp.properties", "JQBH"));// "税控设备编号"
addChilds(fptElement, "FP_DM", Tools.filterNullString(entityBean.getFp_dm()));// "发票代码"
addChilds(fptElement, "FP_HM", Tools.filterNullString(entityBean.getFp_hm()));// "发票号码"
addChilds(fptElement, "KPRQ", Tools.filterNullString(entityBean.getKprq()));// "开票日期 YYYYMMDDHHMMSS"
addChilds(fptElement, "FP_MW", Tools.filterNullString(entityBean.getFp_mw()));// "发票密文"
addChilds(fptElement, "JYM", Tools.filterNullString(entityBean.getJym()));// "发票校验码"
addChilds(fptElement, "EWM", Tools.filterNullString(""));// "二维码 目前不需要传值,置空"
addChilds(fptElement, "PDF_XZFS", Tools.filterNullString("2"));// "1:接口返回 pdf 文件; 2:接口返回 pdf 下载地址; 3:接口同时返回 pdf 文件和 pdf 下载路径 "
Element fpkjElement = addChild(dzfpElement, "FPQZ_XMXXS", null);
addAttribute(fpkjElement, "class", "FPQZ_XMXX;");
addAttribute(fpkjElement, "size", "" + clsList.size());
// List<DzfpBean> entityList = (List<DzfpBean>) clsList;
List<DzfpXmxxEntity> entityList = (List<DzfpXmxxEntity>) clsList;
for (DzfpXmxxEntity dzfpBean : entityList) {
Element fpkjElements = addChild(fpkjElement, "FPQZ_XMXX",
null);
addChilds(fpkjElements, "FPHXZ", Tools.filterNullString(dzfpBean
.getFphxz()));// 发票行性质
addChilds(fpkjElements, "XMMC", Tools.filterNullString(dzfpBean
.getXmmc())); // "项目名称"
addChilds(fpkjElements, "GGXH", Tools.filterNullString(dzfpBean
.getGgxh()));// "规格型号"
addChilds(fpkjElements, "DW", Tools.filterNullString(dzfpBean
.getDw()));// "单位"
addChilds(fpkjElements, "XMSL", Tools.filterNullString(dzfpBean
.getXmsl()));// "项目数量"
addChilds(fpkjElements, "XMDJ", Tools.filterNullString(dzfpBean
.getXmdj()));// "项目单价"
addChilds(fpkjElements, "XMJE", Tools.filterNullString(dzfpBean
.getXmje()));// "项目金额"
addChilds(fpkjElements, "SL", Tools.filterNullString(dzfpBean
.getSl()));// "税率"
addChilds(fpkjElements, "SE", Tools.filterNullString(dzfpBean
.getSe()));// "税额"
addChilds(fpkjElements, "HSBZ", Tools.filterNullString(dzfpBean
.getHsbz()));// "含税标志"
addChilds(fpkjElements, "SPBM", Tools.filterNullString(dzfpBean
.getSpbm()));// 商品编码
addChilds(fpkjElements, "ZXBM", Tools.filterNullString(dzfpBean
.getZxbm()));// 自行编码
addChilds(fpkjElements, "YHZCBS", Tools.filterNullString(dzfpBean
.getYhzcbs()));// 优惠政策标识
addChilds(fpkjElements, "LSLBS", Tools.filterNullString(dzfpBean
.getLslbs()));// 零税率标识
addChilds(fpkjElements, "ZZSTSGL", Tools.filterNullString(dzfpBean
.getZzstsgl()));// 增值税特殊管理
addChilds(fpkjElements, "KCE", Tools.filterNullString(dzfpBean
.getKce()));// 扣除额
}
}
String str = document.getRootElement().asXML();
return str;
}
3. 外层报文+内层报文:
/**
* 外层报文+内层报文
* @param lx 操作类型
* @param contentXML 内层报文-加密
* @return
*/
public static String getAllXml(String type,String contentXML,DzfpFptEntity entityBean){
Document document = DocumentHelper.createDocument();
Element rootElement = document.addElement("interface");
rootElement.addAttribute("xmlns", "");
rootElement.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
rootElement.addAttribute("xsi:schemaLocation", "http://www.chinatax.gov.cn/tirip/dataspec/interfaces.xsd");
rootElement.addAttribute("version", "DZFP1.0");
Element fptElement = rootElement.addElement("globalInfo");
if("开票".equals(type)){//开票
/**
* 应用标识: 服务器自开票版:A16D8DBD18EDDD80 税控组件开票版:AA0DDF541B152FBA
*/
addChilds(fptElement, "appId",Tools.filterNullString("ZZSDZFP"));
addChilds(fptElement, "interfaceCode",Tools.filterNullString("EI.FPKJ.U.EC.INTRA"));// 接口编码
addChilds(fptElement, "userName",PropertiesUtil.getProperNameKey("dzfp.properties", "userName"));// 用户编码
addChilds(fptElement, "passWord",Tools.filterNullString(new CreateXml().getUUID(10).toString()+base(new CreateXml().getUUID(10).toString()+PropertiesUtil.getProperNameKey("dzfp.properties", "registratCode"))));// 请求方密码:10位随机数+Base64({(10位随机数+请求方注册码)MD5})
addChilds(fptElement, "requestCode",PropertiesUtil.getProperNameKey("dzfp.properties", "requestCode"));// 数据交换请求发出方代码(用户编码)
addChilds(fptElement, "requestTime",Tools.filterNullString(getDate2()));// 数据交换请求发出时间
addChilds(fptElement, "responseCode",PropertiesUtil.getProperNameKey("dzfp.properties", "responseCode"));// 数据交换请求接受方代码
addChilds(fptElement, "dataExchangeId",entityBean.getFpqqlsh());// 数据交换流水号,与内层报文一致
addChilds(fptElement, "fjh",Tools.filterNullString(""));// 分机号
addChilds(fptElement, "jqbh",Tools.filterNullString(""));// 开票分机号
}else{//签章
addChilds(fptElement, "terminalCode",PropertiesUtil.getProperNameKey("dzfp.properties", "terminalCode"));// 0bs架构 1 cs架构
/**
* 应用标识: 服务器自开票版:A16D8DBD18EDDD80 税控组件开票版:AA0DDF541B152FBA
*/
addChilds(fptElement, "appId",PropertiesUtil.getProperNameKey("dzfp.properties", "appId"));
addChilds(fptElement, "version",PropertiesUtil.getProperNameKey("dzfp.properties", "version"));// 版本
addChilds(fptElement, "interfaceCode",Tools.filterNullString("ECXML.FPQZ.BC.E.INV"));// 接口编码
addChilds(fptElement, "userName",PropertiesUtil.getProperNameKey("dzfp.properties", "userName"));// 用户编码
addChilds(fptElement, "passWord",Tools.filterNullString(new CreateXml().getUUID(10).toString()+base(new CreateXml().getUUID(10).toString()+PropertiesUtil.getProperNameKey("dzfp.properties", "registratCode"))));// 请求方密码:10位随机数+Base64({(10位随机数+请求方注册码)MD5})
addChilds(fptElement, "taxpayerId",PropertiesUtil.getProperNameKey("dzfp.properties", "taxpayerId"));
addChilds(fptElement, "authorizationCode",PropertiesUtil.getProperNameKey("dzfp.properties", "authorizationCode"));// 纳税人授权码-10位
addChilds(fptElement, "requestCode",PropertiesUtil.getProperNameKey("dzfp.properties", "requestCode"));// 数据交换请求发出方代码(用户编码)
addChilds(fptElement, "requestTime",Tools.filterNullString(getDate2()));// 数据交换请求发出时间
addChilds(fptElement, "responseCode",PropertiesUtil.getProperNameKey("dzfp.properties", "responseCode"));// 数据交换请求接受方代码
addChilds(fptElement, "dataExchangeId",entityBean.getFpqqlsh());// 数据交换流水号(YYYYMMDD)+9位序列号
}
Element sponse = rootElement.addElement("returnStateInfo");
addChilds(sponse, "returnCode",Tools.filterNullString(""));
addChilds(sponse, "returnMessage",Tools.filterNullString(""));
Element data = rootElement.addElement("Data");
Element data1 = data.addElement("dataDescription");
if("开票".equals(type)){//开票
addChilds(data1, "zipCode",Tools.filterNullString("0"));// 0:不压缩 1:压缩 (用GZip压缩)
addChilds(data1, "encryptCode",Tools.filterNullString("0"));// 加密方式代码
addChilds(data1, "codeType",Tools.filterNullString("0"));// 加密方式代码
}else{//签章
addChilds(data1, "zipCode",Tools.filterNullString("0"));// 0:不压缩 1:压缩 (用GZip压缩)
addChilds(data1, "encryptCode",Tools.filterNullString("2"));// 加密方式代码
addChilds(data1, "codeType",Tools.filterNullString("CA"));// 加密方式代码
}
addChilds(data, "content",Tools.filterNullString(contentXML));
document.getRootElement().asXML();
document.setXMLEncoding("utf-8"); // 默认utf-8
StringWriter sw = new StringWriter();
try {
document.write(sw);
} catch (IOException e) {
e.printStackTrace();
}
return sw.toString();
}
/**
*
* 添加孩子节点元素
*
* @param parent
* 父节点
* @param childName
* 孩子节点名称
* @param childValue
* 孩子节点值
* @return 新增节点
*/
public static Element addChild(Element parent, String childName,
String childValue) {
Element element = parent.addElement(childName);// 添加节点元素
element.setText(childValue == null ? "" : childValue); // 为元素设值
return element;
}
/**
*
* 添加孩子节点元素
*
* @param parent
* 父节点
* @param childName
* 孩子节点名称
* @param childValue
* 孩子节点值
* @return 新增节点
*/
public static Element addChilds(Element parent, String childName,
String childValue) {
Element element = parent.addElement(childName);// 添加节点元素
if (childValue != null && !childValue.isEmpty()) {
element.setText(childValue == null ? "" : childValue); // 为元素设值
}
return element;
}
/**
* @param parent
* @param attriName
* @param attriValue
*/
public static void addAttribute(Element parent, String attriName,
String attriValue) {
if (attriName != null && !attriName.isEmpty()) {
if (attriValue != null && !attriValue.isEmpty()) {
parent.addAttribute(attriName, attriValue == null ? ""
: attriValue);// 添加节点元素
}
}
}
以上,是请求报文封装,只看报文封装,忽略数据部分,中间涉及的工具类贴在最后。
二. 解析返回报文
1.返回报文格式如下
<?xml version="1.0" encoding="utf-8"?>
<interface>
<globalInfo>
<appId>ZZSDZFP</appId>
<interfaceCode>EI.FPKJ.U.EC.INTRA</interfaceCode>
<userName>500102191212027426</userName>
<passWord>c8ec925fefRjQzODlFMkZFOTcyODQ2QjEzODk2RjcyNzNEMDNCMjg=</passWord>
<requestCode/>
<requestTime>2019-07-15 11:02:48</requestTime>
<responseCode>144</responseCode>
<dataExchangeId>77994cabfd9849de9176</dataExchangeId>
<fjh/>
<jqbh>661619997746</jqbh>
</globalInfo>
<returnStateInfo>
<returnCode>0000</returnCode>
<!--电子发票返回信息描述:发票开具成功-->
<returnMessage>5Y+R56Wo5byA5YW35oiQ5Yqf</returnMessage>
</returnStateInfo>
<Data>
<content>PFJFU1BPTlNFX0ZQS0ogY2xhc3M9IlJFU1BPTlNFX0ZQS0oiPgogIDxSRVRVUk5DT0RFPjAwMDA8L1JFVFVSTkNPREU+CiAgPFJFVFVSTk1FU1NBR0U+5oiQ5Yqf77yBPC9SRVRVUk5NRVNTQUdFPgogIDxISkJIU0pFPjU2NDUuODk8L0hKQkhTSkU+CiAgPEhKU0U+MC4wMDwvSEpTRT4KICA8S1BSUT4yMDE5MDcxNTExMDg0ODwvS1BSUT4KICA8U1NZRj4yMDE5MDc8L1NTWUY+CiAgPEZQX0RNPjE1MDAwNDUyODg4ODwvRlBfRE0+CiAgPEZQX0hNPjY4MzE0MjkwPC9GUF9ITT4KICA8WEhRREJaPk48L1hIUURCWj4KICA8UkVUQ09ERT4wMDAwPC9SRVRDT0RFPgogIDxGV01XPiZsdDstKi82OTUvMDkvJmx0OzYzNDAwNS0mbHQ7LzQ2LzUqNTE4NDQ3Jmx0Oy8vOCs4MzY1MjQzOTg5Jmx0OzU5LTUzOS8rOComZ3Q7LzImbHQ7NzQvLSs4Kjk0NyoxMTUtNjU0MS80Ki8zKy00NyZsdDsvLzgrODM2NTI0Mzk4Jmd0OzczLzwvRldNVz4KICA8SllNPjU3ODU3MjMyNzY0MDA2NzgzMDcyPC9KWU0+CiAgPFNaUU0+TUlJQk9nWUpLb1pJaHZjTkFRY0NvSUlCS3pDQ0FTY0NBUUV4Q3pBSkJnVXJEZ01DR2dVQU1Bc0dDU3FHU0liM0RRRUhBVEdDQVFZd2dnRUNBZ0VCTUdBd1ZURUxNQWtHQTFVRUJoTUNZMjR4RFRBTEJnTlZCQXNlQkFCREFFRXhEVEFMQmdOVkJBZ2VCRk1YVHF3eEdUQVhCZ05WQkFNZUVFNHRWdjE2RGxLaGk2U0x3VTR0WDhNeERUQUxCZ05WQkFjZUJGTVhUcXdDQndJQkFBQUNUVzB3Q1FZRkt3NERBaG9GQURBTkJna3Foa2lHOXcwQkFRRUZBQVNCZ0hDOVBsSDBSWVlQQmxJYnhWK0ZvUmNSU0RERGY5dWV0dzNySi9hZjhPZGhnTnJRTGFMTi94SEpRYUNuTzFKVHRha3N5ckNEVk9hb0U1Tjd2YUk4Y25WdHhLUDcvaFJYYjMrd0VxcWlYU0pUNVpnUWVUeURYQnB3L2tNK1UrcUlET3hWMHQvQXZHZVhlRXpkUWVFSWZ0YjdMWU12RHdqdSs5TkdhK1hncWN6WDwvU1pRTT4KICA8RVdNPlFrM0NBd0FBQUFBQUFENEFBQUFvQUFBQVN3QUFBRXNBQUFBQkFBRUFBQUFBQUlRREFBQUFBQUFBQUFBQUFBQUFBQUFDQUFBQUFBQUEvLy8vLy8vLy8vLy8vLy8vLy8vZ0FBQUFBekF3dzhQRERNd2dBQUFBQXpBd3c4UERETXdnQUFBLzgvQXpQQVBEREEvZ0FBQS84L0F6UEFQRERBL2dBQUF3TThQODhQTTh6RHdnQUFBd004UDg4UE04ekR3Z0FBQXdNekF3QU0vQXp3RGdBQUF3TXpBd0FNL0F6d0RnQUFBd00vTS9Bei9QQUQ4Z0FBQXdNL00vQXovUEFEOGdBQUEvOHpETUFERHdQd01nQUFBLzh6RE1BRER3UHdNZ0FBQUFBOHdEOHc4QU16TWdBQUFBQTh3RDh3OEFNek1nQUFELy96OHo4ekRQUHd3Z0FBRC8vejh6OHpEUFB3d2dBQUQvOEFEL0E4L3pBQUFnQUFELzhBRC9BOC96QUFBZ0FBQXpEd3p3enc4UEQ4d2dBQUF6RHd6d3p3OFBEOHdnQUFEUDhBRFA4UHp6QU13Z0FBRFA4QURQOFB6ekFNd2dBQUFNekQ4TUR6UERNL01nQUFBTXpEOE1EelBETS9NZ0FBQXo4UEQ4L3pQRDhNOGdBQUF6OFBEOC96UEQ4TThnQUFBd3p3d3d6TURBTUF6Z0FBQXd6d3d3ek1EQU1BemdBQUFEdy9QL0RBL0RNdzhnQUFBRHcvUC9EQS9ETXc4Z0FBRC9Eek16ODgvLzhNOGdBQUQvRHpNejg4Ly84TThnQUFERHd3L004d0RQd0F3Z0FBRER3dy9NOHdEUHdBd2dBQUFNL0F3UHo4UDh6TURnQUFBTS9Bd1B6OFA4ek1EZ0FBRHdNQU13UC9Nek1NTWdBQUR3TUFNd1AvTXpNTU1nQUFBRC84LzhBQXovd0R3Z0FBQUQvOC84QUF6L3dEd2dBQUREd0RBRDhQTXpNOEFnQUFERHdEQUQ4UE16TThBZ0FBQUQvOHpNd0FERDg4L2dBQUFELzh6TXdBREQ4OC9nQUFBODh3d1BBenpEQVBBZ0FBQTg4d3dQQXp6REFQQWdBQUR3RHdNUERNL3pNL3dnQUFEd0R3TVBETS96TS93Z0FBREFBTVBEd0FERDhNOGdBQURBQU1QRHdBREQ4TThnQUFBOC93d004OE1BL0F6Z0FBQTgvd3dNODhNQS9BemdBQUQvdzg4L016OEQ4UDhnQUFEL3c4OC9NejhEOFA4Z0FBRE16TU04L0QvejhQQWdBQURNek1NOC9EL3o4UEFnQUFBOHd3RDh6UHpNelAvZ0FBQTh3d0Q4elB6TXpQL2dBQUQvLzhBRFBBdzhQLy9nQUFELy84QURQQXc4UC8vZ0FBQUFBek16TXpNek1BQWdBQUFBQXpNek16TXpNQUFnQUFBLzh6L0RBQS84OC84Z0FBQS84ei9EQUEvODgvOGdBQUF3TS84d3p6QU04d01nQUFBd00vOHd6ekFNOHdNZ0FBQXdNOERNUER3OE13TWdBQUF3TThETVBEdzhNd01nQUFBd00vek13L0EvTXdNZ0FBQXdNL3pNdy9BL013TWdBQUEvODgvQXp6RDhNLzhnQUFBLzg4L0F6ekQ4TS84Z0FBQUFBOC9ERHpQTU1BQWdBQUFBQTgvRER6UE1NQUFnQUFBPTwvRVdNPgo8L1JFU1BPTlNFX0ZQS0o+</content>
<dataDescription>
<zipCode>0</zipCode>
<encryptCode>0</encryptCode>
<codeType>0</codeType>
</dataDescription>
</Data>
</interface>
2.返回报文数据部分已加密,未加密内容如下
<RESPONSE_FPKJ class="RESPONSE_FPKJ">
<RETURNCODE>0000</RETURNCODE>
<RETURNMESSAGE>鎴愬姛锛?/RETURNMESSAGE>
<HJBHSJE>5645.89</HJBHSJE>
<HJSE>0.00</HJSE>
<KPRQ>20190715110848</KPRQ>
<SSYF>201907</SSYF>
<FP_DM>150004528888</FP_DM>
<FP_HM>68314290</FP_HM>
<XHQDBZ>N</XHQDBZ>
<RETCODE>0000</RETCODE>
<FWMW><-*/695/09/<634005-</46/5*518447<//8+8365243989<59-539/+8*>/2<74/-+8*947*115-6541/4*/3+-47<//8+836524398>73/</FWMW>
<JYM>57857232764006783072</JYM>
<SZQM>MIIBOgYJKoZIhvcNAQcCoIIBKzCCAScCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHATGCAQYwggECAgEBMGAwVTELMAkGA1UEBhMCY24xDTALBgNVBAseBABDAEExDTALBgNVBAgeBFMXTqwxGTAXBgNVBAMeEE4tVv16DlKhi6SLwU4tX8MxDTALBgNVBAceBFMXTqwCBwIBAAACTW0wCQYFKw4DAhoFADANBgkqhkiG9w0BAQEFAASBgHC9PlH0RYYPBlIbxV+FoRcRSDDDf9uetw3rJ/af8OdhgNrQLaLN/xHJQaCnO1JTtaksyrCDVOaoE5N7vaI8cnVtxKP7/hRXb3+wEqqiXSJT5ZgQeTyDXBpw/kM+U+qIDOxV0t/AvGeXeEzdQeEIftb7LYMvDwju+9NGa+XgqczX</SZQM>
<EWM>Qk3CAwAAAAAAAD4AAAAoAAAASwAAAEsAAAABAAEAAAAAAIQDAAAAAAAAAAAAAAAAAAACAAAAAAAA///////////////////gAAAAAzAww8PDDMwgAAAAAzAww8PDDMwgAAA/8/AzPAPDDA/gAAA/8/AzPAPDDA/gAAAwM8P88PM8zDwgAAAwM8P88PM8zDwgAAAwMzAwAM/AzwDgAAAwMzAwAM/AzwDgAAAwM/M/Az/PAD8gAAAwM/M/Az/PAD8gAAA/8zDMADDwPwMgAAA/8zDMADDwPwMgAAAAA8wD8w8AMzMgAAAAA8wD8w8AMzMgAAD//z8z8zDPPwwgAAD//z8z8zDPPwwgAAD/8AD/A8/zAAAgAAD/8AD/A8/zAAAgAAAzDwzwzw8PD8wgAAAzDwzwzw8PD8wgAADP8ADP8PzzAMwgAADP8ADP8PzzAMwgAAAMzD8MDzPDM/MgAAAMzD8MDzPDM/MgAAAz8PD8/zPD8M8gAAAz8PD8/zPD8M8gAAAwzwwwzMDAMAzgAAAwzwwwzMDAMAzgAAADw/P/DA/DMw8gAAADw/P/DA/DMw8gAAD/DzMz88//8M8gAAD/DzMz88//8M8gAADDww/M8wDPwAwgAADDww/M8wDPwAwgAAAM/AwPz8P8zMDgAAAM/AwPz8P8zMDgAADwMAMwP/MzMMMgAADwMAMwP/MzMMMgAAAD/8/8AAz/wDwgAAAD/8/8AAz/wDwgAADDwDAD8PMzM8AgAADDwDAD8PMzM8AgAAAD/8zMwADD88/gAAAD/8zMwADD88/gAAA88wwPAzzDAPAgAAA88wwPAzzDAPAgAADwDwMPDM/zM/wgAADwDwMPDM/zM/wgAADAAMPDwADD8M8gAADAAMPDwADD8M8gAAA8/wwM88MA/AzgAAA8/wwM88MA/AzgAAD/w88/Mz8D8P8gAAD/w88/Mz8D8P8gAADMzMM8/D/z8PAgAADMzMM8/D/z8PAgAAA8wwD8zPzMzP/gAAA8wwD8zPzMzP/gAAD//8ADPAw8P//gAAD//8ADPAw8P//gAAAAAzMzMzMzMAAgAAAAAzMzMzMzMAAgAAA/8z/DAA/88/8gAAA/8z/DAA/88/8gAAAwM/8wzzAM8wMgAAAwM/8wzzAM8wMgAAAwM8DMPDw8MwMgAAAwM8DMPDw8MwMgAAAwM/zMw/A/MwMgAAAwM/zMw/A/MwMgAAA/88/AzzD8M/8gAAA/88/AzzD8M/8gAAAAA8/DDzPMMAAgAAAAA8/DDzPMMAAgAAA=</EWM>
</RESPONSE_FPKJ>
3. 返回报文转为map对象取值
public static Map<String, String> readStringXmlOutNJ(String xml) {
Map<String,String> map = new HashMap<String,String>();
Document doc = null;
String s = null;
try {
// 将字符串转为XML
doc = DocumentHelper.parseText(xml);
Element root = doc.getRootElement(); //根节点
map=listNodes(root,map);
} catch (DocumentException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
public static Map<String,String> listNodes(Element node,Map<String,String> map ){
//如果当前节点内容不为空,则输出
if(!(node.getTextTrim().equals(""))){
map.put(node.getName(), node.getText());
}
//同时迭代当前节点下面的所有子节点
Iterator<Element> iterator = node.elementIterator();
while(iterator.hasNext()){
Element e = iterator.next();
listNodes(e,map);
}
return map;
}
4.如果要字符串报文转换Document对象写入新的文件,可这样写(接2)
/**
* 把document对象写入新的文件
*
* @param document
* @throws Exception
*/
public static void writer(Document document) throws Exception {
// 紧凑的格式
// OutputFormat format = OutputFormat.createCompactFormat();
// 排版缩进的格式
OutputFormat format = OutputFormat.createPrettyPrint();
// 设置编码
format.setEncoding("UTF-8");
// 创建XMLWriter对象,指定了写出文件及编码格式
XMLWriter writer = new XMLWriter(new OutputStreamWriter(
new FileOutputStream(new File("src//res.xml")), "UTF-8"), format);
// 写入
writer.write(document);
// 立即写入
writer.flush();
// 关闭操作
writer.close();
}
public static void fromStrToXml(String xml) throws Exception {
Document document = DocumentHelper.parseText(xml);
writer(document);
}
三.工具类
1.过滤null字符串
/**
* 过滤NULL字符串
* @param Object
* @return String
*/
public static String filterNullString(Object o){
if(o == null || "".equals(o) || "null".equals(o)){
return "";
}
return o.toString();
}
2. 读取配置文件 PropertiesUtil.getProperNameKey("dzfp.properties", "JQBH")
/**
*
* 功能: 根据配置文件名称以及配置文件的键获取值<br>
* 约束: 与本函数相关的约束 <br>
*
* @param key
* @return
*/
public static String getProperNameKey(String properName, String key) {
String keyString = loadPropertyName(properName).getProperty(key);
if (keyString == null || keyString.isEmpty()) {
return null;
}
return keyString;
}
/**
*
* 功能: 根据配置文件名称获取配置文件 <br>
* 约束: 利用函数调用方法 <br>
*
* @return
*/
private static Properties loadPropertyName(String properName) {
Properties prop = new Properties();
try {
InputStream is = PropertiesUtil.class.getClassLoader()
.getResourceAsStream(properName);
prop.load(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return prop;
}
中间涉及CA加密的一些内容就不在这写了。

被折叠的 条评论
为什么被折叠?



