package com.java110.acct.payment.adapt.icbc; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.icbc.api.DefaultIcbcClient; import com.icbc.api.IcbcApiException; import com.icbc.api.IcbcConstants; import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1; import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz; import com.icbc.api.response.CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1; import com.icbc.api.utils.IcbcEncrypt; import com.icbc.api.utils.IcbcSignature; import com.icbc.api.utils.WebUtils; import com.java110.acct.payment.IPaymentFactoryAdapt; import com.java110.acct.payment.adapt.plutus.PlutusPaymentFactoryAdapt; import com.java110.core.context.ICmdDataFlowContext; import com.java110.core.factory.CommunitySettingFactory; import com.java110.core.factory.WechatFactory; import com.java110.core.log.LoggerFactory; import com.java110.dto.app.AppDto; import com.java110.dto.owner.OwnerAppUserDto; import com.java110.dto.payment.PaymentOrderDto; import com.java110.dto.smallWeChat.SmallWeChatDto; import com.java110.intf.store.ISmallWechatV1InnerServiceSMO; import com.java110.intf.user.IOwnerAppUserInnerServiceSMO; import com.java110.utils.cache.MappingCache; import com.java110.utils.constant.WechatConstant; import com.java110.utils.util.BeanConvertUtil; import com.java110.utils.util.DateUtil; import com.java110.utils.util.PayUtil; import com.java110.utils.util.StringUtil; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.*; /** * 工商银行支付 *

* 这个适配器使用需要 安装 工商银行的 jar 安装到maven * 这里 以免影响 编译 所以这个Java 改名为txt *

* 如果需要工商银行支付 * 1、将 工商银行提供的 icbc-api-sdk-cop icbc-api-sdk-cop-io icbc-ca 安装到自己的私有仓库 怎么安装请百度 *

* 2、根据你安装的 命令 会 有如下的三个jar的依赖包,将这三个系诶到 service-acct 下的pom.xml 文件中 *

* * com.icbc * icbc-api-sdk-cop * v1.0 * * * com.icbc * icbc-api-sdk-cop-io * v1.0 * * * com.icbc * icbc-ca * v1.0 * *

*

* 3、将 此类 文件 名去掉最后的TXT 修改 为Java 后缀 *

* 4、执行mvn clean install 执行打包测试 *

* 5、如果要二次开发优化参考 工商银行协议 * https://open.icbc.com.cn/icbc/apip/api_detail.html?apiId=10000000000000137000&baseUrl=%2Fcardbusiness%2Faggregatepay%2Fb2c%2Fonline&resUrl=%2Fconsumepurchase&version=V1&apiName=聚合支付B2C线上消费下单&serviceId=P0067&resourceId=10000000000000009800 * * @desc add by 吴学文 15:33 */ @Service("icbcPaymentFactory") public class IcbcPaymentFactoryAdapt implements IPaymentFactoryAdapt { private static final Logger logger = LoggerFactory.getLogger(PlutusPaymentFactoryAdapt.class); //微信支付 public static final String DOMAIN_WECHAT_PAY = "WECHAT_PAY"; // 微信服务商支付开关 public static final String WECHAT_SERVICE_PAY_SWITCH = "WECHAT_SERVICE_PAY_SWITCH"; //开关ON打开 public static final String WECHAT_SERVICE_PAY_SWITCH_ON = "ON"; public static final String TRADE_TYPE_NATIVE = "NATIVE"; public static final String TRADE_TYPE_JSAPI = "JSAPI"; public static final String TRADE_TYPE_MWEB = "MWEB"; public static final String TRADE_TYPE_APP = "APP"; @Autowired private ISmallWechatV1InnerServiceSMO smallWechatV1InnerServiceSMOImpl; @Autowired private IOwnerAppUserInnerServiceSMO ownerAppUserInnerServiceSMOImpl; @Autowired private RestTemplate outRestTemplate; @Override public Map java110Payment(PaymentOrderDto paymentOrderDto, JSONObject reqJson, ICmdDataFlowContext context) throws Exception { SmallWeChatDto smallWeChatDto = getSmallWechat(reqJson); String appId = context.getReqHeaders().get("app-id"); String userId = context.getReqHeaders().get("user-id"); String tradeType = reqJson.getString("tradeType"); String notifyUrl = MappingCache.getValue(MappingConstant.URL_DOMAIN,"OWNER_WECHAT_URL") + "/app/payment/notify/icbc/992020011134400001"; String openId = reqJson.getString("openId"); if (StringUtil.isEmpty(openId)) { String appType = OwnerAppUserDto.APP_TYPE_WECHAT_MINA; if (AppDto.WECHAT_OWNER_APP_ID.equals(appId)) { appType = OwnerAppUserDto.APP_TYPE_WECHAT; } else if (AppDto.WECHAT_MINA_OWNER_APP_ID.equals(appId)) { appType = OwnerAppUserDto.APP_TYPE_WECHAT_MINA; } else { appType = OwnerAppUserDto.APP_TYPE_APP; } OwnerAppUserDto ownerAppUserDto = new OwnerAppUserDto(); ownerAppUserDto.setUserId(userId); ownerAppUserDto.setAppType(appType); List ownerAppUserDtos = ownerAppUserInnerServiceSMOImpl.queryOwnerAppUsers(ownerAppUserDto); if (ownerAppUserDtos == null || ownerAppUserDtos.size() < 1) { throw new IllegalArgumentException("未找到开放账号信息"); } openId = ownerAppUserDtos.get(0).getOpenId(); } logger.debug("【小程序支付】 统一下单开始, 订单编号=" + paymentOrderDto.getOrderId()); SortedMap resultMap = new TreeMap(); //生成支付金额,开发环境处理支付金额数到0.01、0.02、0.03元 double payAmount = PayUtil.getPayAmountByEnv(MappingCache.getValue("HC_ENV"), paymentOrderDto.getMoney()); //添加或更新支付记录(参数跟进自己业务需求添加) JSONObject resMap = null; resMap = this.java110UnifieldOrder(paymentOrderDto.getName(), paymentOrderDto.getOrderId(), tradeType, payAmount, openId, smallWeChatDto, notifyUrl ); if (TRADE_TYPE_JSAPI.equals(tradeType)) { resultMap.putAll(JSONObject.toJavaObject(resMap, Map.class)); resultMap.put("sign", resultMap.get("paySign")); } else if (TRADE_TYPE_APP.equals(tradeType)) { resultMap.put("appId", smallWeChatDto.getAppId()); resultMap.put("timeStamp", PayUtil.getCurrentTimeStamp()); resultMap.put("nonceStr", PayUtil.makeUUID(32)); resultMap.put("partnerid", smallWeChatDto.getMchId()); resultMap.put("prepayid", resMap.getString("session_id")); //resultMap.put("signType", "MD5"); resultMap.put("sign", PayUtil.createSign(resultMap, smallWeChatDto.getPayPassword())); } else if (TRADE_TYPE_NATIVE.equals(tradeType)) { resultMap.put("prepayId", resMap.getString("session_id")); resultMap.put("codeUrl", resMap.getString("qr_code")); } resultMap.put("code", "0"); resultMap.put("msg", "下单成功"); logger.info("【小程序支付】统一下单成功,返回参数:" + resultMap); return resultMap; } private JSONObject java110UnifieldOrder(String feeName, String orderNum, String tradeType, double payAmount, String openid, SmallWeChatDto smallWeChatDto, String notifyUrl) throws Exception { //String systemName = MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, WechatConstant.PAY_GOOD_NAME); String privateKey = CommunitySettingFactory.getRemark(smallWeChatDto.getObjId(), "ICBC_PRIVATE_KEY"); String apiPublicKey = CommunitySettingFactory.getRemark(smallWeChatDto.getObjId(), "ICBC_PUBLIC_KEY"); String merId = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "ICBC_MER_ID"); String merPrtclNo = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "ICBC_MER_PRTCL_NO"); String deciveInfo = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "ICBC_DECIVE_INFO"); String appName = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "ICBC_APP_NAME"); String icbcAppId = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "ICBC_APP_ID"); String appId = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "APP_ID"); System.out.println("appId=" + appId); System.out.println("privateKey=" + privateKey); System.out.println("apiPublicKey=" + apiPublicKey); System.out.println("merId=" + merId); System.out.println("merPrtclNo=" + merPrtclNo); System.out.println("deciveInfo=" + deciveInfo); System.out.println("appName=" + appName); System.out.println("icbcAppId=" + icbcAppId); DefaultIcbcClient client = new DefaultIcbcClient(appId, IcbcConstants.SIGN_TYPE_RSA2, privateKey, apiPublicKey); CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1 request = new CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1(); //根据测试环境和生产环境替换相应ip和端口 request.setServiceUrl("https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/consumepurchase/V1"); CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz bizContent = new CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz(); request.setBizContent(bizContent); //请对照接口文档用bizContent.setxxx()方法对业务上送数据进行赋值 bizContent.setMer_id(merId); bizContent.setOut_trade_no(orderNum); bizContent.setPay_mode("9"); bizContent.setAccess_type("7"); bizContent.setMer_prtcl_no(merPrtclNo); bizContent.setOrig_date_time(DateUtil.getNow(DateUtil.DATE_FORMATE_STRING_E).replace("Z", "")); bizContent.setDecive_info(deciveInfo); bizContent.setBody(appName + "-购买商品"); bizContent.setFee_type("001"); bizContent.setSpbill_create_ip("192.168.1.8"); bizContent.setTotal_fee(PayUtil.moneyToIntegerStr(payAmount)); bizContent.setMer_url(notifyUrl); bizContent.setShop_appid(smallWeChatDto.getAppId()); bizContent.setIcbc_appid(icbcAppId); bizContent.setOpen_id(openid); // bizContent.setMer_acct("6212880200000038618"); bizContent.setExpire_time("120"); //bizContent.setNotify_type("HS"); bizContent.setNotify_type("HS"); bizContent.setResult_type("1"); bizContent.setPay_limit("no_credit"); bizContent.setOrder_apd_inf(""); CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1 response; response = client.execute(request, System.currentTimeMillis() + "");//msgId消息通讯唯一编号,要求每次调用独立生成,APP级唯一 if (response.getReturnCode() == 0) { // 6、业务成功处理,请根据接口文档用response.getxxx()获取同步返回的业务数据 System.out.println("ReturnCode:" + response.getReturnCode()); System.out.println("response:" + JSON.toJSONString(response)); return JSONObject.parseObject(response.getWx_data_package()); } else { // 失败 System.out.println("ReturnMsg:" + response.getReturnMsg()); throw new IllegalArgumentException("支付失败" + response.getReturnMsg()); } } @Override public PaymentOrderDto java110NotifyPayment(String param) { PaymentOrderDto paymentOrderDto = new PaymentOrderDto(); JSONObject json = JSON.parseObject(param); String appId; if (json.containsKey("wId")) { String wId = json.get("wId").toString(); wId = wId.replace(" ", "+"); appId = WechatFactory.getAppId(wId); } else { appId = json.get("appid").toString(); } JSONObject paramIn = new JSONObject(); paramIn.put("appId", appId); SmallWeChatDto smallWeChatDto = getSmallWechat(paramIn); if (smallWeChatDto == null) { throw new IllegalArgumentException("未配置公众号或者小程序信息"); } Map params = new HashMap(); params.put("from", json.getString("from")); params.put("api", json.getString("api")); params.put("app_id", json.getString("app_id")); params.put("charset", json.getString("charset")); params.put("format", json.getString("format")); params.put("encrypt_type", json.getString("encrypt_type")); params.put("timestamp", json.getString("timestamp")); params.put("biz_content", json.getString("biz_content")); params.put("sign_type", json.getString("sign_type"));//目前上行网关签名暂时仅支持RSA String path = "/app/payment/notify/icbc/992020011134400001\""; String signStr = WebUtils.buildOrderedSignStr(path, params); String results = null; String responseBizContent = null; String apiPublicKey = CommunitySettingFactory.getRemark(smallWeChatDto.getObjId(), "ICBC_PUBLIC_KEY"); String theKey = CommunitySettingFactory.getValue(smallWeChatDto.getObjId(), "ICBC_KEY"); String privateKey = CommunitySettingFactory.getRemark(smallWeChatDto.getObjId(), "ICBC_PRIVATE_KEY"); boolean flag = false; String content = ""; try { flag = IcbcSignature.verify(signStr, json.getString("sign_type"), apiPublicKey, json.getString("charset"), json.getString("sign")); } catch (IcbcApiException e) { e.printStackTrace(); } if (!flag) { responseBizContent = "{\"return_code\":-12345,\"return_msg\":\"icbc sign not pass.\"}"; } else { /**********biz_content解密**********/ if ("AES".equals(json.getString("encrypt_type"))) { try { content = IcbcEncrypt.decryptContent(json.getString("biz_content"), json.getString("encrypt_type"), theKey, json.getString("charset")); } catch (IcbcApiException e) { e.printStackTrace(); } } /**********合作方/分行 业务逻辑处理**********/ JSONObject map = JSONObject.parseObject(content); logger.info("【iccb支付回调】 回调数据: \n" + map); //更新数据 paymentOrderDto.setOrderId(map.getString("out_trade_no")); paymentOrderDto.setTransactionId(map.getString("order_id")); String msg_id = map.get("msg_id").toString(); //业务返回参数设置 int return_code = 0; String return_msg = "success."; responseBizContent = "{\"return_code\":" + return_code + ",\"return_msg\":\"" + return_msg + "\",\"msg_id\":\"" + msg_id + "\"," + "\"busi_param_rp\":\"thisisresponseparameter\"}"; /**********response_biz_content加密**********/ if ("AES".equals(json.getString("encrypt_type"))) { try { responseBizContent = IcbcEncrypt.encryptContent(responseBizContent, json.getString("encrypt_type"), theKey, json.getString("charset")); } catch (IcbcApiException e) { e.printStackTrace(); } responseBizContent = "\"" + responseBizContent + "\""; } } signStr = "\"response_biz_content\":" + responseBizContent + "," + "\"sign_type\":" + "\"RSA\""; String sign = null; try { sign = IcbcSignature.sign(signStr, "RSA", privateKey, json.getString("charset"), theKey); } catch (IcbcApiException e) { e.printStackTrace(); } results = "{" + signStr + ",\"sign\":\"" + sign + "\"}"; paymentOrderDto.setResponseEntity(new ResponseEntity(results, HttpStatus.OK)); return paymentOrderDto; } private SmallWeChatDto getSmallWechat(JSONObject paramIn) { SmallWeChatDto smallWeChatDto = new SmallWeChatDto(); smallWeChatDto.setObjId(paramIn.getString("communityId")); smallWeChatDto.setAppId(paramIn.getString("appId")); smallWeChatDto.setPage(1); smallWeChatDto.setRow(1); List smallWeChatDtos = smallWechatV1InnerServiceSMOImpl.querySmallWechats(smallWeChatDto); if (smallWeChatDtos == null || smallWeChatDtos.size() < 1) { smallWeChatDto = new SmallWeChatDto(); smallWeChatDto.setAppId(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "appId")); smallWeChatDto.setAppSecret(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "appSecret")); smallWeChatDto.setMchId(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "mchId")); smallWeChatDto.setPayPassword(MappingCache.getValue(WechatConstant.WECHAT_DOMAIN, "key")); return smallWeChatDto; } return BeanConvertUtil.covertBean(smallWeChatDtos.get(0), SmallWeChatDto.class); } }