这几天一直在研究微信支付回调这个问题,发现之前微信支付回调都是正常的也没怎么在意,今天在自己项目上测试的时候发现相同的代码在我这个项目上微信支付回调老是重复执行导致支付成功之后的回调逻辑一直在执行,很头疼。回调逻辑都在执行,说明回调正常执行

网上有些给的答案:

  微信没有正常接收到SUCCESS消息建议将resXml:

resXml ="<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";

修改为:resXml = "SUCCESS";

也有人反映这个方法可行,但是我自己这边没能执行成功。

也有部分人说修改成

resXml ="<xml>" + "<return_code>SUCCESS</return_code>"+ "<return_msg>OK</return_msg>" + "</xml> ";

同样部分人说可以 我修改了还是不行。

首先看下我的支付回调代码(这边只说微信支付回调,因为到这里应该都是微信支付通了的吧,我也有一篇是写微信支付的,点击这个链接)

/**
* @author Mr.Lin
* @description 微信支付回调
* @date 2019/7/5
*/
@Service
public class WeiXinPayNotifyServiceImpl implements WeiXinPayNotifyService {
private final static Logger LOGGER = LoggerFactory.getLogger(WeiXinPayNotifyServiceImpl.class); @Override
public void weixinpay_notify(HttpServletRequest request,
HttpServletResponse response) {
    /**
  这些是通过微信支付,返回可以得到一些值 具体如下截图 这个代码可以不用管 下面会继续给出成功且不重复回调的代码    这边的支付都是JSAPA支付
     */
InputStream inputStream;
StringBuffer sb = new StringBuffer();
try {
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(
inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
Map<String, String> m = new HashMap<String, String>();
m = WXUtil.doXMLParse(sb.toString());
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
Iterator it = m.keySet().iterator();
while (it.hasNext()) {
String parameter = (String) it.next();
String parameterValue = m.get(parameter);
String v = "";
if (null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}
String key = WxPayPojo.MCH_KEY; // 秘钥 这个就是你的微信商户平台的秘钥
if (WXUtil.isTenpaySign("UTF-8", packageParams, key)) {
String resXml = "";
if ("SUCCESS".equals((String) packageParams.get("result_code"))) { // 得到返回的参数
String openid = (String) packageParams.get("openid");
String transaction_id = (String) packageParams
.get("transaction_id");
String orderNumberMain = (String) packageParams
.get("out_trade_no");
// 这里可以写你需要的业务
LOGGER.debug("我是回调函数啊!---我执行了---------------------");
LOGGER.debug("openid---->" + openid);
LOGGER.debug("transaction_id---->" + transaction_id);
LOGGER.debug("out_trade_no---->" + orderNumberMain);
resXml =
"<xml>"
+ "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>"
+ "</xml> ";
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
return;
} else {
LOGGER.debug("回调失败");
}
} else {
LOGGER.debug("回调失败");
}
} catch (IOException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
}
}
}

下面是微信支付回调可以调用的参数,你看你项目会用到什么,一般来说获取到订单编号  通过订单编号操作(点击这里查看微信支付回调JSAPI文档):

即上面的都可以通过packageParams.get(")  对应的到返回值。

下面是我参考一个博客之后修改的,符合我的这个要求:链接如下:https://blog.csdn.net/qq_37105358/article/details/81285779

/**
* 微信小程序支付成功回调函数
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value = "/weixinpay/notify")
public void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while((line = br.readLine()) != null){
sb.append(line);
}
br.close();
//sb为微信返回的xml
String notityXml = sb.toString();
String resXml = "";
System.out.println("接收到的报文:" + notityXml); Map map = PayUtil.doXMLParse(notityXml); String returnCode = (String) map.get("return_code");
if("SUCCESS".equals(returnCode)){
//验证签名是否正确
Map<String, String> validParams = PayUtil.paraFilter(map); //回调验签时需要去除sign和空值参数
String validStr = PayUtil.createLinkString(validParams);//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
String sign = PayUtil.sign(validStr, WxPayPojo.MCH_KEY, "utf-8").toUpperCase();//拼装生成服务器端验证的签名
// 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了 //根据微信官网的介绍,此处不仅对回调的参数进行验签,还需要对返回的金额与系统订单的金额进行比对等
if(sign.equals(map.get("sign"))){
// 得到返回的参数
          //这边我上面也说过了 同理 需要什么参数 直接通过map.get获取 参数列表我上面也列举了
String openid = (String) map.get("openid");
String transaction_id = (String) map.get("transaction_id");
String orderNumberMain = (String) map.get("out_trade_no"); /**回调逻辑代码编写*/
//通知微信服务器已经支付成功
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
System.out.println("微信支付回调失败!签名不一致");
}
}else{
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
System.out.println(resXml);
System.out.println("微信支付回调数据结束"); BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}

用到的工具类:

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map; import org.apache.commons.codec.digest.DigestUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder; public class PayUtil {
/**
*      * 签名字符串
*      * @param text 需要签名的字符串
*      * @param key 密钥
*      * @param input_charset 编码格式
*      * @return 签名结果
*      
*/
public static String sign(String text, String key, String input_charset) {
text = text + "&key=" + key;
return DigestUtils.md5Hex(getContentBytes(text, input_charset));
} /**
*      * 签名字符串
*      *  @param text 需要签名的字符串
*      * @param sign 签名结果
*      * @param key 密钥
*      * @param input_charset 编码格式
*      * @return 签名结果
*      
*/
public static boolean verify(String text, String sign, String key, String input_charset) {
text = text + key;
String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
if (mysign.equals(sign)) {
return true;
} else {
return false;
}
} /**
*      * @param content
*      * @param charset
*      * @return
*      * @throws SignatureException
*      * @throws UnsupportedEncodingException
*      
*/
public static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
} private static boolean isValidChar(char ch) {
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
return true;
if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))
return true;// 简体中文汉字编码
return false;
} /**
*      * 除去数组中的空值和签名参数
*      * @param sArray 签名参数组
*      * @return 去掉空值与签名参数后的新签名参数组
*      
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<String, String>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
} /**
*      * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
*      * @param params 需要排序并参与字符拼接的参数组
*      * @return 拼接后字符串
*      
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
} /**
*      *
*      * @param requestUrl 请求地址
*      * @param requestMethod 请求方法
*      * @param outputStr 参数
*      
*/
public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
// 创建SSLContext
StringBuffer buffer = null;
try {
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(requestMethod);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
//往服务器端写内容
if (null != outputStr) {
OutputStream os = conn.getOutputStream();
os.write(outputStr.getBytes("utf-8"));
os.close();
}
// 读取服务器端返回的内容
InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "utf-8");
BufferedReader br = new BufferedReader(isr);
buffer = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
buffer.append(line);
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return buffer.toString();
} public static String urlEncodeUTF8(String source) {
String result = source;
try {
result = java.net.URLEncoder.encode(source, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
} /**
*      * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
*      * @param strxml
*      * @return
*      * @throws JDOMException
*      * @throws IOException
*      
*/
public static Map doXMLParse(String strxml) throws Exception {
if (null == strxml || "".equals(strxml)) {
return null;
} Map m = new HashMap();
InputStream in = String2Inputstream(strxml);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if (children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
} m.put(k, v);
} //关闭流
in.close(); return m;
} /**
*      * 获取子结点的xml
*      * @param children
*      * @return String
*      
*/
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if (!children.isEmpty()) {
Iterator it = children.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if (!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
} return sb.toString();
} public static InputStream String2Inputstream(String str) {
return new ByteArrayInputStream(str.getBytes());
}
}

