微信支付生成二维码

  1. 一、准备开发所需的账号以及配置信息前往https://mp.weixin.qq.com/ (微信公众平台)注册一个应用,类型只能是:公众号/小程序/企业微信,订阅号不支持微信支付接口,注册完成需要完成”微信认证“

  2. 前往:https://pay.weixin.qq.com(微信支付商户平台)注册一个商户,支付成功后的钱就会在这个账号里面

  3. 上面两个平台注册完成之后就需要把配置信息拿到了:1、APPID:应用id也就是 公众号/小程序的ID  2、key: 应用密钥。mch_Id:商户ID (收钱的商家ID)   

  4. 然后就进入我们的开发过程,在Maven中创建一个Spring Boot项目,添加所需的依赖(例如zxing等二维码生成库)。

  5. <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.4.0</version>
    </dependency>
     
    
  6. 在resources/static目录下创建index.html页面,添加生成二维码的表单,让用户输入订单金额等信息,并提交生成二维码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>微信支付</title>
</head>
<body>
    <form action="" method="post" id="form">
        <label for="totalFee">订单金额:</label>
        <input type="number" id="totalFee" name="totalFee" min="0.01" step="0.01" required>
        <button type="submit">生成二维码</button>
    </form>
    <div id="qrcode"></div>
    <script type="text/javascript">
        var form = document.getElementById("form");
        form.addEventListener("submit", function(e) {
            e.preventDefault();
            var xhr = new XMLHttpRequest();
            xhr.open("get", "generateQRCode?totalFee=" + document.getElementById("totalFee").value);
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) {
                        var response = JSON.parse(xhr.responseText);
                        document.getElementById("qrcode").innerHTML = "<img src=\"" + response.qrcodeUrl + "\" alt=\"\">";
                    } else {
                        alert("生成二维码失败");
                    }
                }
            };
            xhr.send();
        });
    </script>
</body>
</html>
  1. 创建PaymentController类,处理用户提交的表单,生成二维码图片,并将付款链接和二维码图片发送到页面:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestParam;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

@RestController
public class PaymentController {
    private static final String APP_ID = "xxxx"; // 公众账号ID
    private static final String MCH_ID = "xxxx"; // 商户号
    private static final String NOTIFY_URL = "http://xxxx.com/notify"; // 异步通知地址
    private static final String KEY = "xxxx"; // 商户支付密钥
    private static final String UNIFIEDORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 统一下单接口地址

    @GetMapping("/")
    public String index() {
        return "index";
    }

    @GetMapping("/generateQRCode")
    public Map<String, String> generateQRCode(@RequestParam("totalFee") String totalFee) throws Exception {
        String outTradeNo = "order" + System.currentTimeMillis(); // 商户订单号,可根据实际情况生成
        String nonceStr = getRandomString();
        String body = "购买商品";
        String spbillCreateIp = "127.0.0.1"; // 客户端IP,可自行修改
        String tradeType = "NATIVE";
        String productId = "product" + System.currentTimeMillis(); // 商品ID,可根据实际情况生成
        String attach = "附加数据";
        String sign = getSign(APP_ID, MCH_ID, nonceStr, body, attach, outTradeNo, totalFee, spbillCreateIp, NOTIFY_URL, tradeType,
                productId, KEY);
        String xml = getXml(APP_ID, MCH_ID, nonceStr, body, attach, outTradeNo, totalFee, spbillCreateIp, NOTIFY_URL,
                tradeType, productId, sign);
        String responseXml = doPost(UNIFIEDORDER_URL, xml);
        String prepayId = getPrepayId(responseXml);
        if (prepayId == null) { // 如果预支付交易会话标识prepay_id为空,则失败
            Map<String, String> map = new HashMap<>();
            map.put("qrcodeUrl", "");
            map.put("codeUrl", "");
            return map;
        }
        String codeUrl = getCodeUrl(prepayId);
        String qrcodeUrl = generateQRCode(codeUrl); // 生成二维码图片,并返回图片的URL

        Map<String, String> map = new HashMap<>();
        map.put("qrcodeUrl", qrcodeUrl);
        map.put("codeUrl", codeUrl);
        return map;
    }

    private String getSign(String appId, String mchId, String nonceStr, String body, String attach, String outTradeNo,
            String totalFee, String spbillCreateIp, String notifyUrl, String tradeType, String productId, String key) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("appid", appId);
        params.put("mch_id", mchId);
        params.put("nonce_str", nonceStr);
        params.put("body", body);
        params.put("attach", attach);
        params.put("out_trade_no", outTradeNo);
        params.put("total_fee", totalFee);
        params.put("spbill_create_ip", spbillCreateIp);
        params.put("notify_url", notifyUrl);
        params.put("trade_type", tradeType);
        params.put("product_id", productId);
        String sign = getSign(params, key);
        return sign;
    }

    private String getSign(Map<String, String> params, String key) {
        StringBuilder sb = new StringBuilder();
        for (String k : params.keySet()) {
            if ("sign".equals(k)) {
                continue;
            }
            String v = params.get(k);
            if (v != null && v.length() > 0) {
                sb.append(k).append("=").append(v).append("&");
            }
        }
        sb.append("key=").append(key);
        String sign = md5(sb.toString()).toUpperCase();
        return sign;
    }

    private String getXml(String appId, String mchId, String nonceStr, String body, String attach, String outTradeNo,
            String totalFee, String spbillCreateIp, String notifyUrl, String tradeType, String productId, String sign) {
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        sb.append("<appid>").append(appId).append("</appid>");
        sb.append("<mch_id>").append(mchId).append("</mch_id>");
        sb.append("<nonce_str>").append(nonceStr).append("</nonce_str>");
        sb.append("<body><![CDATA[").append(body).append("]]></body>");
        sb.append("<attach>").append(attach).append("</attach>");
        sb.append("<out_trade_no>").append(outTradeNo).append("</out_trade_no>");
        sb.append("<total_fee>").append(totalFee).append("</total_fee>");
        sb.append("<spbill_create_ip>").append(spbillCreateIp).append("</spbill_create_ip>");
        sb.append("<notify_url>").append(notifyUrl).append("</notify_url>");
        sb.append("<trade_type>").append(tradeType).append("</trade_type>");
        sb.append("<product_id>").append(productId).append("</product_id>");
        sb.append("<sign>").append(sign).append("</sign>");
        sb.append("</xml>");
        return sb.toString();
    }

    private String getPrepayId(String xml) {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            InputStream is = org.apache.commons.io.IOUtils.toInputStream(xml, "UTF-8");;
            Document doc = db.parse(is);
            NodeList nodeList = doc.getElementsByTagName("prepay_id");
            Node node = nodeList.item(0);
            if (node == null) {
                return null;
            }
            return node.getTextContent();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private String getCodeUrl(String prepayId) {
        if (prepayId == null || prepayId.length() == 0) {
            return null;
        }
        String codeUrl = "weixin://wxpay/bizpayurl?pr=" + prepayId;
        return codeUrl;
    }

    private String generateQRCode(String text) throws IOException, WriterException {
        int width = 300;
        int height = 300;
        QRCodeWriter writer = new QRCodeWriter();
        BitMatrix matrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        com.google.zxing.client.j2se.MatrixToImageWriter.writeToStream(matrix, "png", os);
        byte[] bytes = os.toByteArray();
        os.close();
        String qrcodeUrl = "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes);
        return qrcodeUrl;
    }

    

private String getRandomString()方法,用于生成随机字符串:

    private String getRandomString() {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 32; i++) {
            int index = random.nextInt(str.length());
            sb.append(str.charAt(index));
        }
        return sb.toString();
    }

  1. 创建NotifyController类,处理微信支付异步通知:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class NotifyController {
    private static final String KEY = "xxxx"; // 商户支付密钥

    @PostMapping("/notify")
    public String notify(HttpServletRequest request) throws Exception {
        // 读取请求内容
        InputStream inputStream = request.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        reader.close();
        inputStream.close();
        String xml = sb.toString();

        // 验证签名
        Map<String, String> params = new HashMap<String, String>();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
        Document doc = db.parse(is);
        NodeList nodeList = doc.getFirstChild().getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                String key = node.getNodeName();
                String value = node.getTextContent();
                params.put(key, value);
            }
        }
        String sign = getSign(params, KEY);
        String signFromXml = params.get("sign");
        if (!sign.equals(signFromXml)) {
            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名错误]]></return_msg></xml>";
        }

        // 处理异步通知
        String outTradeNo = params.get("out_trade_no");
        String totalFee = params.get("total_fee");
        // 处理订单逻辑

        return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    }

    private String getSign(Map<String, String> params, String key) {
        StringBuilder sb = new StringBuilder();
        for (String k : params.keySet()) {
            if ("sign".equals(k)) {
                continue;
            }
            String v = params.get(k);
            if (v != null && v.length() > 0) {
                sb.append(k).append("=").append(v).append("&");
            }
        }
        sb.append("key=").append(key);
        String sign = md5(sb.toString()).toUpperCase();
        return sign;
    }

    private String md5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] b = md.digest(str.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder(32);
            for (byte by : b) {
                sb.append(String.format("%02X", by & 0xFF));
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
  1. 运行Spring Boot项目,在浏览器中访问http://localhost:8080,输入订单金额后,点击"生成二维码"按钮即可生成微信付款二维码。

以上就是一个简单的二维码微信付款的Spring Boot Maven项目实现。注意,本示例中仅仅处理了生成预订单并生成二维码的流程,真实应用中还需要处理用户实际支付成功后的异步通知并完成订单逻辑。

 

<think>嗯,用户想了解如何通过API生成微信支付二维码的相关信息,需要接口文档教程和示例代码。首先,我得回忆一下微信支付的流程。微信支付涉及到几个步骤,比如统一下单、获取prepay_id,然后生成支付二维码。不过用户特别提到的是生成二维码的API,所以可能需要直接查看微信支付的相关接口。 根据用户提供的引用内容,引用[2]提到了JAVA微信支付接口开发,其中涉及业务流程和调用接口的参数拼装与验签。这可能和生成支付二维码有关。另外,引用[3]中的微信小程序生成二维码接口,虽然标题是微信小程序,但接口URL是https://api.weixin.qq.com/shop/funds/qrcode/get,这个可能需要access_token和qrcode_ticket。不过不确定这个接口是否属于微信支付的一部分,还是其他业务。 用户的问题可能涉及两个部分:一是微信支付本身的统一下单接口,生成预支付订单并返回二维码数据;二是生成二维码图片的具体方法。微信支付通常的流程是,商户系统调用统一下单接口,微信返回支付参数,然后商户生成二维码让用户扫码支付。例如,生成的是类似“weixin://wxpay/bizpayurl?pr=XXXXXX”这样的URL,然后将其转换成二维码图片。 所以步骤应该是:1. 获取access_token;2. 调用统一下单接口获取支付链接;3. 将链接生成二维码图片。需要确认用户是否已经完成统一下单的部分,或者需要整个流程的说明。 引用[3]中的接口可能需要特定的权限或场景,比如小商店资金二维码,可能和普通微信支付不同。因此,正确的接口应该是微信支付的统一下单接口,生成预支付交易单,然后根据返回的code_url生成二维码。例如,统一下单接口返回的code_url就是支付二维码的链接,商户需要将这个链接转换为二维码图片。 示例代码方面,引用[2]提到JAVA的示例,可能涉及到参数签名和HTTP请求。用户可能需要具体的代码示例,比如使用HttpClient发送POST请求到统一下单接口,处理返回的XML数据,提取code_url,然后用二维码生成生成图片。 另外,需要注意接口的安全性,比如IP白名单配置,引用[3]提到接口强制校验来源IP,所以在调用微信API时,需要确保服务器IP在微信支付后台配置的白名单中。 总结回答结构:首先介绍微信支付生成二维码的基本流程,分步骤说明,包括获取access_token(如果需要)、统一下单接口调用、处理响应、生成二维码,并提供Java示例代码。同时,引用相关的引用内容,比如参数签名和IP校验的部分。 还需要检查用户提供的引用内容是否有其他相关信息。引用[1]提到使用uQRCode插件生成二维码,这可能是在小程序前端生成二维码的方法,但用户的问题是关于后端API生成支付二维码,所以可能更侧重于后端如何获取支付链接,然后生成二维码。不过如果用户需要前后端结合的示例,可能需要说明后端返回code_url,前端生成二维码。 可能的问题:用户是否混淆了微信支付生成二维码和小程序生成二维码的不同接口?需要明确说明微信支付的标准流程,并指出引用[3]中的接口是否是支付相关的,或者属于其他业务模块。根据引用[3]的接口URL中的/shop/funds/qrcode/get,可能属于微信小商店的资金相关二维码,并非标准微信支付接口,因此正确的接口应该是统一下单接口返回的code_url。 因此,回答中应重点介绍统一下单接口的使用,获取code_url,然后使用工具生成二维码。同时,示例代码可以包括Java调用统一下单接口,解析返回的code_url,并用ZXing等库生成二维码图片。</think>### 微信支付 API 生成二维码接口实现步骤 #### 一、核心流程概述 1. **统一下单接口**:生成支付订单并获取二维码参数`code_url`[^2] 2. **生成二维码图片**:将`code_url`转换为可扫描的二维码图像 #### 二、具体实现步骤 **1. 调用统一下单接口** ```java // 示例代码(JAVA) public Map<String, String> unifiedOrder(String appId, String mchId, String key) { String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; Map<String, String> params = new HashMap<>(); params.put("appid", appId); params.put("mch_id", mchId); params.put("nonce_str", generateNonceStr()); params.put("body", "测试商品"); params.put("out_trade_no", "ORDER_123456"); params.put("total_fee", "1"); params.put("spbill_create_ip", "服务器IP"); params.put("notify_url", "回调地址"); params.put("trade_type", "NATIVE"); // 二维码支付模式 // 生成签名 String sign = generateSignature(params, key); params.put("sign", sign); // 发送XML请求 String xmlResponse = sendPostRequest(url, mapToXml(params)); return xmlToMap(xmlResponse); } ``` $$ sign = \text{MD5}( \text{参数按ASCII排序} \& \text{key} ) $$ *返回数据示例:* ```xml <xml> <code_url>weixin://wxpay/bizpayurl?pr=abcdefg</code_url> </xml> ``` **2. 生成二维码图片** ```java // 使用ZXing库生成二维码 public void createQRCode(String codeUrl, int width, int height, String filePath) { BitMatrix matrix = new MultiFormatWriter().encode(codeUrl, BarcodeFormat.QR_CODE, width, height); MatrixToImageWriter.writeToPath(matrix, "PNG", Paths.get(filePath)); } ``` #### 三、关键注意事项 1. **IP白名单配置**:调用接口需提前在微信商户平台配置服务器IP[^3] 2. **签名验证**:所有请求参数必须使用MD5签名算法[^2] 3. **二维码有效期**:`code_url`默认有效期2小时,超时需重新生成
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只java小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值