首先把我上级解释的前置机和我讲述的前置机概念简单表述一下:
前置机是银行为满足企业或者用户能够利用自身的系统或者程序去访问银行数据的一个中间物理机,为什么需要前置机?银行出于安全保密考虑,企业的程序只能通过发送数据到前置机,前置机会对数据进行解析再就是加密来把数据发送到银行后台,银行再根据请求返回数据给前置机,前置机数据请求到之后返回给企业程序.
相关前置机知识可以看一下该链接:什么是前置机,前置机的作用是什么 - 武魂95级蓝银草 - 博客园
银企直联与前置机socket通信-Java_xyt750021的博客-优快云博客_银企直联前置机
一般来说银行都会给你一个安装前置机的安装包以及安装教程

接入手册里面就是包含安装教程,一般来说银行相关工作人员会对接这一块工作的注意事项,安装完前置机之后就会有一个ip和端口给到你

接下来我们就需要按照接口文档来写内容了,由于我完成的是交易细节的查询,所以直接看到交易细节的接口

由于银行前置机要求接收到XML格式的报文
所以我根据报文要求格式编写报文类,再把把报文类利用XMLMapper转化为XML报文,涉及到序列化与反序列化相关知识,可以看一下以下文章连接:
使用 Jackson 玩转 xml 的序列化和反序列化(二)【使用 流式API 操作】_Just do it-优快云博客
java对象转换为xml格式字符串_weixin_33985507的博客-优快云博客
Jackson-操作XML_举世武双的博客-优快云博客_jacksonxmlelementwrapper
完成这些基本就搞一段落,能够从银行获取返回报文,再解析成对应的结果类

