接入了一个比较冷萌的第三方环迅h5网关支付,发起订单以及同步/异步回调(文档中也有官方微信支付宝接入代码资源哦)

虽然之前对于接入第三方支付有比较多的经验,但是这次接入环迅h5支付还是花了2天半的时间才整入到项目中,遇到了一个坑耽搁了一天半,下面讲一下接入注意事项

 

  1. 可能大家一般都是接入微信支付宝等官方支付(微信支付宝官方支付全部已调通更换参数即可,下面会有下载资源链接),下面是环迅支付接入流程
  2. 环迅支付文档请看IPS接口定义技术规范-综合网关-V2.0.2,里面自带demo,demo并不是Javaweb项目,需要使用tomcat运行

 

demo启动效果访问地址:http://localhost:8080/accentry/

 

h5发起支付后会返回html代码,该代码可以在浏览器直接加载---------手机号登录------------------添加银行卡------------开通快捷支付-----------再次发送验证码进行付款-------付款成功后环迅服务器会同步回调以及异步回调

 

 

 

 

这会直接上接入代码了:发起h5网关支付类

AccEntryConfig/CollBackResponse/FunctionUtils/MerVerify/Request/SSLClient/SynchronousResponse/Utils这些类在demo中直接复制过来





package com.api.ips;

import java.net.URLEncoder;
import java.util.LinkedHashMap;

import org.junit.Test;

import com.alibaba.fastjson.JSONObject;

/**
 * 环迅支付工具
 *
 * @author leehao
 * @date 2019-09-25
 */
public class IpsPayUtils {

	/***
	 * 环迅h5支付
	 * 
	 * @param commodity  商品
	 * @param describe   描述
	 * @param payCode    订单号
	 * @param orderPrice 金额(以元为单位)
	 * @return
	 */
	public static String hxPay(String commodity, String describe, String payCode, String orderPrice) {
		String ts = AccEntryConfig.date;// AccEntryConfig.date;//时间戳
		String nonceStr = Utils.getRandomString(32);// 随机字符串
		String trxDtTm = AccEntryConfig.date;// 商户日期
		// 1.加密data
		JSONObject dt = new JSONObject(new LinkedHashMap());
		dt.put("platCode", "");// 平台编码默认1001
		dt.put("account", AccEntryConfig.accCode);// 账户号
		dt.put("trxId", payCode);// 商户订单号
		dt.put("trxDtTm", ts);// 订单日期
		dt.put("expireDtTm", "");// 订单截止时间
		dt.put("trxCcyCd", "156");// 币种枚举,默认 156
		dt.put("trxAmt", orderPrice);// 单位元
		dt.put("productType", "");// 产品类型
		dt.put("limitPayType", "");// 限制支付方式
		dt.put("lang", AccEntryConfig.lang);// 默认为zh
		dt.put("pageUrl", AccEntryConfig.successURL);// 页面回调地址
		dt.put("notifyUrl", AccEntryConfig.s2sURL);// 后台回调地址
		dt.put("attach", commodity);// 商品介绍
		dt.put("goodsDesc", describe);// 商品内容
		String ds = dt.toString();
		// 1
		// System.out.println("加密前data: " + ds);
		String signData = MerVerify.encryptAES(AccEntryConfig.AES_KEY, ds);
		// System.out.println("加密后signData: " + signData);
		// 2
		Request accEntryRequest = new Request(AccEntryConfig.version, AccEntryConfig.date, AccEntryConfig.merCode,
				nonceStr, AccEntryConfig.format, AccEntryConfig.encryptType, signData, AccEntryConfig.signType);
		String object = Utils.getParamStr(Utils.objectToMap(accEntryRequest));
		// System.out.println("加密前object: " + object);
		String signObject = MerVerify.signSHA256withRSA(AccEntryConfig.SHA256_PRIVATE_KEY, object);
		// System.out.println("加密后signObject: " + signObject);

		JSONObject retObj = new JSONObject();
		retObj.put("version", AccEntryConfig.version);
		retObj.put("ts", ts);
		retObj.put("merCode", AccEntryConfig.merCode);
		retObj.put("nonceStr", nonceStr);
		retObj.put("format", AccEntryConfig.format);
		retObj.put("encryptType", AccEntryConfig.encryptType);
		retObj.put("signType", AccEntryConfig.signType);
		retObj.put("account", AccEntryConfig.accCode);
		retObj.put("trxId", payCode);
		retObj.put("trxDtTm", trxDtTm);
		retObj.put("trxAmt", orderPrice);
		retObj.put("data", signData);
		retObj.put("sign", signObject);
		String response = null;
		try {
			response = Utils.postSubmit(AccEntryConfig.ipsURL, retObj);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "10001";
		}
		return response;

	}
  • 这里是发起请求接口以及支付回调(同步-异步 验签解析data中的数据)
    确认交易成功后必须响应环迅支付服务器"ipscheckok"否则会多次回调接口
    
    
    package com.api.ips;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    import java.net.URLEncoder;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.alibaba.fastjson.JSONObject;
    
