说明
由于没有正式的银联商户号,只能用测试的银联商户号进行测试;
正式的银联商户号需要提交资料给银联审核,并需要支付一笔费用,大概几千块钱吧,以后还要根据你的支付量来抽成。先不管那么多吧,先把测试流程走通,后面切换到正式商户号就问题不大了;
官网链接
搭建测试环境
-
Android 支付客户端:
需要接入银联官方支付SDK,银联官方支付SDK是eclipse版本的,个人感觉不是很友好,所以把它改造成android studio结构的项目,方便调式开发。
官方SDK和DEMO下载地址-eclipse版本
image.png
改造迁移到Android studio版本的DEMO下载地址【代码整理中,稍后提供...】
-
后台银联支付程序
【代码整理中,稍后提供...】
测试流程
第一步:手机支付之前,需要调用获取tn订单流水号:
接口地址:http://qq784602719.imwork.net:43580/Sockets/unionpay/appConsume
![](https://img.haomeiwen.com/i1131704/b5675afe8d6b8486.png)
第二步:手机支付回调接口:
接口地址:http://qq784602719.imwork.net:43580/Sockets/unionpay/backRcvResponse
![](https://img.haomeiwen.com/i1131704/821b3d442e70646c.png)
支付通知回调 【服务器获取银联支付回调,获取订单号orderId和原交易号queryId】
{
"bizType":"000201",
"signPubKeyCert":"-----BEGIN CERTIFICATE-----\r\nMIIEQzCCAyugAwIBAgIFEBJJZVgwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UEBhMC\r\nQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhv\r\ncml0eTEXMBUGA1UEAxMOQ0ZDQSBURVNUIE9DQTEwHhcNMTcxMTAxMDcyNDA4WhcN\r\nMjAxMTAxMDcyNDA4WjB3MQswCQYDVQQGEwJjbjESMBAGA1UEChMJQ0ZDQSBPQ0Ex\r\nMQ4wDAYDVQQLEwVDVVBSQTEUMBIGA1UECxMLRW50ZXJwcmlzZXMxLjAsBgNVBAMU\r\nJTA0MUBaMjAxNy0xMS0xQDAwMDQwMDAwOlNJR05AMDAwMDAwMDEwggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDIWO6AESrg+34HgbU9mSpgef0sl6avr1d\r\nbD/IjjZYM63SoQi3CZHZUyoyzBKodRzowJrwXmd+hCmdcIfavdvfwi6x+ptJNp9d\r\nEtpfEAnJk+4quriQFj1dNiv6uP8ARgn07UMhgdYB7D8aA1j77Yk1ROx7+LFeo7rZ\r\nDdde2U1opPxjIqOPqiPno78JMXpFn7LiGPXu75bwY2rYIGEEImnypgiYuW1vo9UO\r\nG47NMWTnsIdy68FquPSw5FKp5foL825GNX3oJSZui8d2UDkMLBasf06Jz0JKz5AV\r\nblaI+s24/iCfo8r+6WaCs8e6BDkaijJkR/bvRCQeQpbX3V8WoTLVAgMBAAGjgfQw\r\ngfEwHwYDVR0jBBgwFoAUz3CdYeudfC6498sCQPcJnf4zdIAwSAYDVR0gBEEwPzA9\r\nBghggRyG7yoBATAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNu\r\nL3VzL3VzLTE0Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vdWNybC5jZmNh\r\nLmNvbS5jbi9SU0EvY3JsMjQ4NzIuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU\r\nmQQLyuqYjES7qKO+zOkzEbvdFwgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF\r\nBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAujhBuOcuxA+VzoUH84uoFt5aaBM3vGlpW\r\nKVMz6BUsLbIpp1ho5h+LaMnxMs6jdXXDh/du8X5SKMaIddiLw7ujZy1LibKy2jYi\r\nYYfs3tbZ0ffCKQtv78vCgC+IxUUurALY4w58fRLLdu8u8p9jyRFHsQEwSq+W5+bP\r\nMTh2w7cDd9h+6KoCN6AMI1Ly7MxRIhCbNBL9bzaxF9B5GK86ARY7ixkuDCEl4XCF\r\nJGxeoye9R46NqZ6AA/k97mJun//gmUjStmb9PUXA59fR5suAB5o/5lBySZ8UXkrI\r\npp/iLT8vIl1hNgLh0Ghs7DBSx99I+S3VuUzjHNxL6fGRhlix7Rb8\r\n-----END CERTIFICATE-----",
"orderId":"1530258613483",
"txnSubType":"01",
"signature":"A7ejZYsORlSPGcag5Y17dYldv5pI3x+l7JbrWfN2QicuugofW1wgu5IHxBzhwGX0kS2vbIOYI0bkFruNNtKtq4mOwdIEOUR8guUU2rckxRNrRiWYdJazcgUtKv8qS14UvBdzc7vzt8gWSbzAjzJH8eAw+JLm/ABP54XwA96/cIwcS9S+0luHnG+dKBiK30/xaLG9Bc1bZDnawILOltjW+IdkkQiiOKtmKl5nVpEjYgqfe0ZjnzBemqYQbyFmGtB/RjxEyApq6NMfeNoaAv81aLbx3jdwyWK8Exc49ZUykDtShbZw2xRDrSLwBGtXWfJMQRXO170mOH9JE9iIAYsRsA==",
"traceNo":"161203",
"settleAmt":"1",
"settleCurrencyCode":"156",
"settleDate":"0629",
"txnType":"01",
"encoding":"UTF-8",
"version":"5.1.0",
"queryId":"981806291550131612038",
"accessType":"0",
"reqReserved":"reqReserved",
"respMsg":"成功[0000000]",
"traceTime":"0629155013",
"txnTime":"20180629155013",
"merId":"777290058159097",
"currencyCode":"156",
"respCode":"00",
"signMethod":"01",
"txnAmt":"1"
}
根据手机支付成功之后,银联中心对你自己写的后台接口进行回调获得的参数中,我们拿到关键参数:
"orderId":"1530258613483"
进入银联技术开发平台,点击我的测试,我的产品。这里我选择的是手机控件支付测试。其它类型的产品测试类似:
![](https://img.haomeiwen.com/i1131704/d821b75cae3a5947.png)
根据图中测试展示,手机控件支付成功!订单号也显示在这里了。
支付订单退款
退款接口:http://qq784602719.imwork.net:43580/Sockets/unionpay/refund
关键参数:原交易号queryId 和退款金额
请求方式:POST
![](https://img.haomeiwen.com/i1131704/d790102118499a66.png)
"queryId":"981806291550131612038",
根据支付成功回调,我们知道原交易号queryId为:981806291550131612038
![](https://img.haomeiwen.com/i1131704/0c1073f42b808dc6.png)
退款结果:
![](https://img.haomeiwen.com/i1131704/ebc549622798f807.png)
退款回调参数:(退款成功之后,后台回调接口会被银联系统调用)
![](https://img.haomeiwen.com/i1131704/5b63879d1748dcb7.png)
{
"bizType":"000201",
"signPubKeyCert":"-----BEGIN CERTIFICATE-----\r\nMIIEQzCCAyugAwIBAgIFEBJJZVgwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UEBhMC\r\nQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhv\r\ncml0eTEXMBUGA1UEAxMOQ0ZDQSBURVNUIE9DQTEwHhcNMTcxMTAxMDcyNDA4WhcN\r\nMjAxMTAxMDcyNDA4WjB3MQswCQYDVQQGEwJjbjESMBAGA1UEChMJQ0ZDQSBPQ0Ex\r\nMQ4wDAYDVQQLEwVDVVBSQTEUMBIGA1UECxMLRW50ZXJwcmlzZXMxLjAsBgNVBAMU\r\nJTA0MUBaMjAxNy0xMS0xQDAwMDQwMDAwOlNJR05AMDAwMDAwMDEwggEiMA0GCSqG\r\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDIWO6AESrg+34HgbU9mSpgef0sl6avr1d\r\nbD/IjjZYM63SoQi3CZHZUyoyzBKodRzowJrwXmd+hCmdcIfavdvfwi6x+ptJNp9d\r\nEtpfEAnJk+4quriQFj1dNiv6uP8ARgn07UMhgdYB7D8aA1j77Yk1ROx7+LFeo7rZ\r\nDdde2U1opPxjIqOPqiPno78JMXpFn7LiGPXu75bwY2rYIGEEImnypgiYuW1vo9UO\r\nG47NMWTnsIdy68FquPSw5FKp5foL825GNX3oJSZui8d2UDkMLBasf06Jz0JKz5AV\r\nblaI+s24/iCfo8r+6WaCs8e6BDkaijJkR/bvRCQeQpbX3V8WoTLVAgMBAAGjgfQw\r\ngfEwHwYDVR0jBBgwFoAUz3CdYeudfC6498sCQPcJnf4zdIAwSAYDVR0gBEEwPzA9\r\nBghggRyG7yoBATAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNu\r\nL3VzL3VzLTE0Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vdWNybC5jZmNh\r\nLmNvbS5jbi9SU0EvY3JsMjQ4NzIuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU\r\nmQQLyuqYjES7qKO+zOkzEbvdFwgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF\r\nBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAujhBuOcuxA+VzoUH84uoFt5aaBM3vGlpW\r\nKVMz6BUsLbIpp1ho5h+LaMnxMs6jdXXDh/du8X5SKMaIddiLw7ujZy1LibKy2jYi\r\nYYfs3tbZ0ffCKQtv78vCgC+IxUUurALY4w58fRLLdu8u8p9jyRFHsQEwSq+W5+bP\r\nMTh2w7cDd9h+6KoCN6AMI1Ly7MxRIhCbNBL9bzaxF9B5GK86ARY7ixkuDCEl4XCF\r\nJGxeoye9R46NqZ6AA/k97mJun//gmUjStmb9PUXA59fR5suAB5o/5lBySZ8UXkrI\r\npp/iLT8vIl1hNgLh0Ghs7DBSx99I+S3VuUzjHNxL6fGRhlix7Rb8\r\n-----END CERTIFICATE-----",
"orderId":"1530260716679",
"txnSubType":"00",
"signature":"YhjN2h8ZnhmWK4ck/Kb1FtGejeXoHsz1sQbx2Ns4bCa7Y8OYYaF3C4CHLqa4IrpONuHC6KO9dJ1v+QCEIQJ+sr2iwxspByzSmdrETJBNHfdO2CdjWvTUxXEGK9cx9oIjXuPOd9EjnATsMpihlfVA69S/VVS4iqrTJoq/H68sC+ATpDBGuZQKq1RzKtJl7Yd2A1yVBpXtJAK6Odey2GT/n7ZUF4P82OUIXphKz61pxJ0ZInkGamJwwH51FhAJ7MY/crO4VlAR9BFqzTzEURxuaolyGA9+W1ssMcW9cxVyrefPcLGrgEX4pUBlj6STus2IhIgo5deogZ7b1BmIL/1HIg==",
"traceNo":"275003",
"settleAmt":"1",
"settleCurrencyCode":"156",
"settleDate":"0629",
"txnType":"04",
"encoding":"UTF-8",
"version":"5.1.0",
"queryId":"981806291625162750038",
"accessType":"0",
"respMsg":"成功[0000000]",
"traceTime":"0629162516",
"txnTime":"20180629162516",
"merId":"777290058159097",
"origQryId":"981806291550131612038",
"currencyCode":"156",
"respCode":"00",
"signMethod":"01",
"txnAmt":"1"
}
![](https://img.haomeiwen.com/i1131704/6ace1fc1db9f0e8f.png)
到这里我们可以看到退款订单号 跟回调接口中返回参数 中的退款订单号一致,退款测试成功!!!
其它的关于支付的一些测试工作,只要按照银联文档进行,都是类似的情况,关键是看银联支付文档。这里也就不一一测试了。
支付API文档地址:
https://open.unionpay.com/ajweb/help/api
![](https://img.haomeiwen.com/i1131704/3905c73e587c622b.png)
订单交易状态查询:
http://qq784602719.imwork.net:43580/Sockets/unionpay/query
关键参数:订单号和txnTime 交易时间
![](https://img.haomeiwen.com/i1131704/3c1b075cad4efa53.png)
接口代码:
@Controller
@RequestMapping("/unionpay")
public class UnionPayController {
private static final Logger logger = LoggerFactory.getLogger(UnionPayController.class);
private AjaxResult ajax = new AjaxResult();
@RequestMapping("")
@ResponseBody
public String index() {
logger.info("欢迎使用银联支付接口");
return "欢迎使用银联支付接口";
}
/**
* APP支付获取tn
*/
@RequestMapping(value = "/appConsume",method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public AjaxResult appConsume() {
try {
Map<String, String> reqData = UnionPayApiConfig.builder()
.setChannelType("08")//渠道类型 channelType 08是移动
.setMerId("777290058159097")//商户代码 merId 777290058159097
.setTxnAmt("1")//单位为分,不能带小数点,样例:1元送100
.setReqReserved("reqReserved")//请求方自定义域
.setBackUrl(SDKConfig.getConfig().getBackUrl())//后台通知地址
.createMap();
/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
Map<String, String> rspData = UnionPayApi.AppConsumeByMap(reqData);
// 应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》
if (!rspData.isEmpty()) {
if (AcpService.validate(rspData, "UTF-8")) {
logger.info("验证签名成功");
String respCode = rspData.get("respCode");
if (("00").equals(respCode)) {
// 成功,获取tn号
String tn = rspData.get("tn");
ajax.success(tn);
} else {
// 其他应答码为失败请排查原因或做失败处理
ajax.addError(respCode);
}
} else {
logger.error("验证签名失败");
// 检查验证签名失败的原因
ajax.addError("验证签名失败");
}
} else {
// 未返回正确的http状态
logger.error("未获取到返回报文或返回http状态码非200");
ajax.addError("未获取到返回报文或返回http状态码非200");
}
String reqMessage = getHtmlResult(reqData);
String rspMessage = getHtmlResult(rspData);
logger.info("app>reqMessage>>>" + reqMessage + " rspMessage>>>" + rspMessage);
return ajax;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 组装请求,返回报文字符串用于显示
*
* @param data
* @return {String}
*/
public static String getHtmlResult(Map<String, String> data) {
TreeMap<String, String> tree = new TreeMap<String, String>();
Iterator<Entry<String, String>> it = data.entrySet().iterator();
while (it.hasNext()) {
Entry<String, String> en = it.next();
tree.put(en.getKey(), en.getValue());
}
it = tree.entrySet().iterator();
StringBuffer sf = new StringBuffer();
while (it.hasNext()) {
Entry<String, String> en = it.next();
String key = en.getKey();
String value = en.getValue();
if ("respCode".equals(key)) {
sf.append("<b>" + key + "=" + value + "</br></b>");
} else
sf.append(key + "=" + value + "</br>");
}
return sf.toString();
}
/**
* 订单状态查询
* B2C跟B2B查询区别就在于bizType的不同
*/
@RequestMapping(value = "/query",method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public void query(HttpServletResponse response,
@RequestParam("orderId") String orderId,
@RequestParam("txnTime") String txnTime){
try {
Map<String, String> reqData = UnionPayApiConfig.builder()
.setTxnType("00")
.setTxnSubType("00")
.setBizType("000301")
.setMerId("777290058159097")
.setOrderId(orderId)
.setTxnTime(txnTime)
.createMap();
Map<String, String> rspData = UnionPayApi.singleQueryByMap(reqData);
if(!rspData.isEmpty()){
if(AcpService.validate(rspData, "UTF-8")){
logger.info("验证签名成功");
if("00".equals(rspData.get("respCode"))){//如果查询交易成功
//处理被查询交易的应答码逻辑
String origRespCode = rspData.get("origRespCode");
if("00".equals(origRespCode)){
//交易成功,更新商户订单状态
}else if("03".equals(origRespCode) ||
"04".equals(origRespCode) ||
"05".equals(origRespCode)){
//需再次发起交易状态查询交易
}else{
//其他应答码为失败请排查原因
}
}else{//查询交易本身失败,或者未查到原交易,检查查询交易报文要素
}
}else{
logger.error("验证签名失败");
// 检查验证签名失败的原因
}
}else{
//未返回正确的http状态
logger.error("未获取到返回报文或返回http状态码非200");
}
String reqMessage = getHtmlResult(reqData);
String rspMessage = getHtmlResult(rspData);
response.getWriter().println("</br>请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 退款接口
* @param response
* @param origOryId :原始交易订单号
* @param free :退款金额
*/
@RequestMapping(value = "/refund",method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public void refund(HttpServletResponse response,
@RequestParam("origOryId") String origOryId,
@RequestParam("free") String free){
try {
Map<String, String> reqData = UnionPayApiConfig.builder()
.setTxnType("04") //交易类型 04-退货 31-消费撤销
.setTxnSubType("00") //交易子类型 默认00
.setBizType("000201") //业务类型 B2C网关支付,手机wap支付
.setChannelType("08") //渠道类型,07-PC,08-手机
.setMerId("777290058159097")//商户号
.setOrderId(String.valueOf(System.currentTimeMillis()))//商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则,重新产生,不同于原消费
.setTxnTime(DateKit.toStr(new Date(), DateKit.UnionTimeStampPattern))//订单发送时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效
.setTxnAmt(free)
.setBackUrl(SDKConfig.getConfig().getBackUrl())
.setOrigQryId(origOryId) //****原消费交易返回的的queryId,可以从消费交易后台通知接口中或者交易状态查询接口中获取
.createMap();
Map<String, String> rspData = UnionPayApi.backRequestByMap(reqData);
if(!rspData.isEmpty()){
if(AcpService.validate(rspData, "UTF-8")){
logger.info("验证签名成功");
String respCode = rspData.get("respCode");
if("00".equals(respCode)){
//交易已受理,等待接收后台通知更新订单状态,也可以主动发起 查询交易确定交易状态。
}else if("03".equals(respCode)||
"04".equals(respCode)||
"05".equals(respCode)){
//后续需发起交易状态查询交易确定交易状态
}else{
//其他应答码为失败请排查原因
}
}else{
logger.error("验证签名失败");
// 检查验证签名失败的原因
}
}else{
//未返回正确的http状态
logger.error("未获取到返回报文或返回http状态码非200");
}
String reqMessage = getHtmlResult(reqData);
String rspMessage = getHtmlResult(rspData);
response.getWriter().println("</br>请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 后台回调
*/
@RequestMapping(value = "/backRcvResponse",method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public String backRcvResponse(HttpServletRequest request) {
logger.info("BackRcvResponse接收后台通知开始");
String encoding = "UTF-8";
//String notifyStr = HttpKit.readData(request);
//System.out.println("返回参数 str:"+notifyStr);
// 获取银联通知服务器发送的后台通知参数
//Map<String, String> reqParam = getAllRequestParamToMap(notifyStr);
Map<String, String> reqParam = getAllRequestParam(request);
System.out.println("返回参数 map:"+JSON.toJSONString(reqParam));
// 重要!验证签名前不要修改reqParam中的键值对的内容,否则会验签不过
if (!AcpService.validate(reqParam, encoding)) {
logger.info("后台验证签名结果[失败].");
// 验签失败,需解决验签问题
} else {
logger.info("后台验证签名结果[成功].");
// 【注:为了安全验签成功才应该写商户的成功处理逻辑】交易成功,更新商户订单状态
String orderId = reqParam.get("orderId"); // 获取后台通知的数据,其他字段也可用类似方式获取
String respCode = reqParam.get("respCode");
// 判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。
logger.info("orderId>>>" + orderId + " respCode>>" + respCode);
}
logger.info("BackRcvResponse接收后台通知结束");
// 返回给银联服务器http 200 状态码
return "ok";
}
/**
* 前台回调
*/
@RequestMapping(value = "/frontRcvResponse",method={RequestMethod.POST,RequestMethod.GET})
public String frontRcvResponse(HttpServletRequest request,HttpServletResponse response) {
try {
logger.info("FrontRcvResponse前台接收报文返回开始");
String encoding = "UTF-8";
logger.info("返回报文中encoding=[" + encoding + "]");
String readData = HttpKit.readData(request);
Map<String, String> respParam = getAllRequestParamToMap(readData);
// 打印请求报文
LogUtil.printRequestLog(respParam);
Map<String, String> valideData = null;
StringBuffer page = new StringBuffer();
if (null != respParam && !respParam.isEmpty()) {
Iterator<Entry<String, String>> it = respParam.entrySet().iterator();
valideData = new HashMap<String, String>(respParam.size());
while (it.hasNext()) {
Entry<String, String> e = it.next();
String key = (String) e.getKey();
String value = (String) e.getValue();
value = new String(value.getBytes(encoding), encoding);
page.append("<tr><td width=\"30%\" align=\"right\">" + key + "(" + key + ")</td><td>" + value
+ "</td></tr>");
valideData.put(key, value);
}
}
if (!AcpService.validate(valideData, encoding)) {
page.append("<tr><td width=\"30%\" align=\"right\">前台验证签名结果</td><td>失败</td></tr>");
logger.info("前台验证签名结果[失败].");
} else {
page.append("<tr><td width=\"30%\" align=\"right\">前台验证签名结果</td><td>成功</td></tr>");
logger.info("前台验证签名结果[成功].");
String orderId = valideData.get("orderId"); // 其他字段也可用类似方式获取
String respCode = valideData.get("respCode");
// 判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。
logger.info("orderId>>>" + orderId + " respCode>>" + respCode);
}
request.setAttribute("result", page.toString());
logger.info("FrontRcvResponse前台接收报文返回结束");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "utf8_result.html";
}
/**
* 获取请求参数中所有的信息
*
* @param request
* @return
*/
public static Map<String, String> getAllRequestParam(final HttpServletRequest request) {
Map<String, String> res = new HashMap<String, String>();
Enumeration<?> temp = request.getParameterNames();
if (null != temp) {
while (temp.hasMoreElements()) {
String en = (String) temp.nextElement();
String value = request.getParameter(en);
res.put(en, value);
//在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>
//System.out.println("ServletUtil类247行 temp数据的键=="+en+" 值==="+value);
if (null == res.get(en) || "".equals(res.get(en))) {
res.remove(en);
}
}
}
return res;
}
/**
* 将回调参数转为Map
*
* @param notifyStr
* @return {Map<String, String>}
*/
public static Map<String, String> getAllRequestParamToMap(final String notifyStr) {
Map<String, String> res = new HashMap<String, String>();
try {
logger.info("收到通知报文:" + notifyStr);
String[] kvs = notifyStr.split("&");
for (String kv : kvs) {
String[] tmp = kv.split("=");
if (tmp.length >= 2) {
String key = tmp[0];
String value = URLDecoder.decode(tmp[1], "UTF-8");
res.put(key, value);
}
}
} catch (UnsupportedEncodingException e) {
logger.info("getAllRequestParamStream.UnsupportedEncodingException error: " + e.getClass() + ":"
+ e.getMessage());
}
return res;
}
}
网友评论