Wechat payment repeated callback, java Wechat payment callback problem

I have been studying the issue of WeChat payment callbacks these days. I found that the WeChat payment callbacks were normal before and I didn’t care much. When I tested it on my project today, I found that the same code was always executed repeatedly on my project. The callback logic has been executed after the payment is successful, which is a headache. The callback logic is being executed, indicating that the callback is executed normally

Some answers given online:

  WeChat did not receive the SUCCESS message normally, suggesting resXml:

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

Amend to: resXml = "SUCCESS";

 

Some people also reflect that this method is feasible, but I have not been able to implement it successfully.

    Some people said it was modified to

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

Some people said that I can modify it or not.

First take a look at my payment callback code ( here only WeChat payment callback is mentioned, because we should all be through WeChat payment, I also have an article about WeChat payment, click this link )

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

The following are the parameters that can be called for WeChat payment callbacks. You see what your project will use. Generally, you can get the order number and operate through the order number ( click here to view the WeChat payment callback JSAPI document ):

That is, the above can be returned to the corresponding value through packageParams.get(").

The following is modified after I refer to a blog, which meets my requirements: The link is as follows: 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();
    }

Tools used:

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

 

Guess you like

Origin blog.csdn.net/baidu_39322753/article/details/104672971