1、获取配置信息,基础代码设置
1.1 建行支付、退款需要商户提供以下信息:
商户代码 | 支付使用 |
商户柜台代码 | 支付使用 |
分行代码 | 支付使用 |
公钥 | 外联平台使用、支付使用 |
操作员号 | 外联平台使用 |
操作员号交易密码 | 外联平台使用 |
证书 | 外联平台使用 |
证书密码 | 外联平台使用 |
1.2 创建工具类、实体类
1.2.1 映射信息
public class Const {
//建行币种
public static final String CCB_RMB= "01";//币种 01 人民币
//建行交易码
public static final String CCB_CODE= "530590";//由建行统一分配为 530590
//建行接口类型
public static final String CCB_METHOD_TYPE= "1";//1- 防钓鱼接口
//建行语言
public static final String CCB_LANGUAGE_CN= "CN";
//建行支付方式
public static final String CCB_TRADE_TYPE_JSAPI= "JSAPI";//JSAPI-- 公 众 号 支 付
public static final String CCB_TRADE_TYPE_MINIPRO= "MINIPRO";//MINIPRO--小程序
public static final String CCB_5W1001 = "5W1001";//商户连接交易
public static final String CCB_5W1002 = "5W1002";//商户支付流水查询
public static final String CCB_5W1003 = "5W1003";//商户退款流水查询
public static final String CCB_5W1004 = "5W1004";//商户单笔退款交易
public static final String CCB_5W1005 = "5W1005";//商户流水文件下载
public static final String CCB_5W1006 = "5W1006";//E付通授权信息查询
public static final String CCB_5W1007 = "5W1007";//外卡收单商户端mpi
public static final String CCB_5W1015 = "5W1015";//历史订单退款交易
public static final String CCB_5W1016 = "5W1016";//历史订单退款结果查询
public static final String CCB_5W1024 = "5W1024";//线上集团商户单笔退款
public static final String CCB_520200 = "520200";//商户支付交易
}
1.2.2 支付查询
//支付查询
@XmlRootElement(name="TX") // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class AccountPayJournalRequest {
/**
*请求序列号 只可以使用数字
*/
@XmlElement(name = "REQUEST_SN")
public String REQUEST_SN;
/**
*商户号
*/
@XmlElement(name = "CUST_ID")
public String CUST_ID;
/**
*操作员号
*/
@XmlElement(name = "USER_ID")
public String USER_ID;
/**
*密码
*/
@XmlElement(name = "PASSWORD")
public String PASSWORD;
/**
*交易码
*/
@XmlElement(name = "TX_CODE")
public String TX_CODE;
/**
*语言
*/
@XmlElement(name = "LANGUAGE")
public String LANGUAGE;
@XmlElement(name = "TX_INFO")
public Body body;
@XmlRootElement(name="TX_INFO")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
public static class Body{
/**
*起始日期
*/
public String START;
/**
*开始小时
*/
public String STARTHOUR;
/**
*开始分钟
*/
public String STARTMIN;
/**
*截止日期
*/
public String END;
/**
*结束小时
*/
public String ENDHOUR;
/**
*结束分钟
*/
public String ENDMIN;
/**
*流水类型
*/
public String KIND;
/**
*订单号
*/
public String ORDER;
/**
*结算账户号
*/
public String ACCOUNT;
/**
*文件类型
*/
public String DEXCEL;
/**
*金额
*/
public BigDecimal MONEY;
/**
*排序
*/
public String NORDERBY;
/**
*当前页次
*/
public int PAGE;
/**
*柜台号
*/
public String POS_CODE;
/**
*流水状态
*/
public String STATUS;
/**
*子商户号
*/
public String Mrch_No;
}
}
//支付查询响应
@XmlRootElement(name="TX") // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class AccountPayJournalResponse {
/**
*请求序列号 只可以使用数字
*/
@XmlElement(name = "REQUEST_SN")
public String REQUEST_SN;
/**
*商户号
*/
@XmlElement(name = "CUST_ID")
public String CUST_ID;
/**
*交易码
*/
@XmlElement(name = "TX_CODE")
public String TX_CODE;
/**
*响应码
*/
@XmlElement(name = "RETURN_CODE")
public String RETURN_CODE;
/**
*交易响应信息
*/
@XmlElement(name = "RETURN_MSG")
public String RETURN_MSG;
/**
*语言
*/
@XmlElement(name = "LANGUAGE")
public String LANGUAGE;
// @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
@XmlElement(name = "TX_INFO")
public Body body;
@XmlRootElement(name="TX_INFO")
@XmlAccessorType(XmlAccessType.FIELD)
public static class Body{
/**
*总页次
*/
public int TPAGE;
/**
*当前页次
*/
public int CUR_PAGE;
/**
*提示
*/
public String NOTICE;
@XmlElementWrapper(name = "LIST")
public List<ListInfo> listInfoList;
@XmlRootElement(name="LIST")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
public static class ListInfo{
public String TRAN_DATE; //交易日期
public String ACC_DATE; //记账日期
public String ORDER; //订单号
public String ACCOUNT; //付款方账号
public String ACC_NAME; //付款方户名
public BigDecimal PAYMENT_MONEY; //支付金额
public BigDecimal REFUND_MONEY; //退款金额
public String POS_ID; //柜台号
public String REM1; //备注1public String
public String REM2; //备注2
public String ORDER_STATUS; //订单状态
public String PAY_MODE; //支付方式
public BigDecimal Orig_Amt; //订单金额
public BigDecimal Txn_ClrgAmt; //结算金额
public BigDecimal MrchCmsn_Amt; //手续费金额
public BigDecimal Discount_Amt; //优惠金额
public String OriOvrlsttnEV_Trck_No; //银行流水号
public String MsgRp_Jrnl_No; //商户流水号
public String OnlnPcsgInd_1_Bmp_ECD; //交易标志位图编码
public String TxnAmt; //交易金额
public String Cst_Tp_Prft_Dsc; //客户类型优惠描述
public String Jrnl_TpCd; //流水类型代码
public String CrCrd_Instm_Prd_Num; //信用卡分期期数
public String Crd_Attr_Bmp_Def_ID; //卡属性位图
public String DstCrd_IssuBnk_InsNo; //发卡行机构号
}
}
1.2.3 单笔退款申请
//退款申请
@XmlRootElement(name="TX") // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class OneRefundRequest {
/**
*请求序列号 只可以使用数字
*/
@XmlElement(name = "REQUEST_SN")
public String REQUEST_SN;
/**
*商户号
*/
@XmlElement(name = "CUST_ID")
public String CUST_ID;
/**
*操作员号
*/
@XmlElement(name = "USER_ID")
public String USER_ID;
/**
*密码
*/
@XmlElement(name = "PASSWORD")
public String PASSWORD;
/**
*交易码
*/
@XmlElement(name = "TX_CODE")
public String TX_CODE;
/**
*语言
*/
@XmlElement(name = "LANGUAGE")
public String LANGUAGE;
// @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
@XmlElement(name = "TX_INFO")
public Body body;
/**
*签名信息
*/
@XmlElement(name = "SIGN_INFO")
public String SIGN_INFO;
/**
*签名CA信息
*/
@XmlElement(name = "SIGNCERT")
public String SIGNCERT;
@XmlRootElement(name="TX_INFO")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
public static class Body{
/**
* 退款金额
*/
public String MONEY;
/**
* 订单号
*/
public String ORDER;
/**
* 退款流水号
* 可不填,商户可根据需要填写,退款流水号由商户的系统生成
*/
public String REFUND_CODE;
}
}
//退款响应
@XmlRootElement(name="TX") // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class OneRefundResponse {
/**
*请求序列号 只可以使用数字
*/
@XmlElement(name = "REQUEST_SN")
public String REQUEST_SN;
/**
*商户号
*/
@XmlElement(name = "CUST_ID")
public String CUST_ID;
/**
*交易码
*/
@XmlElement(name = "TX_CODE")
public String TX_CODE;
/**
*响应码
*/
@XmlElement(name = "RETURN_CODE")
public String RETURN_CODE;
/**
*交易响应信息
*/
@XmlElement(name = "RETURN_MSG")
public String RETURN_MSG;
/**
*语言
*/
@XmlElement(name = "LANGUAGE")
public String LANGUAGE;
// @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
@XmlElement(name = "TX_INFO")
public Body body;
@XmlRootElement(name="TX_INFO")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
public static class Body{
public String ORDER_NUM; //订单号
public String PAY_AMOUNT; //支付金额
public String AMOUNT; //退款金额
public String REM1; //备注1
public String REM2; //备注2
public String PAY_MODE; //退款方式 ZFB:支付宝;CFT:微信;其他返回空
public String MRCH_ACCENTRAMT; //商户实际退款金额。 PAY_MODE=ZFB或CFT时有效,否则返回空值
public String CASH_REFUND_FEE; //买家退款金额 PAY_MODE=ZFB或CFT时有效,否则返回空值
public String COUPON_REFUND_FEE; //代金券退款金额 PAY_MODE=CFT时有效,否则返回空值
public String PRESENT_REFUND_DISCOUNT; //平台优惠退款金额 PAY_MODE=CFT时有效,否则返回空值
public String PRESENT_REFUND_MDISCOUNT_AMOUNT; //商家优惠退款金额 PAY_MODE=CFT时有效,否则返回空值
public String REFUND_FEE; //申请退款总金额 PAY_MODE=ZFB或CFT时有效,否则返回空值
public String TXNAMT; //交易金额 折后金额 龙支付优惠退货,该字段返回实际退卡金额。
/**
* 龙支付优惠退货的情况返回:
* 交易操作的权益位图(1-操作,0-不操作)
* 第1位:建行综合积分
* 第2位:客户回馈优惠券
* 第3位:客户回馈优惠活动
* 第4位:ELP优惠活动
* 第5位:预付卡
* 第6位:商户优惠券
* 第7位:预留(银联优惠)
* 第8位:预留(微信优惠)
* 第9位:预留(支付宝优惠)
* 第10位:激励金
* 注:该字段仅对有需要的商户返回
*/
public String ONLNPCSGIND_1_BMP_ECD; //联机处理标志一位图编码
}
}
1.2.3 退款查询
//退款查询
@XmlRootElement(name="TX") // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class AccountRefundJournalRequest {
/**
*请求序列号 只可以使用数字
*/
@XmlElement(name = "REQUEST_SN")
public String REQUEST_SN;
/**
*商户号
*/
@XmlElement(name = "CUST_ID")
public String CUST_ID;
/**
*操作员号
*/
@XmlElement(name = "USER_ID")
public String USER_ID;
/**
*密码
*/
@XmlElement(name = "PASSWORD")
public String PASSWORD;
/**
*交易码
*/
@XmlElement(name = "TX_CODE")
public String TX_CODE;
/**
*语言
*/
@XmlElement(name = "LANGUAGE")
public String LANGUAGE;
// @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
@XmlElement(name = "TX_INFO")
public Body body;
@XmlRootElement(name="TX_INFO")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
public static class Body{
/**
*起始日期
*/
public String START;
/**
*开始小时
*/
public String STARTHOUR;
/**
*开始分钟
*/
public String STARTMIN;
/**
*截止日期
*/
public String END;
/**
*结束小时
*/
public String ENDHOUR;
/**
*结束分钟
*/
public String ENDMIN;
/**
*流水类型
*/
public String KIND;
/**
*订单号
*/
public String ORDER;
/**
*结算账户号
*/
public String ACCOUNT;
/**
*金额
*/
public BigDecimal MONEY;
/**
*排序
*/
public String NORDERBY;
/**
*当前页次
*/
public int PAGE;
/**
*柜台号
*/
public String POS_CODE;
/**
*流水状态
*/
public String STATUS;
/**
*子商户号
*/
public String Mrch_No;
}
}
//退款查询响应
@XmlRootElement(name="TX") // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class AccountRefundJournalResponse {
/**
*请求序列号 只可以使用数字
*/
@XmlElement(name = "REQUEST_SN")
public String REQUEST_SN;
/**
*商户号
*/
@XmlElement(name = "CUST_ID")
public String CUST_ID;
/**
*交易码
*/
@XmlElement(name = "TX_CODE")
public String TX_CODE;
/**
*响应码
*/
@XmlElement(name = "RETURN_CODE")
public String RETURN_CODE;
/**
*交易响应信息
*/
@XmlElement(name = "RETURN_MSG")
public String RETURN_MSG;
/**
*语言
*/
@XmlElement(name = "LANGUAGE")
public String LANGUAGE;
// @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
@XmlElement(name = "TX_INFO")
public Body body;
@XmlRootElement(name="TX_INFO")
@XmlAccessorType(XmlAccessType.FIELD)
public static class Body{
/**
*总页次
*/
public int TPAGE;
/**
*当前页次
*/
public int CUR_PAGE;
/**
*提示
*/
public String NOTICE;
@XmlElementWrapper(name = "LIST")
public List<ListInfo> listInfoList;
@XmlRootElement(name="LIST")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
public static class ListInfo{
public String TRAN_DATE; //交易日期
public String REFUND_DATE; //退款日期
public String ORDER_NUMBER; //订单号
public String REFUND_ACCOUNT; //退款账号
public BigDecimal PAY_AMOUNT; //支付金额
public BigDecimal REFUNDEMENT_AMOUNT; //退款金额
public String POS_CODE; //柜台号
public String USERID; //操作员
public String STATUS; //订单状态
public String REFUND_CODE; //退款流水号
public String REM1; //备注1
public String REM2; //备注2
public String PAY_MODE; //支付方式
public BigDecimal Orig_Amt; //订单金额
public BigDecimal Txn_ClrgAmt; //退款结算金额
public BigDecimal MrchCmsn_Amt; //退款手续费金额
public String OriOvrlsttnEV_Trck_No; //银行流水号
public String MsgRp_Jrnl_No; //商户流水号
public String Crd_Attr_Bmp_Def_ID; //卡属性位图
public String DstCrd_IssuBnk_InsNo; //发卡行机构号
public String OnlnPcsgInd_1_Bmp_ECD; //交易标志位图编码
public String TxnAmt; //交易金额
public String Cst_Tp_Prft_Dsc; //客户类型优惠描述
public String Jrnl_TpCd; //流水类型代码
}
}
1.2.4 XML映射工具
public class XmlUtil {
protected static Logger logger = LoggerFactory.getLogger(XmlUtil.class);
private static final Map<String,Class> clazzMap = new HashMap<String,Class>(){{
this.put(AccountRefundJournalRequest.class.getName(), AccountRefundJournalRequest.class);//商户支付流水查询 商户退款流水查询
this.put(OneRefundRequest.class.getName(),OneRefundRequest.class);//商户单笔退款交易
this.put(AccountPayJournalResponse.class.getName(), AccountPayJournalResponse.class);//商户退款流水查询响应
this.put(OneRefundResponse.class.getName(),OneRefundResponse.class);//商户单笔退款交易响应
}};
/**
* 将对象转为流程XML
*
* @param graphModel
* @return
* @throws JAXBException
*/
/**
* 将对象转为流程XML
*
* @return
* @throws JAXBException
*/
public static String convertToXML(Object entry) throws JAXBException,RuntimeException {
if(entry instanceof AccountRefundJournalRequest){
return convertToClazz(AccountRefundJournalRequest.class,entry);
}else if(entry instanceof OneRefundRequest){
return convertToClazz(OneRefundRequest.class,entry);
}else if(entry instanceof AccountPayJournalRequest){
return convertToClazz(AccountPayJournalRequest.class,entry);
}else {
throw new RuntimeException("class not found, can not convert to xml");
}
}
private static String convertToClazz(Class clazz,Object entry) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
StringWriter writer = new StringWriter();
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(entry, writer);
String xmlStr = writer.toString();
//建行编码方式是GB2312
if(StringUtils.isNotBlank(xmlStr) && xmlStr.contains("encoding=\"UTF-8\"")){
xmlStr = xmlStr.replace("encoding=\"UTF-8\"","encoding=\"GB2312\"");
}
xmlStr = StringUtils.replace(xmlStr, """, "'");
return xmlStr;
}
public static Object convertToClass(String xml,Class clazz){
Object xmlObject = null;
Reader reader = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
// xml转为对象的接口 反序列化
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
reader = new StringReader(xml);
xmlObject = unmarshaller.unmarshal(reader);
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return xmlObject;
}
}
1.2.5 网络请求工具
public class HttpClientUtil {
public static String httpPostCCB(String url, Map paramMap) {
return HttpClientUtil.httpPost(url, paramMap, "UTF-8");
}
public static String httpPost(String url, Map paramMap, String code) {
String content = null;
if (url == null || url.trim().length() == 0 || paramMap == null || paramMap.isEmpty()) return null;
HttpClient httpClient = new HttpClient();
httpClient.getParams().setParameter(HttpMethodParams.USER_AGENT,"Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.2) Gecko/20090803 Fedora/3.5.2-2.fc11 Firefox/3.5.2");//
PostMethod method = new PostMethod(url);
Iterator it = paramMap.keySet().iterator();
while (it.hasNext()) {
String key = it.next() + "";
Object o = paramMap.get(key);
if (o != null && o instanceof String) {
method.addParameter(new org.apache.commons.httpclient.NameValuePair(key, o.toString()));
}
if (o != null && o instanceof String[]) {
String[] s = (String[]) o;
if (s != null)
for (int i = 0; i < s.length; i++) {
method.addParameter(new org.apache.commons.httpclient.NameValuePair(key, s[i]));
}
}
}
try {
int statusCode = httpClient.executeMethod(method);
content = new String(method.getResponseBody(), code);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(method!=null)method.releaseConnection();
method = null;
httpClient = null;
}
return content;
}
public static String sendHttpRequest(String ipAdress, int nPort,String sRequest) {
String sResult = "";
OutputStream out = null;
BufferedReader in = null;
try {
String encoding = "GB18030"; // ��ϵͳʹ��UTF-8���룬�轫������ת��ΪGB18030
String params = "requestXml=" + sRequest; //ע�⣺�����ı������requestXml������
String path = "http://" + ipAdress + ":" + nPort;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(10 * 1000); // �������ӳ�ʱʱ��
conn.setDoOutput(true); // �� doOutput ��־����Ϊ true��ָʾӦ�ó���Ҫ������д�� URL
conn.setDoInput(true); // //�� doInput ��־����Ϊ true��ָʾӦ�ó���Ҫ�� URL
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length",String.valueOf(params.length()));
conn.setRequestProperty("Connection", "close");
out = conn.getOutputStream();
out.write(params.getBytes(encoding));
out.flush();
out.close();
if (conn.getResponseCode() == 200) {
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), encoding));
} else {
in = new BufferedReader(new InputStreamReader(conn.getErrorStream(), encoding));
}
String sLine = null;
StringBuffer sb = new StringBuffer();
while ((sLine = in.readLine()) != null) {
sb.append(sLine);
}
sResult = sb.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null)
in.close();
if (out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sResult;
}
}
2、开启外联平台
2.1 下载外联平台
2.2 将证书 存放在 cert 目录下
2.3 修改设置,bin目录下启动 设置.bat
将 1.1 中配置信息填进去后,点击确定
2.4 启动外联平台服务
3、支付
3.1 充值
public static void main(String[] args) {
String MERCHANTID = "1111111111111";//商户代码
String POSID = "1111111";//商户柜台代码
String BRANCHID = "11111111";//分行代码
String PUB = "1111111111111111111111";//公钥后 30 位
String ORDERID = "12aadsda2dsad944443";//定单号
String PAYMENT = "0.01";//付款金额
String CURCODE = Const.CCB_RMB;//币种
String TXCODE = "530590";//交易码
String REMARK1 = "";//备注 1
String REMARK2 = "";//备注 2
String TYPE = Const.CCB_METHOD_TYPE;//接口类型
String GATEWAY = "0";//网关类型 默认0
String CLIENTIP = "";//客户端 IP
String REGINFO = "";//客户注册信息
String PROINFO = "";//商品信息
String REFERER = "";//商户 URL
String TRADE_TYPE = Const.CCB_TRADE_TYPE_JSAPI;//交易类型
String SUB_APPID = "";//微信公共号id
String SUB_OPENID = "";//微信用户id
String bankURL="https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6";//发送的url
Map<String,String> map = new HashMap();
map.put("MERCHANTID",MERCHANTID);
map.put("POSID",POSID);
map.put("BRANCHID",BRANCHID);
map.put("ORDERID",ORDERID);
map.put("PAYMENT",PAYMENT);
map.put("CURCODE",CURCODE);
map.put("TXCODE",TXCODE);
map.put("REMARK1",REMARK1);
map.put("REMARK2",REMARK2);
map.put("TYPE",TYPE);
map.put("PUB",PUB);
map.put("GATEWAY",GATEWAY);
map.put("CLIENTIP",CLIENTIP);
map.put("REGINFO",REGINFO);
map.put("PROINFO",PROINFO);
map.put("REFERER",REFERER);
map.put("TRADE_TYPE",TRADE_TYPE);
map.put("SUB_APPID",SUB_APPID);
map.put("SUB_OPENID",SUB_OPENID);
String param = "MERCHANTID=" + MERCHANTID + "&POSID=" + POSID + "&BRANCHID=" + BRANCHID + "&ORDERID=" + ORDERID + "&PAYMENT=" + PAYMENT + "&CURCODE=" + CURCODE +
"&TXCODE=" + TXCODE +"&REMARK1=" + REMARK1 +"&REMARK2=" + REMARK2 + "&TYPE=" + TYPE + "&PUB=" + PUB + "&GATEWAY=" + GATEWAY
+ "&CLIENTIP=" + CLIENTIP +"®INFO=" + REGINFO+"&PROINFO=" + PROINFO+"&REFERER=" + REFERER
+ "&TRADE_TYPE=" + TRADE_TYPE + "&SUB_APPID=" + SUB_APPID +
"&SUB_OPENID=" + SUB_OPENID;
map.put("MAC", MD5Util.MD5Encode(param,"UTF-8"));
String ret = HttpClientUtil.httpPostCCB(bankURL, map);
System.out.println(ret);
}
3.2 充值回调
//为了安全情况下,需要把参数,进行校验,一下方法简写,忽略校验了
@ApiOperation("建行服务器支付回调")
@PostMapping("bank/callback")
public String bankCallBack(HttpServletRequest request) {
Map<String, String> map = new HashMap<String, String>();
Enumeration<String> parameterNames = request.getParameterNames();
StringBuilder data = new StringBuilder();
while (parameterNames.hasMoreElements()) {
String name = (String) parameterNames.nextElement();
String value = request.getParameter(name);
map.put(name, value);
data.append(name).append("=").append(value).append("&");
}
log.info("bank callBack data : {}",data);
if (StringUtils.isBlank(map.get("BRANCHID")) || StringUtils.isBlank(map.get("POSID"))){
return null;
}
String orderid = map.get("ORDERID");
if (StringUtils.isBlank(orderid)){
return null;
}
if ("Y".equals(map.get("SUCCESS"))) {//表示支付成功
}
return "";
}
4、退款
public static void main(String[] args) {
OneRefundRequest oneRefundRequest = new OneRefundRequest();
oneRefundRequest.setREQUEST_SN("1111111111");//交易单号
oneRefundRequest.setCUST_ID("1111111111111");//商户号
oneRefundRequest.setUSER_ID("1111111111111-003");//操作员号
oneRefundRequest.setPASSWORD("11111111");//操作员密码
oneRefundRequest.setTX_CODE(Const.CCB_5W1004);//交易码
oneRefundRequest.setLANGUAGE(Const.CCB_LANGUAGE_CN);//语言
OneRefundRequest.Body body = new OneRefundRequest.Body();
body.setMONEY("30.00");//退款金额
body.setORDER("12aadsda2dsad944443");//订单号
oneRefundRequest.setBody(body);
String xmlMsg = null;
try {
xmlMsg = XmlUtil.convertToXML(oneRefundRequest);
} catch (JAXBException e) {
throw new RuntimeException(e.getMessage());
}
System.out.println(xmlMsg);
String oneRefundRsponseStr = "";
try {
//外联平台的ip和端口
oneRefundRsponseStr = HttpClientUtil.sendHttpRequest("127.0.0.1",12345, xmlMsg);
}catch (Exception e){
}
System.out.println(oneRefundRsponseStr);
}
5、查询
5.1 充值查询
public static void main(String[] args) {
AccountPayJournalRequest accountPayJournalRequest = new AccountPayJournalRequest();
accountPayJournalRequest.setREQUEST_SN("1111111111111");
accountPayJournalRequest.setCUST_ID("1111111111111");//商户号
accountPayJournalRequest.setUSER_ID("1111111111111-003");//操作员号
accountPayJournalRequest.setPASSWORD("111111");//操作员面
accountPayJournalRequest.setTX_CODE(Const.CCB_5W1002);//交易码
accountPayJournalRequest.setLANGUAGE(Const.CCB_LANGUAGE_CN);//语言
AccountPayJournalRequest.Body body = new AccountPayJournalRequest.Body();
accountPayJournalRequest.setBody(body);
body.setKIND("1");//0:未结流水,1:已结流水
body.setORDER("0001000026821683267596082");//按订单号查询时,时间段不起作用
body.setDEXCEL("1");//默认为“1”,1:不压缩,2.压缩成zip文件
body.setNORDERBY("2");//排序 1:交易日期,2:订单号
body.setPAGE(1);//当前页次
body.setSTATUS("1");//0:交易失败,1:交易成功,2:待银行确认(针对未结流水查询);3:全部
String xmlMsg = null;
try {
xmlMsg = XmlUtil.convertToXML(accountPayJournalRequest);
} catch (JAXBException e) {
throw new RuntimeException(e.getMessage());
}
String accountJournalRequestStr = "";
try {
accountJournalRequestStr = HttpClientUtil.sendHttpRequest("localhost",12345, xmlMsg);
}catch (Exception e){
}
System.out.println(accountJournalRequestStr);
}
5.2 退款查询
public static void main(String[] args) {
AccountRefundJournalRequest oneRefundRequest = new AccountRefundJournalRequest();
oneRefundRequest.setREQUEST_SN("111111111");//交易单号
oneRefundRequest.setCUST_ID("1111111111111");//商户号
oneRefundRequest.setUSER_ID("1111111111111-003");//操作员号
oneRefundRequest.setPASSWORD("11111111");//操作员密码
oneRefundRequest.setTX_CODE(Const.CCB_5W1003);//交易码
oneRefundRequest.setLANGUAGE(Const.CCB_LANGUAGE_CN);//语言
AccountRefundJournalRequest.Body body = new AccountRefundJournalRequest.Body();
body.setORDER("0001000026821683267596082");//订单号
body.setSTATUS("3");
body.setPAGE(0);
body.setNORDERBY("2");
body.setKIND("1");
oneRefundRequest.setBody(body);
String xmlMsg = null;
try {
xmlMsg = XmlUtil.convertToXML(oneRefundRequest);
} catch (JAXBException e) {
throw new RuntimeException(e.getMessage());
}
System.out.println(xmlMsg);
String oneRefundRsponseStr = "";
try {
oneRefundRsponseStr = HttpClientUtil.sendHttpRequest("localhost",12345, xmlMsg);
}catch (Exception e){
}
System.out.println(oneRefundRsponseStr);
}
6、 外联平台发布k8s
为了方便可以在本地将证书添加到外联品台里,或者使用pv挂载
6.1 将文件打成压缩包
ccb_web_connect.zip
6.2 构建Dockerfile
FROM java:8
ADD ccb_web_connect.zip ./
RUN unzip ccb_web_connect.zip && chmod 755 /ccb_web_connect/bin/startService.sh
WORKDIR /ccb_web_connect/bin
## 参数依次为------- 商户号 操作员号 操作员密码 证书密码 端口号
ENTRYPOINT ["sh","-c","./startService.sh 1111111111111 1111111111111-003 111111 123456 12345"]
6.3 构建无状态服务
kubectl create -f 文件名称
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "12"
labels:
app: ccb-connect-test
name: ccb-connect-test
namespace: cloud-test
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: ccb-connect-test
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: ccb-connect-test
spec:
containers:
- image: 192.168.32.14/prihub/ccb_connect:test
imagePullPolicy: Always
name: ccb-connect-dkxpw
ports:
- containerPort: 12345
name: 12345aa
protocol: TCP
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
terminationGracePeriodSeconds: 30
7、 帮助指导
YDCA02910001 | 流水记录不存在 | 查询成功 | |
0250E0200001 | 流水记录不存在 | 查询成功 | |
YFCP1001A00D | 通讯故障 | 查询失败 | 建议重发查询交易 |
YALA02910002 | 查询过于频繁,请稍后再试 | 查询失败 | 减少不必要的查询 |
0130Z1109064 | 操作员已被冻结,不能进行交易。请向主管咨询有关情况 | 查询失败 | 找商户主管解冻操作员 |
0130Z1101018 | 您输入的信息不正确,请重新输入。 | 查询失败 | “1、商户主管不能发外联交易,要使用操作员 2、PC端用操作员登书登录一次商户服务平台(https://merchant.ccb.com/MCMain.htm)” |
0130Z1101002 | 您输入的交易要素格式或范围不正确,请重新输入。 | 查询失败 | 发送报文参数有误,请核验报文与接口字段 |
0130Z1101021 | 您输入的密码不正确,请重新输入。 | 查询失败 | 检查报文交易密码是否正确 |
YBLA06412001 | 子商户与主商户信息不匹配 | 查询失败 | 检查主子商户关系 |
YBLP1MERCX01 | 子商户与主商户信息不匹配 | 查询失败 | 联系银行维护集团商户关系 |
YBLP1MERCX02 | ***(主商户号)无查询权限 | 查询失败 | 联系银行维护商户集团使用目的 |
YBLP1MERCX05 | ***(子商户号)不是集团商户的子商户 | 查询失败 | 联系银行维护集团商户关系 |
YBLA02910011 | 不符合规则 | 查询失败 | 发送报文参数有误,请核验报文与接口字段 |
YBLA02910003 | 商户已经注销 | 查询失败 | 联系银行处理 |
0130Z0100001 | 暂时未能处理您的请求,请稍后再试。【交易超时】 | 状态不确定 | 先调用5W1003退款查询,返回退款记录,则无需发起退款;无退款记录返回,则在120秒后再发起5W1003退款查询; |
ZTLAP101AL03 | 未知错误,@@20000 | 状态不确定 | 建议商户核实商户账处理状态后再发起退款 |
ZBLAP101WX03 | 未知报错,@@SYSTEMERROR~~请求平台数据返回异常,请稍后再试@@ | 状态不确定 | 建议商户隔段时间重试 |
YBLP1MERTH01 | 此笔订单正在退款中,不可以重复退款 | 退款失败 | 不要重复退款 |
0130Z0100002 | 暂时未能处理您的请求,请稍后再试。【通讯故障】 | 退款失败 | 建议重发退款交易 |
YFCP1001A00E | 暂时未能处理您的请求,请稍后再试。 | 退款失败 | 建议重发退款交易 |
YALA02910002 | 查询过于频繁,请稍后再试 | 查询失败 | 建议降低退款频率后,重发退款交易 |
YBLA02910008 | 终端【***(终端号)】不允许退货 | 退款失败 | 联系银行开通退款功能 |
YBLA02910010 | 金额不足. 退款失败 | ||
YBLA02910011 | 退款金额与原交易的订单金额不一致,交易拒绝 | 退款失败 | 该交易仅支持全额退款,建议检查退款金额后重发退款交易 |
YBLA02910014 | 累计退款金额超限,交易拒绝 | 退款失败 | |
ZBLAP101WX01 | 支付不成功,@@ERROR~~您的请求参数与订单信息不一致@@ 扣商户账成功,入客户账失败 需核实退款中上送的微信商户信息(如channel_id上送是否正确),若正确还报此类错误,则需要提供相关信息,找微信排查下。 | ||
XFCF40100001 | 超出流量限制 | 退款失败 | |
0130Z110C064 | 没有查询到符合条件的记录。 | 退款失败 | |
0130Z110C405 | 退款金额不能大于原支付金额。 | 退款失败 | |
0130Z110C032 | 退款金额不能大于原交易金额。 | 退款失败 | |
0130Z110W001 | 序列号错误 | 退款失败 | 不能用同一序列号发两次退款 |
YBLA06412001 | 未查询到相关数据 | 退款失败 | 退款对应的支付订单不存在 |
YBLP1MERCX05 | ***(子商户号)不是集团商户的子商户 | 退款失败 | 联系银行维护集团商户关系 |