Commit 690960df authored by fangxinjiang's avatar fangxinjiang

交行jar引入及开发demo-fxj

parent d11d7495
...@@ -101,7 +101,7 @@ ...@@ -101,7 +101,7 @@
<version>1.2.0</version> <version>1.2.0</version>
</dependency> </dependency>
<!-- 交行jar引入 --> <!-- 交行jar引入 -->
<!--<dependency> <dependency>
<groupId>com.ipct.safety</groupId> <groupId>com.ipct.safety</groupId>
<artifactId>ipct_safety</artifactId> <artifactId>ipct_safety</artifactId>
<version>2.1.1</version> <version>2.1.1</version>
...@@ -110,6 +110,6 @@ ...@@ -110,6 +110,6 @@
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.5.8</version> <version>5.5.8</version>
</dependency>--> </dependency>
</dependencies> </dependencies>
</project> </project>
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the yifu4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.yifu.cloud.plus.v1.ekp.controller;
import com.yifu.cloud.plus.v1.ekp.util.IpctUtil;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 预警配置表
*
* @author fxj
* @date 2025-07-21 09:49:56
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/ekpIpct")
@Tag(name = "预警配置表管理")
public class EkpIpctController {
@Autowired
private IpctUtil ipctUtil;
/**
* @Author fxj
* @Description 企业微信智能表格API调用调试入口
* @Date 15:56 2025/9/26
* @Param
* @return
**/
@PostMapping("/tesxIpctApi")
public void tesxIpctApi() {
try {
/**
* 第一步,调用ipct_safety包中的SM2类中的SM2Generate方法,将方法返回的公私钥对保存
* custId为云跨行客户号,由交行提供
*
*
* 私钥:MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgT9IzBq591GocYT7bxZPSW5S4xDLmeLG8zklsciINlT2gCgYIKoEcz1UBgi2hRANCAASaA0BYV6o6yMPKNl8DL0n4s9yV0e3Yzbh5D4ChG8ejGSDSPXmvUXJ6xgK61LH1N+Ns7dcPUtMvfWjIxxbIppaT
* 公钥:MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEmgNAWFeqOsjDyjZfAy9J+LPcldHt2M24eQ+AoRvHoxkg0j15r1FyesYCutSx9TfjbO3XD1LTL31oyMcWyKaWkw==
*/
//已获取公钥私钥这里直接注释
//ipctUtil.SM2Generate(ipctUtil.getCustId());
/**
* 第二步,请求交换密钥申请接口获取授权码。该操作仅系统第一次对接时需要进行,发送请求后需联系客户的云跨行管理员
* 在外部系统登记-授权码管理菜单中进行授权
* 参数系统名称sysNme与系统id sysId为客户云跨行管理员在外部系统登记-外部系统管理菜单中创建
*/
//ipctUtil.insertAuthCode(ipctUtil.getSysName(), ipctUtil.getSysId());
/**
* 第三步,交换非对称密钥对公钥,企业端上送第一步生成的公钥,银行端返回银行的公钥与对称密钥
* 调用ipct_safety包中的SM4类中的encryptErpSm4方法,对上送的公钥进行加密
* 再调用ipct_safety包中的SecretUtils类中的encrytErpSM4对报文体进行加密
*/
String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEmgNAWFeqOsjDyjZfAy9J+LPcldHt2M24eQ+AoRvHoxkg0j15r1FyesYCutSx9TfjbO3XD1LTL31oyMcWyKaWkw==";
String authCode = "SW94B7ZP492J";
//ipctUtil.erpPubKeyChange(ipctUtil.getCustId(), publicKey, authCode);
//云跨行公钥及新对称密钥
String sm2PublicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEqqyqhXLF/DEw6GhVc6MhGnrwBFwVL0n7ck3eh2hGqzBt1qMJ8X0Yfk+WRg+1ttebTkEshrGC5VIxF0HBdOQ54A==";//云跨行公钥
String erpNewSymmetryKey = "OTNCVDNQWVo2VjA5";//新对称密钥
//云跨行公钥:MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEqqyqhXLF/DEw6GhVc6MhGnrwBFwVL0n7ck3eh2hGqzBt1qMJ8X0Yfk+WRg+1ttebTkEshrGC5VIxF0HBdOQ54A==
//新对称密钥:OTNCVDNQWVo2VjA5
/**
* 第四步,调用系统登录接口进行登录,该操作每个自然日均需要进行,若不登录则无法进行业务交易
*/
//ipctUtil.erpLogin();
/**
* 第五步,调用业务接口
* 组装报文体后,需将报文体调用ipct_safety包中的SecretUtils类中的erpEncryptAndSign方法对报文体进行加密
* 收到返回报文后,需将响应体调用ipct_safety包中的SecretUtils类中的erpDecryptAndVerify方法对报文体进行解密
* @throws Exception
*/
Map stdReqBody = new HashMap();
stdReqBody.put("busNum", "12340");
stdReqBody.put("bsnId", "1");
stdReqBody.put("startDate", "2042-11-16");
stdReqBody.put("endDate", "2042-11-16");
stdReqBody.put("bankCd", "");
stdReqBody.put("acctNo", "");
stdReqBody.put("acctNoNme", "");
stdReqBody.put("debitCdtFlg", "");
stdReqBody.put("summary", "");
stdReqBody.put("amtSort", "");
stdReqBody.put("pageSize", 10);
stdReqBody.put("currentPage", 1);
//客户私钥:
//当日明细查询 erpNewSymmetryKey:新对称密钥, sm2PrivateKey:客户方的私钥, publicKey:云跨行公钥 trCode:业务接口编号 参考交行文档
String sm2PrivateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgT9IzBq591GocYT7bxZPSW5S4xDLmeLG8zklsciINlT2gCgYIKoEcz1UBgi2hRANCAASaA0BYV6o6yMPKNl8DL0n4s9yV0e3Yzbh5D4ChG8ejGSDSPXmvUXJ6xgK61LH1N+Ns7dcPUtMvfWjIxxbIppaT";
ipctUtil.erpRequest("C010100001", erpNewSymmetryKey, sm2PrivateKey, publicKey, stdReqBody);
}catch (Exception e){
e.printStackTrace();
}
}
}
package com.yifu.cloud.plus.v1.ekp.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocom.cscs.utils.SM2;
import com.bocom.cscs.utils.SM4;
import com.bocom.cscs.utils.SecretUtils;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* @Author fxj
* @Date 2025/10/28
* @Description 交行API工具类型 云跨行erp对接demo 依次实现下列步骤
* @Version 1.0
*/
@Component
@Data
@Log4j2
public class IpctUtil {
//通信客户端部署的服务器ip
private String ip = "106.15.44.157";
//通信客户端测试环境ERP对接服务端口
private String testPort = "4014";
//通信客户端生产环境ERP对接服务端口
private String prodPort = "4011";
//客户号
private String custId = "0115680126680138";
//客户名称
private String custNme = "唤预肖尔屠净嚎色侩础测试有限公司";
//操作员号
private String userId = "1033822";
//操作员名称
private String userNme = "景清";
//银行账户
private String bankAccount = "320006669013004363313";
//账户名称
private String bankAccountName = "优壹仓序公司";
//开户行
private String bankName = "交通银行常熟高新技术产业开发区支行";
//行号
private String bankCode = "301305500451";
//币种
private String currency = "CNY";
//外部系统名称
private String sysName = "皖信人力";
//外部系统唯一ID
private String sysId = "IPCT20251031104947054615";
//代发协议编号
private String dfxyNo = "3109002940";
/**
* 代发类型
* "A147:代发工资","A148:代发市公积金","A150:代发基金分红","A325:代发奖金,"A327:代发奖学金","A328:代发交通费","A329:代发津贴"
* "A330:代发基金赎回","A331:代发劳保费","A332:代发理财收益","A333:代发年金","A334:代发期权费","A335:代发其他款项"
**/
private String[] dflx = new String[]{"A147","A148","A150","A325","A327","A328","A329","A330","A331","A332","A333","A334","A335"};
/**
* 第一步,调用ipct_safety包中的SM2类中的SM2Generate方法,将方法返回的公私钥对保存
* custId为云跨行客户号,由交行提供
* #私钥:MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgJdKBJb/WS//BCFoKRNpSHs23DYpCtMyiuGwQfwAqBTKgCgYIKoEcz1UBgi2hRANCAASmXWdJhZL/ewd/FSe9o2XK6I4CaIJOJ4Lzc1Lm0fZRdeoPi0XnTubd3ONAAM8UadSngEzOjZDFDA2wcblbT5eG
* #公钥:MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEpl1nSYWS/3sHfxUnvaNlyuiOAmiCTieC83NS5tH2UXXqD4tF507m3dzjQADPFGnUp4BMzo2QxQwNsHG5W0+Xhg==
* @throws Exception
*/
public void SM2Generate(String custId) throws Exception {
try {
Map keypair = SM2.getInstance().SM2Generate(custId);
//私钥
String privateKey = null==keypair.get("private")?"":keypair.get("private").toString();
//公钥
String publicKey = null==keypair.get("public")?"":keypair.get("public").toString();
log.info("私钥:" + privateKey);
log.info("公钥:" + publicKey);
}catch (Exception e){
log.error("SM2Generate执行异常", e);
}
}
/**
* 第二步,请求交换密钥申请接口获取授权码。该操作仅系统第一次对接时需要进行,发送请求后需联系客户的云跨行管理员
* 在外部系统登记-授权码管理菜单中进行授权
* 参数系统名称sysNme与系统id sysId为客户云跨行管理员在外部系统登记-外部系统管理菜单中创建
*/
public void insertAuthCode(String sysName, String sysId) {
try {
// 组报文
Map stdReqHead = new HashMap();
Map stdReqBody = new HashMap();
Map request = new HashMap();
//客户号、客户名、操作员号、操作员名为云跨行系统生成,由系统管理员提供
stdReqHead.put("custId", custId);
stdReqHead.put("custNme", custNme);
stdReqHead.put("userId", userId);
stdReqHead.put("userNme", userNme);
stdReqHead.put("trCode", "insertAuthCode");
stdReqHead.put("channel", "04");
stdReqHead.put("systemType", "01");
stdReqHead.put("sysId", sysId);
stdReqBody.put("sysName", sysName);
stdReqBody.put("sysId", sysId);
request.put("stdReqHead", stdReqHead);
request.put("stdReqBody", stdReqBody);
// 请求insertAuthCode接口
String response = httpRequest(request, "insertAuthCode");
// 接收返回字段
JSONObject jsonObject = JSON.parseObject(response);
Map<String, Object> resMap = (Map<String, Object>) jsonObject;
Map<String, Object> rspBody = null;
if (null != resMap && null != resMap.get("RSP_BODY")){
rspBody = (Map<String, Object>) resMap.get("RSP_BODY");
}
Map<String, Object> stdRespnseHead = null;
Map<String, Object> stdRespnseBody;
if (null != rspBody){
if (null != rspBody.get("stdRspHead")){
stdRespnseHead = (Map<String, Object>) rspBody.get("stdRspHead");
}
if (null != rspBody.get("stdRspBody")){
stdRespnseBody = (Map<String, Object>) rspBody.get("stdRspBody");
}
}
//获取授权码
String authCode = null;
if (null != stdRespnseHead && null != stdRespnseHead.get("authCode")){
authCode = stdRespnseHead.get("authCode").toString();
}
log.info("授权码:" + authCode);
}catch (Exception e){
log.error("insertAuthCode执行异常", e);
}
}
/**
* 第三步,交换非对称密钥对公钥,企业端上送第一步生成的公钥,银行端返回银行的公钥与对称密钥
* 调用ipct_safety包中的SM4类中的encryptErpSm4方法,对上送的公钥进行加密
* 再调用ipct_safety包中的SecretUtils类中的encrytErpSM4对报文体进行加密
*/
public void erpPubKeyChange(String custId, String publicKey, String authCode){
try {
// 报文公钥部分用SM4加密
String erpPubKey = SM4.getInstance().encryptErpSm4(publicKey, custId);
// 组报文
Map stdReqHead = new HashMap();
Map stdReqBody = new HashMap();
Map request = new HashMap();
//客户号、客户名、操作员号、操作员名为云跨行系统生成,由系统管理员提供
stdReqHead.put("custId", custId);
stdReqHead.put("custNme", custNme);
stdReqHead.put("userId", userId);
stdReqHead.put("userNme", userNme);
stdReqHead.put("trCode", "erpPubKeyChange");
stdReqHead.put("channel", "04");
stdReqHead.put("systemType", "01");
stdReqHead.put("sysId", sysId);
stdReqBody.put("erpPubKey", erpPubKey);
stdReqBody.put("sysId", sysId);
stdReqBody.put("authCode", authCode);// authCode 为上一个方法的返回值
request.put("stdReqHead", stdReqHead);
//body部分用SM4加密 调用encrytErpSM4
String encrytBody = null;
try {
encrytBody = SecretUtils.encrytErpSM4(stdReqBody, custId);
} catch (Exception e) {
log.error("reqBody加密执行异常", e);
}
request.put("stdReqBody", encrytBody);
// 请求接口
String response = httpRequest(request, "erpPubKeyChange");
// 接收返回字段
JSONObject jsonObject = JSON.parseObject(response);
Map<String, Object> resMap = (Map<String, Object>) jsonObject;
Map<String, Object> rspBody = null;
if (null != resMap.get("RSP_BODY")){
rspBody = (Map<String, Object>) resMap.get("RSP_BODY");
}
Map<String, Object> stdRespnseHead = null;
if (null != rspBody.get("stdRspHead")){
stdRespnseHead = (Map<String, Object>) rspBody.get("stdRspHead");
}
String stdRespnseBody = null;
if (null != rspBody.get("stdRspBody")){
stdRespnseBody = (String) rspBody.get("stdRspBody");
}
// 接返回报文 解密并保存云跨行公钥及新对称密钥
String rspData = null;
try {
rspData = SecretUtils.decrytErpSM4(stdRespnseBody, custId);
} catch (Exception e) {
log.error("rspBody解密执行异常", e);
}
Map map = JSON.parseObject(rspData);
String clientPubKey = (String) map.get("clientPubKey");//云跨行公钥
log.info("云跨行公钥:" + clientPubKey);
String erpNewSymmetryKey = (String) map.get("erpNewSymmetryKey");//新对称密钥
log.info("新对称密钥:" + erpNewSymmetryKey);
}catch (Exception e){
log.error("erpPubKeyChange执行异常", e);
}
}
/**
* 第四步,调用系统登录接口进行登录,该操作每个自然日均需要进行,若不登录则无法进行业务交易
*/
public void erpLogin() {
// 组报文
Map stdReqHead = new HashMap();
Map stdReqBody = new HashMap();
Map request = new HashMap();
//客户号、客户名、操作员号、操作员名为云跨行系统生成,由系统管理员提供
stdReqHead.put("custId", custId);
stdReqHead.put("custNme", custNme);
stdReqHead.put("userId", userId);
stdReqHead.put("userNme", userNme);
stdReqHead.put("trCode", "erpLogin");
stdReqHead.put("channel", "04");
stdReqHead.put("systemType", "01");
stdReqHead.put("sysId", sysId);
request.put("stdReqHead", stdReqHead);
request.put("stdReqBody", stdReqBody);
// 请求erpLogin接口
httpRequest(request, "erpLogin");
}
/**
* 第五步,调用业务接口
* 组装报文体后,需将报文体调用ipct_safety包中的SecretUtils类中的erpEncryptAndSign方法对报文体进行加密
* 收到返回报文后,需将响应体调用ipct_safety包中的SecretUtils类中的erpDecryptAndVerify方法对报文体进行解密
* @throws Exception
*/
public void erpRequest(String trCode,
String erpNewSymmetryKey,
String sm2PrivateKey,
String sm2PublicKey,
Map stdReqBody ) throws Exception {
// 组业务报文
Map stdReqHead = new HashMap();
Map request = new HashMap();
//客户号、客户名、操作员号、操作员名为云跨行系统生成,由系统管理员提供
stdReqHead.put("custId", custId);
stdReqHead.put("custNme", custNme);
stdReqHead.put("userId", userId);
stdReqHead.put("userNme", userNme);
stdReqHead.put("trCode", trCode);//业务数据交易码
stdReqHead.put("channel", "04");
stdReqHead.put("systemType", "01");
stdReqHead.put("sysId", sysId);
//组装业务数据
if (null != stdReqBody){
stdReqBody = new HashMap();
}
//stdReqBody.put("", "***************");
request.put("stdReqHead", stdReqHead);
// body部分调用erpEncryptAndSignSM2加密 erpNewSymmetryKey:新的对称密钥 sm2PrivateKey:客户方的私钥
String encrytBody = SecretUtils.erpEncryptAndSign(stdReqBody, erpNewSymmetryKey, custId, sm2PrivateKey);
request.put("stdReqBody", encrytBody);
// 请求erpToCbbp接口
String response = httpRequest(request, trCode);
// 接收返回字段
JSONObject jsonObject = JSON.parseObject(response);
Map<String, Object> resMap = (Map<String, Object>) jsonObject;
Map<String, Object> rspBody = null;
if (null != resMap.get("RSP_BODY")){
rspBody = (Map<String, Object>) resMap.get("RSP_BODY");
}
Map<String, Object> stdRespnseHead = null;
if (null != rspBody.get("stdRspHead")){
stdRespnseHead = (Map<String, Object>) rspBody.get("stdRspHead");
}
String stdRespnseBody = null;
if (null != rspBody.get("stdRspBody")){
stdRespnseBody = (String) rspBody.get("stdRspBody");
}
// 接返回报文 解密 erpNewSymmetryKey:新的对称密钥 sm2PublicKey:云跨行公钥
String rspData = null;
if (null != stdRespnseBody){
rspData = SecretUtils.erpDecryptAndVerify(stdRespnseBody, erpNewSymmetryKey, sm2PublicKey);
}
Map map = null;
if (null != JSON.parseObject(rspData)){
map = JSON.parseObject(rspData);
}
log.info("返回报文:"+ rspData);
}
/**
* 发送报文方法
* @param request
* @param trCode
* @return
*/
private String httpRequest(Map request, String trCode) {
try{
Map reqDataMap = new HashMap();
Map reqHead = new HashMap();
reqDataMap.put("REQ_HEAD", reqHead);
reqDataMap.put("REQ_BODY", request);
JSONObject reqDataJson = new JSONObject(reqDataMap);
String address = null;
if(trCode == "insertAuthCode" || trCode == "erpPubKeyChange" || trCode == "erpLogin") {
address = "http://" + ip + ":" + testPort + "/" + trCode+".bocms";
} else {
address = "http://" + ip + ":" + testPort + "/" + "erpToCbbp" +".bocms";
}
URL url = new URL(address);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("content-type", "application/x-www-form-urlencoded");
connection.setRequestProperty("jumpcloud-Env", "BASE");
connection.setDoInput(true);
connection.setDoOutput(true);
// post方式发送
connection.setRequestMethod("POST");
OutputStream out = connection.getOutputStream();
String reqData = "REQ_MESSAGE=" + reqDataJson.toJSONString();
out.write(reqData.getBytes("UTF-8"));
out.flush();
out.close();
int retCode = connection.getResponseCode();
if (retCode != 200) {
throw new Exception("交易出错!retCode=" + retCode);
}
int len = connection.getContentLength();
byte[] retData = readContent(connection.getInputStream(), len);
String response = new String(retData, "UTF-8");
return response;
}catch (Exception e){
log.error("http发送报文方法请求执行异常", e);
return null;
}
}
/**
* 读取返回信息
*
* @param in
* @param len
* @return
* @throws IOException
*/
private byte[] readContent(InputStream in, int len) throws IOException {
if (len <= 0) {
byte[] buf = new byte[2048];
byte[] readBuf = new byte[1024];
int totalLen = 0;
while (true) {
int readLen = in.read(readBuf);
if (readLen <= 0)
break;
if (totalLen + readLen > buf.length) {
byte[] tmp = new byte[buf.length + readLen + 1024];
System.arraycopy(buf, 0, tmp, 0, totalLen);
buf = tmp;
}
System.arraycopy(readBuf, 0, buf, totalLen, readLen);
totalLen = totalLen + readLen;
}
byte[] retBuf = new byte[totalLen];
System.arraycopy(buf, 0, retBuf, 0, totalLen);
return retBuf;
} else {
int totalLen = 0;
byte[] buf = new byte[len];
while (totalLen < len) {
int readLen = in.read(buf, totalLen, len - totalLen);
if (readLen <= 0)
break;
totalLen = totalLen + readLen;
}
return buf;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment