1.微信支付回调地址的设置,在我上一篇H5调起微信支付中已经介绍过了。
地址:https://blog.csdn.net/qq_38669394/article/details/106637751
2.微信支付回调是本地服务提供接口,微信调用本地服务的接口,我们接收微信传过来的支付结果。
3.注意事项,微信访问我们是以xml格式,这里我多微信传过来的xml格式转为map,然后进入service层进行处理
xml转map工具类,后面我会给出来
/**
* 3-微信异步通知 (签约支付)
*/
@RequestMapping(value = "/wxPayNotify", produces = {"application/xml;charset=UTF-8"})
public void wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {
try {
StringBuilder sb = new StringBuilder();
BufferedReader in = request.getReader();
String line;
while ((line = in.readLine()) != null) {
sb.append(line);
}
in.close();
log.info("==== wxPayNotify,servletPath :请求参数 xml:",sb.toString());
String xml = sb.toString();
Map<String,String> map = PayCommonUtil.readStringXmlToMap(xml);
wxPayService.wxPayNotify(map,response);
} catch (Exception ex) {
log.error(ex.toString());
log.error("微信回调接口失败--------");
}
}
4.对微信访问参数进行验签,验签成功后 处理业务逻辑 ,验签工具类后面给出来
@Override
public void wxPayNotify(Map<String, String> map, HttpServletResponse response) {
for (Object keyValue : map.keySet()) {
System.out.println(keyValue + "=" + map.get(keyValue));
}
//过滤空 设置 TreeMap
SortedMap<Object, Object> sortMap = new TreeMap<Object, Object>();
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
String parameter = (String) it.next();
String parameterValue = map.get(parameter);
String v = "";
if (null != parameterValue) {
v = parameterValue.trim();
}
sortMap.put(parameter, v);
}
//判断签名是否正确
String resXml = "";
if (PayCommonUtil.isTenpaySign("UTF-8", sortMap)) { //true的话这里标识验签通过
log.info("回显参数"+sortMap);
log.info("微信支付回调验签成功");
if ("SUCCESS".equals((String) sortMap.get("result_code"))) {
// 这里是支付成功
//执行自己的业务逻辑
String appid = (String) sortMap.get("appid");//appid
String sign = (String) sortMap.get("sign");//签名
String total_fee = (String) sortMap.get("total_fee");//总金额
String mch_id = (String) sortMap.get("mch_id"); //商户号
String openid = (String) sortMap.get("openid"); //用户标识
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
log.info("支付失败,错误信息:" + sortMap.get("err_code"));
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
} else {
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[通知签名验证失败]]></return_msg>" + "</xml> ";
log.info("通知签名验证失败");
}
//处理业务完毕
BufferedOutputStream out;
try {
out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log.error("微信回调接口成功--------");
}
5.工具类
package com.newland.common.utils;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import com.tencent.common.Configure;
/**
* 微信支付成功回调工具类
* 服务号相关信息
*/
public class PayCommonUtil {
/**
* 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
*
* @return boolean
*/
public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams) {
StringBuffer sb = new StringBuffer();
Set es = packageParams.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if (!"sign".equals(k) && null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + Configure.getKey()); //需要注意这里的KEY是微信的配置key
//算出摘要
String mysign = EncodeUtils.encodeMD5(sb.toString(), characterEncoding).toLowerCase();
String tenpaySign = ((String) packageParams.get("sign")).toLowerCase();
//System.out.println(tenpaySign + " " + mysign);
return tenpaySign.equals(mysign);
}
public static Map<String,String> readStringXmlToMap(String xml) {
Map<String,String> map = new HashMap<String,String>();
Document doc = null;
try {
doc = DocumentHelper.parseText(xml); // 将字符串转为XML
Element rootElt = doc.getRootElement(); // 获取根节点
List<Element> list = rootElt.elements();//获取根节点下所有节点
for (Element element : list) { //遍历节点
map.put(element.getName(), element.getText()); //节点的name为map的key,text为map的value
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
}