首先吐槽一个工行的效率问题,兜圈子,回复慢,人家事还多。对接和一堆业务员对接,完全不懂技术,说不到点上。给的账号三番五次是错的,并且文档描述也和实际demo不一致,完全靠百度一点一点磨出来的。

微信小程序只能走微信支付,所以应客户需求走工行渠道的微信支付。

先贴可以执行的代码:

package com.hbbc.pi;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.hbbc.icbc.testxcx;
import com.hbbc.util.DBUtil;
import com.hbbc.util.LogUtil;
import com.hbbc.util.SignArithmeticUtil;
import com.hbbc.util.hf.HFContext;
import com.icbc.api.DefaultIcbcClient;
import com.icbc.api.IcbcApiException;
import com.icbc.api.IcbcConstants;
import com.icbc.api.request.AggregatePayHidePayRequestV1;
import com.icbc.api.request.AggregatePayHidePayRequestV1.AggregatePayHidePayRequestV1Biz;
import com.icbc.api.response.AggregatePayHidePayResponseV1;

import Decoder.BASE64Decoder;

public class PayICBC {
	private String MY_PRIVATE_KEY = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCyisf78uAWzRXlTspmRyiY7nl6pAgBBVxJiRXKTqzvEayu0VacBEegEWZaHqR0trIQ80FRO845bvHYGERtOIqWDGIGqT3FOeXg+cYC+dQWr/2mZpTSyt3n68vxUpJQKCiOP4B8TDQ+1pMRcgiVcAnBqOwzNrTF8nZzHfogfHpYrvO4J+OLGditU3qpuFfc4uaNjkUkQ4r2/0nIc2XiHC3i2ex3pWVjgz706jCbAb0iJiVDxefdYgUwIx5q5KjnjzmHPT5GPLdW+H8LeA0eiWlzI/KZ46mUK9v6UOasjtFko6sLmwbmveMhAMLKB6WqLYE2g9HfHBaMfqOYVvzX7RWLAgMBAAECggEBAKJIlOgEZf0zonBQgpYend8L++0mhYPwDGdmrCC8DGIs7YnlC1U6aqQqzJ6jdZYEravMf5/XaSwbBYAjquMUUMlGdqWDIdJNeVMZFsKqCgwqp+SH0dWklobUS+ZzUM7DANZhFZ8OqI/labkTull+pnDAczImUDmgqWj0HB+nsaWyXfv+8qxyWYjYYkwYVZa9leI5Q/2veAzjXkMhQOWnFT7Rcd5OncJExrpH5EifbFYknLEoNS7ZHqtEAgI3euOh9NcxWOeZ5YEuE9rUm0lsGrQinRzqEp4FQUDSNImJCGTzKJuUs68rKS9Yb4hawGXYd++erfhvgwKexgBuCgYEA/i7Y9j8XQ9JiUUD2zNEVohMK4FTBkz/DGPBkO5L+Gkhkx3OQAPt3+EsTnW/qard+VqZ/4TYOYo/8jPWgL5Q5Nun9btJYltsN4boclB6TTuNHlV2nGPtvQUfQ5B+WidXKSJ77dLaP7qrl0K36xLr0LuO/VVw/bG4K5JXJNOnWNNkCgYEAs9GC9pme6MoSc4tA1wlgTwjBu+wtsJRG7yttlowe+dbyVYhCBKKh3o+73vlcjgGv5ucrwwfpTWPaxakgzITCoOiBq4JLdvy9T/lfeef/o9TYUEWcG0c7va+ifQtQvj9DsgTDBbIRgFB5WJBgcKGwaqJlcw3ba08FPhrnHzwMCgYEAw/CpH2oTLR0I3UoO9mRXINE9GSE89523b4ogOixd5TTZO0dCQv+Ww7hcLokPU6SPp4xCGAHrpN8J+D+AdCz2zfYif0N3NxM16EPns+a995oMnH/NR9zLLq+Fv9T53tcHUGP9w0LYQUtMTUlQfkb/5QV7gPnTimppyzwMFtYLYkECgYA9/W85ljILLIZ54LrEpw3VkT5Ai6Ygpq1hjEYmTT3sgWZfiC7CLFLDSCfLMYnvxrMeVflnLdYHAPKNi8Wr2+SPt7njuANAUkExxJ4fI6mlw0xLJI58hVj7gWxWdgZZYo7W9H5j9yvnPidlKCQoI0upv8Lc9qndFJ9RuuWwm2E/gwKBgQCCIsoHkplSzFLkEalvJ2O8E4jf/PgrVKxa5bHruS7fNNQIhTGCyO5mCkWjCKLhTaFiHiOSUg+vMIP9rUP/zYmPoqVF47EfKNTwHgShtt0pwGZ6gh3mJaeaeZB8FYy2xkeKLRdNWXswF6EZGbsLyBbX33iov5OxVyC/SUX8U1qKMg==";
	protected static final String APP_ID = "100000000000001xxxxx"; 
	private final String mch_id = "020059xxxxxx";//商户号
	//网关公钥  测试
	protected static final String APIGW_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwFgHD4kzEVPdOj03ctKM7KV+16bWZ5BMNgvEeuEQwfQYkRVwI9HFOGkwNTMn5hiJXHnlXYCX+zp5r6R52MY0O7BsTCLT7aHaxsANsvI9ABGx3OaTVlPB59M6GPbJh0uXvio0m1r/lTW3Z60RU6Q3oid/rNhP3CiNgg0W6O3AGqwIDAQAB";
	public static void main(String[] args) throws Exception {
		testxcx payment = new testxcx();
		payment.payment();
	}
	public void payment() throws Exception {
		//参数传递自行处理
		String openId = postData.getString("openId");
		String orderID = postData.getString("orderID");
		String total = postData.getString("total");
		DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, IcbcConstants.SIGN_TYPE_RSA2, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY); 
		AggregatePayHidePayRequestV1 request = new AggregatePayHidePayRequestV1(); 
		request.setServiceUrl("https://xxxx/api/mybank/pay/aggregatepay/hidepayrequest/V2"); 
		AggregatePayHidePayRequestV1Biz bizContent = new AggregatePayHidePayRequestV1Biz(); 
		String today = new SimpleDateFormat("YYYYMMddHHmmss").format(new Date());
		 Calendar nowTime = Calendar.getInstance();
		  nowTime.add(Calendar.MINUTE, 10);
		  String endtoday = new SimpleDateFormat("YYYYMMddHHmmss").format(nowTime.getTime());
		String hourString =new SimpleDateFormat("HHmmss").format(new Date());
		bizContent.setOutTradeNo(orderID); //商户订单号;需保证商户系统唯一
		bizContent.setOrderChannel("100"); // 下单发起渠道,100对应微信小程序, 101对应微信公众号,102对应支付宝生 活号
		bizContent.setTpAppId("wxe317859xxx86xx5e");  // 第三方应用ID;商户在微信公众号内接入时必送,上送微信分配的公众账号ID;商户通过支付宝生活号接入时必送,上送支付宝分配的应用ID。目前暂不支持上送 
		bizContent.setMerId("020059xxxxx");    //   商户号 正常
		bizContent.setTpOpenId(openId);   //第三方用户标识;商户在微信公众号/支付宝生活号内接入时必送,上送用户在商户appid下的唯一标识。 目前暂不支持上送。
		bizContent.setTranType("OfflinePay"); //交易类型。用于区分交易场景为线上支 付还是线下支付,对应数据字典: OfflinePay-线下支付,OnlinePay-线上 支付。
		bizContent.setOrderDate(today); //交易提交时间, 格式为: YYYYMMDDHHmmss 
		bizContent.setEndTime(endtoday); // 交易过期时间
		bizContent.setGoodsBody("xxxx"); 
		bizContent.setInstallTimes("1");
		bizContent.setOrderAmount(total); //总金额(单位:分)
		bizContent.setSpbillCreateIp("127.0.0.1"); //请求发起终端ip(商户后台发起请求的服务器IP地址,如果获取不到上送127.0.0.1即可)
		bizContent.setNotifyUrl("http://115.171.19.161:11452/servlet/ICBCOFSTEBizServlet?tokenID=1303");
		bizContent.setNotifyType("HS"); //通知类型,表示在交易处理完成后把交 易结果通知商户的处理模式。 取 值“HS”:在交易完成后将通知信息,主 动发送给商户,发送地址为notify_url指 定地址; 取值“AG”:在交易完成后不通 知商户
		bizContent.setReturnUrl("http://paycenter.uboxol.com/payment/notify/icbcpay_wap");
		bizContent.setInterfaceVersion("1.1.0.0"); //接口号,目前仅支持上送1.1.0.0
		bizContent.setResultType("0");
		request.setBizContent(bizContent); 
		AggregatePayHidePayResponseV1 response; 
		try {
			response = client.execute(request,today); 
			LogUtil.log("getPrepayId:"+response.getPrepayId());
			LogUtil.log("getReturnMsg:"+response.getReturnMsg());
			LogUtil.log("getReturnUrl:"+response.getReturnUrl());
			LogUtil.log("getTranErrorCode:"+response.getTranErrorCode());
			LogUtil.log("isSuccess:"+String.valueOf(response.isSuccess()));
			LogUtil.log("ReturnMsg:"+String.valueOf(response.getReturnMsg()));
			LogUtil.log("Returncode:"+String.valueOf(response.getReturnCode()));
			if (response.getReturnCode()==0) {
				LogUtil.log("下单成功!");
				List<String> resultList=new ArrayList<String>();
				   BASE64Decoder decoder = new BASE64Decoder();
				   String aString = new String(decoder.decodeBuffer(response.getSignData()), "utf-8");
				   Map<String, String> map = (Map)JSON.parse(aString);
				   String nonceString = map.get("nonceStr");
				   String timeStamp = map.get("timeStamp");
				   String paySign =map.get("paySign");
				   resultList.add(paySign);
				   resultList.add("prepay_id="+response.getPrepayId());
				   resultList.add(nonceString);
				   resultList.add(timeStamp);
				   String reString= JSON.toJSONStringWithDateFormat(resultList, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat);
					LogUtil.log("[payment]最终接口返回数据:" + reString);
					ctx.output.returnStringDirectly(reString);
			}else {
				LogUtil.log("下单失败!");
				ctx.output.returnStringDirectly("下单失败!");
			}
		   

		} catch (IcbcApiException e) { e.printStackTrace(); }
	}
	
}

踩坑:一脚一个大坑

1. 如果出现APPID没授权,无效等去找工行,是他们没开权限。

2.文档上写的result_type参数选输,但是这项为空就过不去,在官网上找的和他相关的文档为必输项。

3.给的我请求地址是V2,但是文档上的参考是V1

4.文档上的tran_type是线上线下,业务为线上支付,但是工行就让传线下支付,没有原因。

5.当你完成了工行支付请求,它会响应一个预支付成功,工行业务回复没有预支付这个概念????最后还是预支付成功的。

6.当预支付成功以后,会返回一个sign_data用于唤起微信支付,但是它是base64编码,需解码,解码完之后会有一串内容,用于小程序即可。

7.但是问题来了,小程序API上写的签名类型只有两种,但是工行返回的签名类型是RSA,为此我找了半天转格式,一直签名错误,不用管这些说明,直接拿过来用,signType就是RSA就行。

工商银行 微服务 工商银行微信客户端_工行小程序支付

8.测试网关公钥和线上网关公钥不同,拿着线上网关公钥报 Signature length not correct: got 128 but was expecting 256,工行就是说公钥没问题,最后发现给的是网站的网关公钥,并且生产环境的商户号也没有建档。