【转发】农行银企直联XML对接socket SAP EPIC

无人久伴 提交于 2020-08-10 00:32:44

 

前段时间项目中接入了农行的银企直联来完成代发的功能,当我拿到银行方面给过来的文档和资料后,发现和招行的银企直联模式差不多,大概就是:在window机器上开一个类似于前置机的小程序,作为我们和银行服务器直联数据连接的中介,我们发送xml数据给前置机,前置机再将数据加密后发送给银行服务器。但是万万没想到农行这个银企直联给我搞了不小的麻烦,他们的文档写的简直是不忍直视,接口返回码也模糊不清,没有明确说明。现在我把踩过的坑给分享一下。

准备开始
在开始之前我们会拿到2个东西,一个是中国农业银行银企通平台(4.70版).msi安装包,另一个是现金管理银企直连接入开发手册V1.2.1.wps接口文档说明
开始安装前置机程序,完成之后是这个样子:

测试用的客户号、操作员代码、操作员密码都会一并提供过来。
注意:正式环境下是需要插入一个key宝,由于现在是测试环境,在安装目录的etc路径下,用记事本编辑 etc\LoginSet.xml,将 IsKey 节点中的内容改成0,就可以不用KEY登录了。
系统设置
点击系统设置,在里面配置我们要用的模式:ERP公网接入、本地服务器地址、通讯协议、监听的端口等等。
直接上几张图吧:











注意:这里有一个坑需要说明一下:农行的这个程序是不支持http 协议(虽然他上面写着可以选择,无语)所以我们要用tcp协议。

组装XML数据
看到上图,已经成功的监听到了15999端口,现在我们就要向前置机所在的机器的ip+port的这个URL上推送XML数据,例如:192.168.1.111:15999

这里举一个范例:汇兑-单笔对似,xml数据报文是这样要求的。

java代码实例:




 1 //5.汇兑-单笔对私
 2 ApRoot root = new ApRoot();
 3 root.setCCTransCode("CFRT21");
 4 root.setAmt("9.10");
 5 builder.setRoot(root);
 6 ApCmp cmp = new ApCmp();
 7 cmp.setDbAccNo("361101040010679");
 8 cmp.setDbProv("05");
 9 cmp.setDbCur("01");
10 cmp.setDbLogAccNo("");
11 cmp.setCrAccNo("6228453296002816764");
12 cmp.setCrProv("");
13 cmp.setCrCur("01");
14 cmp.setCrLogAccNo("");
15 cmp.setConFlag("1");
16 builder.setCmp(cmp);
17 ApCorp corp = new ApCorp();
18 corp.setPsFlag("");
19 corp.setBookingFlag("0");
20 corp.setBookingDate("");
21 corp.setBookingTime("");
22 corp.setUrgencyFlag("0");
23 corp.setOthBankFlag("0");
24 corp.setCrAccName("郑春广");
25 corp.setDbAccName("内猛关仪太彩悟佑慊古丝");
26 corp.setWhyUse("测试");
27 corp.setPostscript("测试");
28 builder.setCorp(corp);


安装要求组装数据:

 1 1
 2 String s = builder.toXmlString(builder);
 3 /**
 4 * 请求数据:加密标识(1加密,0不加密) + 请求xml数据的长度(默认7位,不够补空格) + 请求的xml
 5 * @param s 请求的xml
 6 * @author jieYW
 7 * @date 2018/5/29
 8 * @return java.lang.String
 9 */
10 public String genRequestData(String s)throws Exception{
11 return "1" + String.format("%1$-6s", s.getBytes("gbk").length) + s;
12 }

 


注意:这里也有一个大坑,字符编码必须通过gbk的编码。前置机内部是通过gbk来解码的。这里如果不设置gbk,你在报文中有汉字的时候就gg了,会一直报这个错误:接收请求报文失败 -接收报体失败 - POLL失败退出 - 偏移量 = 750,当时这个问题困扰了我一段时间,因为我是知道他字符编码是gbk的,所以我只在socket的输出流里设置了字符的编码,经过血一般经历后终于想到了这里,然后彻底解决中文乱码的问题。

 

【讲xml转换成socket套接字段】

 

 

socket发送数据
将上述组装好的数据通过tcp协议发送给前置机:

 

1 String s = builder.toXmlString(builder);
2 ApHttpRequest request = new ApHttpRequest();
3 String s1 = request.socketSendAndReceive("192.168.1.111", 15999, builder.genRequestData(s));
4 System.out.println("接受数据:" + s1);

 


测试结果:


