Devolución de llamada repetida de pago de Wechat, problema de devolución de llamada de pago de Java Wechat

He estado estudiando el problema de las devoluciones de llamada de pago de WeChat en estos días. Descubrí que las devoluciones de llamada de pago de WeChat eran normales antes y no me importaba mucho. Cuando lo probé en mi proyecto hoy, descubrí que el mismo código siempre se ejecutaba repetidamente en mi proyecto. La lógica de devolución de llamada se ha ejecutado después de que el pago es exitoso, lo cual es un dolor de cabeza. Se está ejecutando la lógica de devolución de llamada, lo que indica que la devolución de llamada se ejecuta normalmente

Algunas respuestas dadas en línea:

  WeChat no recibió el mensaje SUCCESS normalmente, lo que sugiere resXml:

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

Modificar a: resXml = "SUCCESS";

 

Algunas personas también reflexionan que este método es factible, pero no he podido implementarlo con éxito.

    Algunas personas dijeron que se modificó para

resXml = "<xml>" + "<return_code> ÉXITO </return_code>" + "<return_msg> Aceptar </return_msg>" + "</xml>";

Algunas personas dijeron que puedo modificarlo o no.

Primero eche un vistazo a mi código de devolución de llamada de pago ( aquí solo se menciona la devolución de llamada de pago de WeChat, porque todos deberíamos estar a través del pago de WeChat, también tengo un artículo sobre el pago de WeChat, haga clic en este enlace )

/**
 * @author SpringRoot
 * @description 微信支付回调
 * @date 2020/3/4-11:17
 */
@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();
        }
    }
}

Los siguientes son los parámetros que se pueden llamar para devoluciones de llamada de pago de WeChat. Usted ve lo que usará su proyecto. Generalmente, puede obtener el número de pedido y operar a través del número de pedido ( haga clic aquí para ver el documento JSAPI de devolución de llamada de pago de WeChat ):

Es decir, lo anterior se puede devolver al valor correspondiente a través de packageParams.get (").

Lo siguiente se modifica después de referirme a un blog, que cumple con mis requisitos: El enlace es el siguiente: 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();
    }

Herramientas utilizadas:

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());
    }
}

 

Supongo que te gusta

Origin blog.csdn.net/baidu_39322753/article/details/104672971
Recomendado
Clasificación