WeChat scan code payment (including appid, mch_id, key), which can be run locally

Note: The appid, mch_id, and key of this article are all from Chuanzhi podcast. This article is only for learning, and I hope readers will not use them for commercial purposes.

1. Go to the WeChat payment development document to fetch and download the java demo  https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

As shown in the figure:

 

After the download is complete, open it with the development tool. Each class has a corresponding code comment. The author will not explain them one by one here.

 

2. Make a simulation of WeChat unified order placement, and you can know which parameters are necessary through its development document

WeChat unified order address: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

3. Paste the code directly

appid, mch_id, and key are all from Chuanzhi podcast. I hope readers will not use them for commercial purposes, but only for learning.

package com.github.wxpay.test;

import com.github.wxpay.sdk.IWXPayDomain;
import com.github.wxpay.sdk.WXPayConfig;

import java.io.InputStream;


public class Config extends WXPayConfig {

    /**
     * appId
     * */
    private static final String appId="wx8397f8696b538317";

    /**
     * mch_id
     * */
    private static final String mchId = "1473426802";

    /**
     * key
     * */
    private static final String key = "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb";

    @Override
    public String getAppID() {
        return appId;
    }


    @Override
    public String getMchID() {
        return mchId;
    }

    @Override
    public String getKey() {
        return key;
    }

    /**
     * 证书,暂时不需要
     * @return
     */
    @Override
    public InputStream getCertStream() {
        return null;
    }

    /**
     * 域名
     * @return
     */
    @Override
    public IWXPayDomain getWXPayDomain() {
        return  new IWXPayDomain() {
            public void report(String domain, long elapsedTimeMillis, Exception ex) {

            }

            public DomainInfo getDomain(WXPayConfig config) {
                return new DomainInfo("api.mch.weixin.qq.com",true);
            }
        };

    }
}

4. Test

package com.github.wxpay.test;

import com.github.wxpay.sdk.WXPayRequest;
import com.github.wxpay.sdk.WXPayUtil;

import java.util.HashMap;
import java.util.Map;


public class WXPayTest {
    public static void main(String[] args) throws Exception {
        Config config = new Config();
        //1、封装参数
        Map<String, String> map = new HashMap<String, String>();
        map.put("appid", config.getAppID());//公账号id
        map.put("mch_id", config.getMchID());//商户号
        map.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
        map.put("body", "商品描述--测试");//商品描述
        map.put("out_trade_no", "22222122112");//商户订单号
        map.put("total_fee", "1");//金额
        map.put("spbill_create_ip", "127.0.0.1");//终端ip
        map.put("notify_url", "http://www.baidu.com");//通知地址
        map.put("trade_type", "NATIVE");//交易类型 native本地支付

        //微信提供的工具包
        String xmlParam = WXPayUtil.generateSignedXml(map, config.getKey());
        System.out.println("参数内容:" );
        System.out.println(xmlParam);

        //2、发送请求
        WXPayRequest wxPayRequest = new WXPayRequest(config);
        String xmlResult = wxPayRequest.requestWithCert("/pay/unifiedorder", null, xmlParam, false);
        System.out.println("参数结果:");
        System.out.println(xmlResult);

        //解析返回结果
        Map<String ,String> m = WXPayUtil.xmlToMap(xmlResult);
        String url = m.get("code_url");
        System.out.println("支付地址:"+url);
    }
}

process:

1) Encapsulation parameters: encapsulate the necessary parameters in the unified order into an xml file

2) Send request: submit the encapsulated xml to the WeChat payment system

3) Analyze the returned result: If there is no problem with the xml, the WeChat payment system will give us a url, which is the payment address

As shown in the figure:

 

5. The last step is to put the payment address into the QR code. If you have trouble generating the QR code, you can check this article: https://blog.csdn.net/qq_36138652/article/details/114986021

Remember to modify the content in the QR code, because the content in the QR code is the url you paid for

package com.code;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


public class QRCodeUtil {

    /**
     * CODE_WIDTH:二维码宽度,单位像素
     * CODE_HEIGHT:二维码高度,单位像素
     * FRONT_COLOR:二维码前景色,0x000000 表示黑色
     * BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
     * 演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
     */
    private static final int CODE_WIDTH = 400;
    private static final int CODE_HEIGHT = 400;
    private static final int FRONT_COLOR = 0x000000;
    private static final int BACKGROUND_COLOR = 0xFFFFFF;