都是一级一级分装一级一级拆解的,不慌不忙地完成就行了
再就是对你写的对前置机获取报文进行一个测试,看看是否能顺利获取数据
这里贴上测试类:
/**
* @author jcx
* @description 光大银行测试
* @description
* @createTime 2022/1/24 9:31
*/
@Slf4j
@SpringBootTest
public class CebTest {
private static XmlMapper xmlMapper = new XmlMapper();
private static String CIF_NO = "2450856366";
// 接收报文url
private static final String URL = "http://172.16.220.165:8000/ent/b2e004002.do?usrID=2450856366&userPassword=123456&Sigdata=1";
// 获得交易流水的测试方法
@Test
public void getTradeDetailTest() {
//字段为null,自动忽略,不再序列化
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 美化输出
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
//XML标签名:使用骆驼命名的属性名,
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
//设置转换模式
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
CebResponseXml<CebResponseSystemHeadXml, CebResponseTransHeadXml, CebResponseTransContentXml<CebResponseRespDataXml>> tradeDetail = getTradeDetail();
System.out.println("tradeDetail===================>"+tradeDetail);
log.info("获取完毕");
}
/**
* 获取交易细节
* @param
* @return { @link com.gdbbk.datacentre.dto.chnl.xml.ceb.CebResponseXml<com.gdbbk.datacentre.dto.chnl.xml.ceb.CebResponseSystemHeadXml,com.gdbbk.datacentre.dto.chnl.xml.ceb.CebResponseTransHeadXml,com.gdbbk.datacentre.dto.chnl.xml.ceb.CebResponseTransContentXml<com.gdbbk.datacentre.dto.chnl.xml.ceb.CEBResponseRespDataXml>> }
* @throws
* @author jcx
* @date 2022/1/25 15:12
*/
private CebResponseXml<CebResponseSystemHeadXml, CebResponseTransHeadXml, CebResponseTransContentXml<CebResponseRespDataXml>> getTradeDetail() {
String resultStr = executeServerHttpService(getCebRequestXmlString());
log.info("请求返回的参数为========\n"+resultStr);
try {
CebResponseXml<CebResponseSystemHeadXml, CebResponseTransHeadXml, CebResponseTransContentXml<CebResponseRespDataXml>> result = xmlMapper.readValue(resultStr, CebResponseXml.class);
// 判断响应是否成功
if (!StringUtil.equals("0000", result.getTransContent().getReturnCode())) {
throw new RuntimeException("光大银行获取流水失败:" + result.getTransContent().getReturnMsg());
}
return result;
} catch (JsonProcessingException e) {
throw new RuntimeException("光大银行获取流水失败xml解析失败", e);
}
}
@Test
public void getDate() {
// String dateStr = DateUtil.getStringDate(new Date(), "yyyyMMdd");
// System.out.println(dateStr);
// LocalDate date = LocalDate.now();
// String replace = date.toString().replace("-", "");
// System.out.println(replace);
// String s = LocalTime.now().toString().replace(":","").substring(0,6);
// System.out.println(s);
// String s = UUID.randomUUID().toString();
// System.out.println(s);
// long l = System.currentTimeMillis();
// System.out.println(l);
// String s1 = l + "";
// String substring = s1.substring(s1.length() - 9, s1.length() - 1);
// System.out.println(substring);
// String s2 = (System.currentTimeMillis() + "").substring((System.currentTimeMillis() + "").length()-9,(System.currentTimeMillis() + "").length()-1);
// System.out.println(s2);
double random = Math.random();
System.out.println(random);//0.9240323806012383
System.out.println(random * 10000);//9240.323806012382
System.out.println(Math.round(random * 10000));//9240
String serialNo = String.valueOf(Math.round(random * 10000)) + System.currentTimeMillis();
System.out.println(serialNo);//97161644569521784
}
/**
* 把请求报文组装并返回
*
* @param
* @return { @link java.lang.String }
* @throws
* @author jcx
* @date 2022/1/25 9:30
*/
public String getCebRequestXmlString() {
CebRequestReqDataXml cEBRequestReqDataXml = new CebRequestReqDataXml();
cEBRequestReqDataXml.setRequestPatches("99");
cEBRequestReqDataXml.setAcNo("35500188068982460");
cEBRequestReqDataXml.setClientPatchID("111122323232");
cEBRequestReqDataXml.setEndTime("20220210");
//0-正序 1或空不送该字段-倒序
cEBRequestReqDataXml.setSortType(null);
cEBRequestReqDataXml.setStartPatches("1");
cEBRequestReqDataXml.setStartTime("20220201");
CebRequestTransContentXml cEBRequestTransContentXml = new CebRequestTransContentXml();
cEBRequestTransContentXml.setReqData(cEBRequestReqDataXml);
CebRequestSystemHeadXml cEBRequestSystemHeadXml = new CebRequestSystemHeadXml();
cEBRequestSystemHeadXml.setEncodeing("utf-8");
cEBRequestSystemHeadXml.setCifNo(CIF_NO);
cEBRequestSystemHeadXml.setFlag("");
cEBRequestSystemHeadXml.setLanguage("zh_CN");
cEBRequestSystemHeadXml.setMAC("");
cEBRequestSystemHeadXml.setLicenseId("");
cEBRequestSystemHeadXml.setNote("");
cEBRequestSystemHeadXml.setPinSeed("");
cEBRequestSystemHeadXml.setServiceName("");
cEBRequestSystemHeadXml.setUserID("002");
cEBRequestSystemHeadXml.setSyMacFlag("");
cEBRequestSystemHeadXml.setVersion("");
CebRequestTransHeadXml cEBRequestTransHeadXml = new CebRequestTransHeadXml();
cEBRequestTransHeadXml.setTransCode("b2e004002");
cEBRequestTransHeadXml.setJnlDate("20030809");
cEBRequestTransHeadXml.setBatchID("12232323123124");
cEBRequestTransHeadXml.setJnlTime("144534");
CebRequestXml cEBRequestXml = new CebRequestXml();
cEBRequestXml.setTransContent(cEBRequestTransContentXml);
cEBRequestXml.setSystemHead(cEBRequestSystemHeadXml);
cEBRequestXml.setTransHead(cEBRequestTransHeadXml);
// 增加xml头配置
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
String cEBRequestXmlString;
try {
cEBRequestXmlString = xmlMapper.writeValueAsString(cEBRequestXml).replaceFirst("encoding='UTF-8'", "encoding='GBK'");
log.info("登录请求的参数:{}", cEBRequestXmlString);
return cEBRequestXmlString;
} catch (JsonProcessingException e) {
throw new RuntimeException("光大银行获取请求参数的xml解析失败", e);
}
}
/**
* 执行请求
*
* @param reqData
* @return { @link java.lang.String }
* @throws
* @author jcx
* @date 2022/1/24 16:07
*/
public String executeServerHttpService(String reqData) {
try {
// 处理交易的url
RestTemplate restTemplate = new RestTemplate();
// 设置响应编码为GBK形式
restTemplate.getMessageConverters().add(1, new StringHttpMessageConverter(Charset.forName("GBK")));
log.info("【请求报文】:\n" + reqData);
HttpEntity<String> formEntity = new HttpEntity<>(reqData);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(URL, formEntity, String.class);
String retStr = responseEntity.getBody();
log.info("【返回报文】Ret Data:\n " + retStr);
return retStr;
} catch (Exception e) {
throw new RuntimeException("光大银行执行请求失败:", e);
}
}
}
测试通过之后就是,需要按照业务需求把数据存储,以及做数据表的细分
最后就是测试自己的业务代码能否跑的通了
在这个过程中,我个人遇到的问题:第一个就是业务需求的表格的数据存储,再加上这里是用mybatisXML配置文件手写SQL对数据库进行数据操作,麻了很久,因为太久没有用mybatis了,之前都是用mybatis-plu或者通用Mapper或者是JPA,简单又高效,所以当我看到一堆SQL的时候我的心都是慌的慢慢克服
再就是关于前置机还有端口,ip还有账号等等一些信息都会在前端页面输入配置,这个工作如果放到生产的话估计就不需要了,分了好几张表,几张表都是存储一些信息,不明白这么设计的初衷是什么,有空可以翻一翻代码看看业务上这么设计的必要性,能不能不这么设计.
再就是根据返回报文解析之后的数据存储到分银行交易流水信息表(临时表),再日终存储到各银行交易流水信息月度表(一月一表),达到分表目的.再就是在数据里面有一个各银行总表,各银行总表也会按月分表这样达到一个数据存储要求.
本文介绍了银企直连中前置机的角色,阐述了前置机作为安全中介处理企业与银行间数据交换的过程。通过Java实现银企直联交易细节查询,涉及XML报文格式、序列化与反序列化,以及MyBatis进行数据库操作。同时,讨论了在实际业务中遇到的数据存储和配置问题。
3401

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