    @RestController
    public class pay {
    
    	@GetMapping("pay")
    	public String payh() {
    		String hxPay = IpsPayUtils.hxPay("苹果", "虾皮苹果", "798484848444474", "0.01");
    		System.out.println(hxPay);
    		return hxPay;
    	}
    
    	/**
    	 * 同步回调
    	 * 
    	 * @param request
    	 * @param response
    	 * @throws UnsupportedEncodingException
    	 */
    	@RequestMapping("asynchroHuanxin")
    	public void asynchroHuanxin(HttpServletRequest request, HttpServletResponse response)
    			throws UnsupportedEncodingException {
    		JSONObject map = Utils.getJsonParam(request);
    		System.out.println("同步回调:" + map.toString());
    		String data = map.getString("data");
    	    String version = map.getString("version");
    	    String merCode = map.getString("merCode");
    	    String ts = map.getString("ts");
    	    String nonceStr = map.getString("nonceStr");
    	    String format = map.getString("format");
    	    String encryptType = map.getString("encryptType");
    	    String signType = map.getString("signType");
    	    String notifyType = map.getString("notifyType");
    	    String sign = map.getString("sign");
    	    String verifyObject = null;
    	    String decryptData = null;
    	    boolean verifyResult = false;
    		try {
    	        if (!Utils.isBlank(sign)) {
    	            CollBackResponse backResponse = new CollBackResponse(version,ts,merCode,nonceStr,
    	                    format,encryptType,data,signType,notifyType);
    	            verifyObject = Utils.getParamStr(Utils.objectToMap(backResponse));
    	            verifyResult = MerVerify.verifySHA256withRSA(AccEntryConfig.SHA256_PUBLIC_KEY,
    	                    verifyObject, sign);
    	            if (verifyResult) {
    	                decryptData = MerVerify.decryptAES(AccEntryConfig.AES_KEY, data);
    	                System.out.println("----:"+decryptData);
    	                JSONObject jo = JSONObject.parseObject(new String(decryptData));
    	                String trxId = jo.getString("trxId");//商户订单号
    	                String trxStatus = jo.getString("trxStatus");//订单状态
    	                String trxResultMsg = jo.getString("trxResultMsg");//订单消息
    	                String ipsTrxId = jo.getString("ipsTrxId");//IPS订单流水号
    	                if (trxStatus.equals("SUCCESS")) {
    						//交易成功
    	                	System.out.println("交易成功");
    					}
    	                if (trxStatus.equals("FAIL")) {
    						//交易失败
    	                	System.out.println("交易失败");
    					}
    	                if (trxStatus.equals("PROCESSING")) {
    						//交易处理中
    	                	System.out.println("交易处理中");
    					}
    	            }
    	        }
    	    } catch (Throwable ex) {
    	        ex.printStackTrace();
    	    }
    	}
    