补充代码
XML组装:

 

 1 /**
 2  * 将ApXmlBuilder格式的数据转化为xml形式
 3  *
 4  * @param builder
 5  * @author jieYW
 6  * @date 2018/5/29
 7  * @return java.lang.String
 8  */
 9 public String toXmlString(ApXmlBuilder builder)throws Exception{
10     StringBuffer sb = new StringBuffer("<ap>");
11     Field[] fields = builder.getClass().getDeclaredFields();
12     for (int i = 0; i < fields.length; i++) {
13         Field field = fields[i];
14         field.setAccessible(true);
15         Object item = field.get(builder);
16         if(item == null){
17             continue;
18         }
19         String name = DaoSupport.toFirstUpperCase(field.getName());
20         if(!name.equals("Root")){
21             sb.append("<" + name + ">");
22         }
23         Field[] itemFields = item.getClass().getDeclaredFields();
24         for (int j = 0; j < itemFields.length; j++) {
25             Field itemField = itemFields[j];
26             itemField.setAccessible(true);
27             Object itemObject = itemField.get(item);
28             if(itemObject == null){
29                 continue;
30             }
31             String itemFieldName = itemField.getName();
32             sb.append("<" + itemFieldName + ">");
33             sb.append(itemField.get(item).toString());
34             sb.append("</" + itemFieldName + ">");
35         }
36         if(!name.equals("Root")){
37             sb.append("</" + name + ">");
38         }
39     }
40     sb.append("</ap>");
41     return sb.toString();
42 }
43 ————————————————

 


发送报文:

 

 1 public String socketSendAndReceive(String url, int port,String data)throws Exception{
 2     System.out.println("请求数据:" + data);
 3     Socket socket = new Socket(url, port);
 4     OutputStream bw = socket.getOutputStream();
 5     bw.write(data.getBytes("gbk"));
 6     bw.flush();
 7     InputStream ips = socket.getInputStream();
 8     StringBuffer sb = new StringBuffer();
 9     int len = 0;
10     byte[] buf = new byte[1024];
11     while((len=ips.read(buf))!=-1){
12         sb.append(new String(buf,0,len,"gbk"));
13     }
14     bw.close();
15     ips.close();
16     socket.close();
17     return sb.toString();
18 }

 

解析XML:

 

 1 /**
 2  * 将xml数据解析为ApXmlBuilde格式的数据
 3  *
 4  * @param msg
 5  * @author jieYW
 6  * @date 2018/5/29
 7  * @return com.mind.pay.abc.ap.ApXmlBuilder
 8  */
 9 public static ApXmlBuilder parseXml(String msg)throws Exception {
10     ApXmlBuilder builder = new ApXmlBuilder();
11     Method[] methods  = builder.getClass().getMethods();
12     ApRoot apRoot = new ApRoot();
13     Method[] rootMethods = apRoot.getClass().getMethods();
14 
15     Map<String,Method> methodMap = new HashMap<>();
16     for (Method method : methods) {
17         methodMap.put(method.getName(),method);
18     }
19     InputStream inputStream = new ByteArrayInputStream(msg.getBytes("UTF-8"));
20     SAXReader reader = new SAXReader();
21     Document document = reader.read(inputStream);
22     Element root = document.getRootElement();
23     List<Element> elementList = root.elements();
24     // 遍历所有子节点
25     for (Element e : elementList){
26         if(methodMap.keySet().contains("set" + e.getName())){
27             Class<?> aClass = Class.forName("com.mind.pay.abc.ap.Ap" + e.getName());
28             Object itemObject = aClass.newInstance();
29             List<Element>  items = e.elements();
30             for (Element itemElement : items) {
31                 Method[] itemMethods = itemObject.getClass().getMethods();
32                 for (Method itemMethod : itemMethods) {
33                     //如果字段存在,invoke方法赋值
34                     if(itemMethod.getName().contains("set"+itemElement.getName())){
35                         itemMethod.invoke(itemObject,itemElement.getText());
36                     }
37                 }
38             }
39             methodMap.get("set" + e.getName()).invoke(builder,itemObject);
40         }else{
41             //根目录下的参数,封装到apRoot中
42             for (Method rootMethod : rootMethods) {
43                 //如果字段存在,invoke方法赋值
44                 if(rootMethod.getName().contains("set"+e.getName())){
45                     rootMethod.invoke(apRoot,e.getText());
46                 }
47             }
48             builder.setRoot(apRoot);
49         }
50      }
51     // 释放资源
52     inputStream.close();
53     inputStream = null;
54     return builder;
55 }

 

 


原文链接:https://blog.csdn.net/wei389083222/article/details/80802839

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!