    public static void main(String[] args) {
        String codeContent1 = "weixin://wxpay/bizpayurl?pr=JJ4LTGRzz";
        File file = new File("D:/codes");
        String fileName = "z"+System.currentTimeMillis()+".png";
        createCodeToFile(codeContent1, file, fileName,"");

    }
    /**
     * 生成二维码 并 保存为图片
     */
    /**
     * @param codeContent        :二维码参数内容,如果是一个网页地址,如 https://www.baidu.com/ 则 微信扫一扫会直接进入此地址
     *                           如果是一些参数,如 1541656080837,则微信扫一扫会直接回显这些参数值
     * @param codeImgFileSaveDir :二维码图片保存的目录,如 D:/codes
     * @param fileName           :二维码图片文件名称,带格式,如 123.png
     */
    public static void createCodeToFile(String codeContent, File codeImgFileSaveDir, String fileName,String note) {
        try {
            /** 参数检验*/
            if (codeContent == null || "".equals(codeContent)) {
                System.out.println("二维码内容为空,不进行操作...");
                return;
            }
            codeContent = codeContent.trim();
            if (codeImgFileSaveDir == null || codeImgFileSaveDir.isFile()) {
                codeImgFileSaveDir = FileSystemView.getFileSystemView().getHomeDirectory();
                System.out.println("二维码图片存在目录为空,默认放在桌面...");
            }
            if (!codeImgFileSaveDir.exists()) {
                codeImgFileSaveDir.mkdirs();
                System.out.println("二维码图片存在目录不存在,开始创建...");
            }
            if (fileName == null || "".equals(fileName)) {
                fileName = new Date().getTime() + ".png";
                System.out.println("二维码图片文件名为空,随机生成 png 格式图片...");
            }
            /**com.google.zxing.EncodeHintType:编码提示类型,枚举类型
             * EncodeHintType.CHARACTER_SET:设置字符编码类型
             * EncodeHintType.ERROR_CORRECTION:设置误差校正
             *      ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
             *      不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
             * EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近
             * */
            Map<EncodeHintType, Object> hints = new HashMap();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            hints.put(EncodeHintType.MARGIN, 1);

            /**
             * MultiFormatWriter:多格式写入,这是一个工厂类,里面重载了两个 encode 方法,用于写入条形码或二维码
             *      encode(String contents,BarcodeFormat format,int width, int height,Map<EncodeHintType,?> hints)
             *      contents:条形码/二维码内容
             *      format:编码类型,如 条形码,二维码 等
             *      width:码的宽度
             *      height:码的高度
             *      hints:码内容的编码类型
             * BarcodeFormat:枚举该程序包已知的条形码格式,即创建何种码,如 1 维的条形码,2 维的二维码 等
             * BitMatrix:位(比特)矩阵或叫2D矩阵,也就是需要的二维码
             */
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            BitMatrix bitMatrix = multiFormatWriter.encode(codeContent, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);

            /**java.awt.image.BufferedImage:具有图像数据的可访问缓冲图像,实现了 RenderedImage 接口
             * BitMatrix 的 get(int x, int y) 获取比特矩阵内容,指定位置有值,则返回true,将其设置为前景色,否则设置为背景色
             * BufferedImage 的 setRGB(int x, int y, int rgb) 方法设置图像像素
             *      x:像素位置的横坐标,即列
             *      y:像素位置的纵坐标,即行
             *      rgb:像素的值,采用 16 进制,如 0xFFFFFF 白色
             */
            BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
            for (int x = 0; x < CODE_WIDTH; x++) {
                for (int y = 0; y < CODE_HEIGHT; y++) {
                    bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
                }
            }

            /**javax.imageio.ImageIO java 扩展的图像IO
             * write(RenderedImage im,String formatName,File output)
             *      im:待写入的图像
             *      formatName:图像写入的格式
             *      output:写入的图像文件,文件不存在时会自动创建
             *
             * 即将保存的二维码图片文件*/
            File codeImgFile = new File(codeImgFileSaveDir, fileName);
            ImageIO.write(bufferedImage, "png", codeImgFile);

            System.out.println("二维码图片生成成功:" + codeImgFile.getPath());


            // 自定义文本描述
            if (StringUtils.isNotEmpty(note)) {
                // 新的图片,把带logo的二维码下面加上文字
                BufferedImage outImage = new BufferedImage(400, 445, BufferedImage.TYPE_4BYTE_ABGR);
                Graphics2D outg = outImage.createGraphics();
                // 画二维码到新的面板
                outg.drawImage(bufferedImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), null);
                // 画文字到新的面板
                outg.setColor(Color.BLACK);
                outg.setFont(new Font("楷体", Font.BOLD, 30)); // 字体、字型、字号
                int strWidth = outg.getFontMetrics().stringWidth(note);
                Integer height = 400;
                if (strWidth > 399) {
                    //长度过长就截取前面部分
                    // 长度过长就换行
                    String note1 = note.substring(0, note.length() / 2);
                    String note2 = note.substring(note.length() / 2, note.length());
                    int strWidth1 = outg.getFontMetrics().stringWidth(note1);
                    int strWidth2 = outg.getFontMetrics().stringWidth(note2);

                    outg.drawString(note1, 200 - strWidth1 / 2, height + (outImage.getHeight() - height) / 2 + 12);
                    BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR);
                    Graphics2D outg2 = outImage2.createGraphics();
                    outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
                    outg2.setColor(Color.BLACK);
                    outg2.setFont(new Font("宋体", Font.BOLD, 30)); // 字体、字型、字号

                    outg2.drawString(note2, 200 - strWidth2 / 2, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 + 5);
                    outg2.dispose();
                    outImage2.flush();
                    outImage = outImage2;
                } else {
                    outg.drawString(note, 200 - strWidth / 2, height + (outImage.getHeight() - height) / 2 + 12); // 画文字
                }
                outg.dispose();
                outImage.flush();
                bufferedImage = outImage;
            }

            bufferedImage.flush();
            /**
             * 区别就是以一句,输出到输出流中,如果第三个参数是 File,则输出到文件中
             */
            ImageIO.write(bufferedImage, "png",codeImgFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

Guess you like

Origin blog.csdn.net/qq_36138652/article/details/114601961