    	/**
    	 * 异步回调
    	 * 
    	 * @param request
    	 * @param response
    	 */
    	@RequestMapping("synchroHuanxin")
    	public String synchroHuanxin(HttpServletRequest request, HttpServletResponse response) {
    		JSONObject map = Utils.getJsonParam(request);
    		System.out.println("异步回调:" + map.toString());
    		String data = map.getString("data");
    	    String version = map.getString("version");
    	    String merCode = map.getString("merCode");
    	    String ts = map.getString("ts");
    	    String nonceStr = map.getString("nonceStr");
    	    String format = map.getString("format");
    	    String encryptType = map.getString("encryptType");
    	    String signType = map.getString("signType");
    	    String notifyType = map.getString("notifyType");
    	    String sign = map.getString("sign");
    	    String verifyObject = null;
    	    String decryptData = null;
    	    boolean verifyResult = false;
    		try {
    	        if (!Utils.isBlank(sign)) {
    	            CollBackResponse backResponse = new CollBackResponse(version,ts,merCode,nonceStr,
    	                    format,encryptType,data,signType,notifyType);
    	            verifyObject = Utils.getParamStr(Utils.objectToMap(backResponse));
    	            verifyResult = MerVerify.verifySHA256withRSA(AccEntryConfig.SHA256_PUBLIC_KEY,
    	                    verifyObject, sign);
    	            if (verifyResult) {
    	                decryptData = MerVerify.decryptAES(AccEntryConfig.AES_KEY, data);
    	                System.out.println("----:"+decryptData);
    	                JSONObject jo = JSONObject.parseObject(new String(decryptData));
    	                String trxId = jo.getString("trxId");//商户订单号
    	                String trxStatus = jo.getString("trxStatus");//订单状态
    	                String trxResultMsg = jo.getString("trxResultMsg");//订单消息
    	                String ipsTrxId = jo.getString("ipsTrxId");//IPS订单流水号
    	                if (trxStatus.equals("SUCCESS")) {
    						//交易成功
    	                	System.out.println("交易成功");
    	                	return "ipscheckok";
    					}
    	                if (trxStatus.equals("FAIL")) {
    						//交易失败
    	                	System.out.println("交易失败");
    					}
    	                if (trxStatus.equals("PROCESSING")) {
    						//交易处理中
    	                	System.out.println("交易处理中");
    					}
    	            }
    	        }
    	    } catch (Throwable ex) {
    	        ex.printStackTrace();
    	    }
    		return null;
    	}
    	}
    
    

