java实现微信二维码支付

本文详细介绍了一种微信二维码支付的实现方案,包括前后端交互、订单信息处理、二维码生成及扫码支付流程。通过调用微信公众平台接口,实现了PC端H5页面的支付功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

微信公众平台二维码支付

生成的二维码主要是用于PC端H5付款的调用,思路是前端调取获取订单接口,目的是前后端校对价格,代码就不予展示
然后就是根据订单号和价格生成二维码

   @ApiOperation(value = "微信生成二维码", httpMethod = "POST", response = ResultJsonBean.class, notes = "")
    @RequestMapping(value = "/qrcode",  method = {RequestMethod.POST,RequestMethod.GET})
    @ResponseBody
    @ParentPCUser
    public void qrcode(
            @ApiParam(value="token")@RequestParam(required = false) String token,
            @ApiParam(value="支付金额",required = true)@RequestParam(required = true) Long totalprice,
            @ApiParam(value="支付订单号",required = true)@RequestParam(required = true) String orderNo,
            HttpServletRequest request,HttpServletResponse response) {
        try {
            String text = PatriarchWexinPayUtil.weixinPay(orderNo, totalprice*100);
            //根据url来生成生成二维码
            int width = 300;
            int height = 300;
            //二维码的图片格式
            String format = "gif";
            Hashtable hints = new Hashtable();
            //内容所使用编码
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            BitMatrix bitMatrix;
            try {
                bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
                MatrixToImageWriter.writeToStream(bitMatrix, format, response.getOutputStream());
            } catch (WriterException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

然后就是获取code_url工具类

package com.kyd.util.pay;

import com.alibaba.fastjson.JSONArray;
import com.kyd.app_parent.service.vo.WeixinPayVO;
import com.kyd.refund.weixin.util.XmlUtil;
import com.kyd.util.AppException;
import com.kyd.util.Base64Util;
import com.kyd.util.XMLUtil;
import com.swetake.util.Qrcode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jdom.JDOMException;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.Security;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

//import com.swetake.util.Qrcode;

/**
 * 验证是否是微信官网的信息(家长端)
 * @author litao
 *
 */
@Slf4j
@Configuration
public class PatriarchWexinPayUtil implements EnvironmentAware{


	public static String AUTH_API = "https://api.weixin.qq.com/sns/oauth2/access_token";

	// 构造签名的map
    // 构造向微信发送参数的实体类
	
	/*支付宝合作者身份ID*/
	private static  String MCH_ID;
	/*接口名称*/
//	private static final String APPID=AppEnv.getInstance().getStringProp("weixin.appid", "wx998423eb9b2d522a");
	private static  String APPID;//智慧校园的微信appid
	/*接口名称*/
	private static  String QUERY_URL;
	private static  String PAY_URL;
	private static final String KEY="JiaXiaoGongXiangParents0701LoveU";
	private static String NOTIFY_URL=null;
	private static String appSecret;
	@SuppressWarnings("unused")
	private static  String OPENID;
	@SuppressWarnings("unused")
	private static  String SPBILL_CREATE_IP;
	
	private static Environment env;

	/**
	 * 密钥算法
	 */
	private static final String ALGORITHM = "AES";
	/**
	 * 加解密算法/工作模式/填充方式
	 */
	private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";

	public static String getMchId() {
		return MCH_ID;
	}

	public static String getNotifyPrefix(){
		return NOTIFY_URL.substring(0, NOTIFY_URL.lastIndexOf("/"));
	}





    public static String decodeReqInfo(String req_info) throws Exception {
		//1.对加密串A做base64解码,得到加密串B
		log.info("~~~~~~~~~~~~~进入decodeReqInfo方法");
		byte[] req_bytes = Base64Util.decode(req_info);
		log.info("~~~~~~~~~~~~~byte[] req_bytes");
		//2.对商户key做md5,得到32位小写key*
		SecretKeySpec key = new SecretKeySpec(MD5Util.MD5Encode(KEY, "UTF-8").toLowerCase().getBytes(), ALGORITHM);
		log.info("~~~~~~~~~~~~~SecretKeySpec");
		//3.用key*对加密串B做AES-256-ECB解密
		Security.addProvider(new BouncyCastleProvider());
		log.info("~~~~~~~~~~~~~addProvider");
		// 创建密码器
		Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING,"BC");
		log.info("~~~~~~~~~~~~~Cipher");
		//使用密钥初始化,设置为解密模式
		cipher.init(Cipher.DECRYPT_MODE, key);
		log.info("~~~~~~~~~~~~~init");
		byte[] result = cipher.doFinal(req_bytes);
		log.info("~~~~~~~~~~~~~result");
		return new String(result, "utf-8");
	}

    @Override
	public void setEnvironment(final Environment environment) {
		this.env = environment;
		MCH_ID=env.getProperty("weixin.patriarch.mch_id");
		APPID=env.getProperty("weixin.patriarch.appid");
		QUERY_URL=env.getProperty("weixin.queryurl");
		PAY_URL=env.getProperty("weixin.payurl");
		OPENID=env.getProperty("weixin.openid");
		SPBILL_CREATE_IP=env.getProperty("weixin.spbill_create_ip");
		NOTIFY_URL=env.getProperty("weixin.patriarch.notify_url");
		appSecret=env.getProperty("weixin.patriarch.appSecret");
	}

    
	/**
	 *@Description: 生成二维码支付
	 *@parm  
	 *@return  
	 *@Author    litao
	 *@time  2019/10/22 17:14
	 *@other
	 */
	public static String weixinPay(String orderno, Long totalprice) throws Exception {

		String out_trade_no = orderno; //订单号 (调整为自己的生产逻辑)
		String nonceStr=UUID.randomUUID().toString().replace("-", "");
		// 回调接口
		String trade_type = "NATIVE";

		SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
		packageParams.put("appid", APPID);
		packageParams.put("mch_id", MCH_ID);
		packageParams.put("nonce_str", nonceStr);
		packageParams.put("body", "\u4ebf\u8d77\u70b9\u7535\u5b50\u4ea7\u54c1");  //(调整为自己的名称)
		packageParams.put("out_trade_no", out_trade_no);
		packageParams.put("total_fee", totalprice+""); //价格的单位为分
		packageParams.put("spbill_create_ip", SPBILL_CREATE_IP);
		packageParams.put("notify_url", NOTIFY_URL);
		packageParams.put("trade_type", trade_type);
//		String sign = WXSignUtils.createSign("UTF-8", packageParams);
		String sign = PayToolUtil.createSign("UTF-8", packageParams,weixinConstant.KEY);
		packageParams.put("sign", sign);
		String requestXML = PayToolUtil.getRequestXml(packageParams);
		System.out.println(requestXML);

		String resXml = HttpUtil.postData(PAY_URL, requestXML);
		Map map = XMLUtil4jdom.doXMLParse(resXml);
		String urlCode = (String) map.get("code_url");
		return urlCode;
	}

}

PayToolUtil方法

package com.kyd.util.pay;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

public class PayToolUtil {

    /**
     * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     * @return boolean
     */
    public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if(!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }

        sb.append("key=" + API_KEY);

        //算出摘要
        String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
        String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();

        //System.out.println(tenpaySign + "    " + mysign);
        return tenpaySign.equals(mysign);
    }

    /**
     * @author
     * @date 2016-4-22
     * @Description:sign签名
     * @param characterEncoding
     *            编码格式
     * @param parameters
     *            请求参数
     * @return
     */
    public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + API_KEY);
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }

    /**
     * @author
     * @date 2016-4-22
     * @Description:将请求参数转换为xml格式的string
     * @param parameters
     *            请求参数
     * @return
     */
    public static String getRequestXml(SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
                sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
            } else {
                sb.append("<" + k + ">" + v + "</" + k + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    /**
     * 取出一个指定长度大小的随机正整数.
     *
     * @param length
     *            int 设定所取出随机数的长度。length小于11
     * @return int 返回生成的随机数。
     */
    public static int buildRandom(int length) {
        int num = 1;
        double random = Math.random();
        if (random < 0.1) {
            random = random + 0.1;
        }
        for (int i = 0; i < length; i++) {
            num = num * 10;
        }
        return (int) ((random * num));
    }

    /**
     * 获取当前时间 yyyyMMddHHmmss
     *
     * @return String
     */
    public static String getCurrTime() {
        Date now = new Date();
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String s = outFormat.format(now);
        return s;
    }
}

http工具类,负责发起post请求并获取的返回

package com.kyd.util.pay;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;

/**
 * http工具类,负责发起post请求并获取的返回
 */
public class HttpUtil {
    private final static int CONNECT_TIMEOUT = 5000; // in milliseconds
    private final static String DEFAULT_ENCODING = "UTF-8";

    public static String postData(String urlStr, String data){
        return postData(urlStr, data, null);
    }

    public static String postData(String urlStr, String data, String contentType){
        BufferedReader reader = null;
        try {
            URL url = new URL(urlStr);
            URLConnection conn = url.openConnection();
            conn.setDoOutput(true);
            conn.setConnectTimeout(CONNECT_TIMEOUT);
            conn.setReadTimeout(CONNECT_TIMEOUT);
            if(contentType != null)
                conn.setRequestProperty("content-type", contentType);
            OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
            if(data == null)
                data = "";
            writer.write(data);
            writer.flush();
            writer.close();

            reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append("\r\n");
            }
            return sb.toString();
        } catch (IOException e) {
            //logger.error("Error connecting to " + urlStr + ": " + e.getMessage());
        } finally {
            try {
                if (reader != null)
                    reader.close();
            } catch (IOException e) {
            }
        }
        return null;
    }
}

然后就是生成二维码的工具类

package com.kyd.util.pay;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import com.google.zxing.common.BitMatrix;
public class MatrixToImageWriter {

    private static final int BLACK = 0xFF000000;

    private static final int WHITE = 0xFFFFFFFF;

    private MatrixToImageWriter() {
    }

    public static BufferedImage toBufferedImage(BitMatrix matrix) {

        int width = matrix.getWidth();

        int height = matrix.getHeight();

        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    public static void writeToFile(BitMatrix matrix, String format, File file)

            throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format "
                    + format + " to " + file);
        }
    }

    public static void writeToStream(BitMatrix matrix, String format,
                                     OutputStream stream)
            throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, stream)) {
            throw new IOException("Could not write an image of format "
                    + format);
        }
    }
}

按照整体流程前端请求就会生成一个直接可以扫描付款的二维码
生成的二维码
扫码结果
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值