回调的链接  你微信支付的时候 应该也有写到的    就跟前端正常调用接口一样  比如:https://www.cnblogs.com/ 这个是你项目的域名   这个你项目名称lxwt

回调链接就是:https://www.cnblogs.com/lxwt/weixinpay/notify    就可以了

我跟他这个代码对比下发现其实都是差不多的   一个意思   就是不清楚为啥会重复回调  可能是我的工具类解析的问题吧    下面这个我测试过了  不会出现重复回调了

有更好的方法请留言  谢谢!

 


微信支付重复回调,java微信支付回调问题的更多相关文章

  1. 【Java EE 学习 21 下】【 使用易宝支付接口实现java网上支付功能】

    一.网上支付分为两种情况,一种方法是使用直接和银行的支付接口,另外一种方法是使用第三方支付平台和银行对接完成支付. 1.直接和银行对接. 2.使用第三方支付平台 3.常见的第三方支付平台 二.使用易宝 ...

  2. Java微信公众平台开发_02_启用服务器配置

    源码将在晚上上传到 github 一.准备阶段 需要准备事项: 1.一个能在公网上访问的项目: 见:[  Java微信公众平台开发_01_本地服务器映射外网  ] 2.一个微信公众平台账号: 去注册: ...

  3. Java微信公众平台开发_03_消息管理之被动回复消息

    GitHub源码:https://github.com/shirayner/weixin_gz 一.本节要点 1.回调url 上一节,我们启用服务器配置的时候,填写了一个服务器地址(url),如下图, ...

  4. Java+微信支付(下预购单+回调+退款+查询账单)

    前言: 现在的APP的离不开微信支付, 现在项目里接入微信支付 , 微信支付的官方文档是:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chap ...

  5. 【微信支付】公众号、商户基础配置和流程(包括设置支付授权目录、测试支付目录和白名单、JS接口安全域名、授权回调域名等)

    一.使用场景以及说明 使用场景:商户已有H5商城网站,用户通过消息或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买的流程. 说明:1.用户打开图文消息或者扫描二维码,在微信内置浏览器打开网 ...

  6. 微信H5支付时用户有微信分身停留5秒后未选择哪个微信分身,也未支付就被动回调到商户支付是否完成的页面

    微信H5支付时用户有微信分身停留5秒后未选择哪个微信分身,也未支付就被动回调到商户支付是否完成的页面 微信支付中间页调起微信收银台后超过5秒 安卓H5支付设置了redirect_url后调起微信收银台 ...

  7. TP5调用小程序微信支付,回调,在待支付中再次调用微信支付

    1,必须要有 $mch_id $key $appid这三个值,是需要去申请的,我是直接用公司的2,购买商品订单号用户openid统一下单名称商品价格(必须以分为单位,调起微信支付)服务器的ip地址(没 ...

  8. 微信扫码支付Native方式二以及支付回调

    官方API文档https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5 1.使用jar包 1 <!--微信支付 --> 2 ...

  9. JAVA微信支付代码(WeChatPay.java 才是调用类)

    微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/index.html MD5Util.java package weixin; import java.se ...

  10. java微信公众号JSAPI支付以及所遇到的坑

    上周做了个支付宝微信扫码支付,今天总结一下.微信相比支付宝要麻烦许多 由于涉及到代理商,没办法,让我写个详细的申请流程,懵逼啊. 笔记地址 http://note.youdao.com/notesha ...

随机推荐

  1. JDK10下安装Eclipse photon 提示Java for Windows Missing

    这两天把服务器清理了一下,操作系统也重新装了,没办法啊,就是喜欢倒腾...在重新安装软件的时候,我又到各个官网去看了软件的最新版本,其中就去了JDK和Eclipse的官网溜达了一圈. 很久没有更新过自 ...

  2. Lizcst Software Lab新秀品牌上线!

    科友微电机是Lizcst Software Lab旗下品牌新秀,专业经营各种微型特种直流电机.微型发电机.微型电机配件.航模车模船模素材.教学科学小制作材料的网店.本店秉承Lizcst Softwar ...

  3. Binding的三种方式

    1 Text="{Binding Name}" Name为后台的属性 2 Text="{Binding ElementName=XXX,Path=A.B.C.D….}&q ...

  4. centos7 防火墙问题

    centos从7开始默认用的是firewalld,这个是基于iptables的,虽然有iptables的核心,但是iptables的服务是没安装的.所以你只要停止firewalld服务即可:sudo ...

  5. 在 __CC_ARM 编译器环境下,使用$Sub$$ 与 $Super$$ 的“补丁”功能

    $Sub$$ 与 $Super$$ 的“补丁”功能(详见 ARM® Compiler v5.06 for µVision® armlink User Guide): 这是一种特殊模式:用于有一个已经存 ...

  6. SQL Server 2017 SELECT…INTO 创建的新表指定到文件组

    原文:SQL Server 2017 SELECT-INTO 创建的新表指定到文件组 SELECT-INTO 在 SQL Server 中也是常见的一个功能,过去用此方法创建的新表只能存储到默认的文件 ...

  7. Setting up multi nodes live migration in Openstack Juno with devstack

    Setting up multi nodes live migration in Openstack Juno with devstack Summary Live migration overvie ...

  8. Qt编译和使用boost库(附QT5.51的Boost下载)good

    配置gcc可以在cmd中使用 添加MinGW到环境变量 安装过Qt的都已经默认安装过MinGw的环境了,只需要找到配置一下环境变量就行 我的在D:\Qt5.5.1\Tools\mingw492_32\ ...

  9. 查看SharePoint文档库是,显示层次目录,可以点击返回层次

    在sharepoint 2013中,Documnet library(文档库)包含多层文件夹,当进入到文件夹后,返回指定层次了(例如返回上一层),需要用浏览器的返回. 使用起来不方便,而且浏览器的返回 ...

  10. VCL比MFC好在哪里

    作者:刘国华链接:https://www.zhihu.com/question/35218485/answer/118472021来源:知乎著作权归作者所有,转载请联系作者获得授权. 从使用感受而言, ...