    所需的jar包在demo全部复制过来即可,但是不支持maven从网上仓库引入依赖,会导致无法加载私钥。目前我是直接把jar包添加到项目中,大家可以尝试本地安装jar再引入依赖

这里是支付成功后环迅服务器回调接口传过来的参数值,订单状态以及订单信息都在data中。需要解密
验签需要把所有参数通过文档方式加密一遍与sign相对比

同步回调:

{"merCode":"178767",
"notifyType":"1",
"data":"83b8203f20b6a9aabb79a9c3735ae75f8a3bd1c1b99e8972b4146297ccd2ed17a0948434480fd47f270a41093800b02e6bf426bacd846bc88b4671a89a51af3e8c0bf611d7e744d0b8b293e47aeae983597d02a98f8b90a0c5f9c738906d625c27fd52b39d7bcf05171c960ad535a26569d2579bd1ee6f921395e6258064067298694b8d80269276459cf4703c4c21a22d5fe9803fa7ce38d650cba8131504c0e3e965de980ba8525d452507b735db5f91ec6ac9ffbcd5555d22ddcdfbed1a2e486493de9bac03367857923f6effa9fbffe6d26dde4cdb7e818ab4dd3020c1acab938d42811e81c606ef2f462015f03b89e4f805eb0df182407bc68ed12e5f510785e1c5d324e756ef4c85b4ba63635773782a75d3559ec519e59a4a7814c942b09757c8f6d07d9c21c6bf67c92f13387a481410cc28a6208f3d5e5996fa0195a822abe5c6303e2439a56a4e443a19c72a9f652eb97112c3551a87e38741e5edf36f3fdbdf94222b52be63ad81e075da898700e380e5d44509a7ba59305ec995c8e61c3746fa1b7cd8ba1b3ba72969a9",
"sign":"3ff5680aed7a5667a19015567efd86d9b6734191746be3e31c095c629ee9763e63e58acccbe01c706f2e6d431f20d9fcca6b9bb3e58afb621a0bc53300ba0523b35b745d1fb414eeab7202f7de786ad6a8d8ad3a229f00db78eefe5de43d15a68df5291a681264384733c6bd71dfee53fafdec9f5eace2104d5aa7c34de0eba412fe5b6ad803442a85009f510494f6430645f1ec42a31500979f0fa610f042c4c5af3020472c970cc2a362dcc55afb2bf5fd2418f86a8288714d238df6a166d8a339f2f8e17ea2bbaf8a2e171efc71001256858e48bce7140101e3ebfde0485dd2f3eb22df94528af9fa0be390bb0b7e5c5987088324b3e6ac6f6a93b806e268",
"signType":"RSA2",
"version":"2.0.0",
"encryptType":"AES",
"nonceStr":"5668d6f03c6b4e0c8f3e28acc86473ef",
"ts":"20191024115045"}



----:{"account":"1787670106","trxId":"88988998989444","trxDtTm":"20191024","trxCcyCd":"156","trxAmt":"0.01","payAmt":"0.01","payFee":"0","feeWho":"2","payType":"1501","cardType":"1","trxStatus":"SUCCESS","trxResultMsg":"支付成功","attach":"苹果","ipsTrxId":"BO20191024115016004120","bkTrxId":"2019102442104710419284230202905","ipsTrxDtTm":"20191024115045","thdTrxId":"","extInfo":"thrPayInfo="}




----:苹果
异步回调:{
"merCode":"178767",
"notifyType":"1",
"data":"83b8203f20b6a9aabb79a9c3735ae75f8a3bd1c1b99e8972b4146297ccd2ed17a0948434480fd47f270a41093800b02e6bf426bacd846bc88b4671a89a51af3e8c0bf611d7e744d0b8b293e47aeae983597d02a98f8b90a0c5f9c738906d625c27fd52b39d7bcf05171c960ad535a26569d2579bd1ee6f921395e6258064067298694b8d80269276459cf4703c4c21a22d5fe9803fa7ce38d650cba8131504c0e3e965de980ba8525d452507b735db5f91ec6ac9ffbcd5555d22ddcdfbed1a2e486493de9bac03367857923f6effa9fbffe6d26dde4cdb7e818ab4dd3020c1acab938d42811e81c606ef2f462015f03b89e4f805eb0df182407bc68ed12e5f510785e1c5d324e756ef4c85b4ba63635773782a75d3559ec519e59a4a7814c942b09757c8f6d07d9c21c6bf67c92f13387a481410cc28a6208f3d5e5996fa0195a822abe5c6303e2439a56a4e443a19c72a9f652eb97112c3551a87e38741e5edf36f3fdbdf94222b52be63ad81e075da898700e380e5d44509a7ba59305ec995c8e61c3746fa1b7cd8ba1b3ba72969a9",
"sign":"29f4050533302b29cd5d13e85e89390cdb8bab95d84c77cfe2ee1fcb4c0d5d0948431460afa98e36875a406af212328c79f1c054f5d000ea579b7959e7933cf5e01fca7245bfa1d1ecefe6f30350e25870329a435c4e9828fca71e6f66949e831bee93c1cd6bbc3583a206996dfbb0e1e8bc0f3a78ff94589cc8e8db009e3a597a457b17a74e63a387bbfdb93c3e7624f0cfc313c0a307a7fdba1af7ec199c49fe9c54e811d50ce111de22fa9de86f1ea4c36e8de152cb8d2351fbd97fdb1494e7295b92a285adb1c9716fc8d3d66d45cdcaa98174801ce6bb3267e16a00a05181145e7c58d933e5be0ab880977acba63a7e1ee61cc5b836da92f0e5e363e177",
"signType":"RSA2",
"version":"2.0.0",
"nonceStr":"889df20d9ccd4b3385d7cc139da36f52",
"encryptType":"AES",
"ts":"20191024115045"}

支付回调必须要做域名穿透,大家可是用花生壳或者https://natapp.cn/member/dashborad这两者,花生壳前期可以免费试用,但是得实名认证,域名不会发生改变,natapp可以一直使用但是每次使用的时候分配的域名都不一致

 

说实话,环迅支付文档是我遇到最难搞的了。像个gui一样~~~~~

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章