第三方支付之微信支付(扫码支付)

Posted 二十六度半

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第三方支付之微信支付(扫码支付)相关的知识,希望对你有一定的参考价值。


 
第一步:注册微信支付账户,开通扫码支付
具体流程请参照官方说明
 
第二步:创建Maven项目
 
1. 添加微信支付SDK依赖、二维码工具依赖(微信支付需要自己通过二维码工具生成支付二维码)
     <!-- 微信支付 -->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
        
        <!-- google二维码工具 -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.1.0</version>
        </dependency>

 

2. 实现SDK微信配置类,创建商户自己的配置类

public class WxPayConfig implements WXPayConfig{

    private byte[] certData;
    
    //初始化退款、撤销时的商户证书
    public WxPayConfig() throws Exception {
        String certPath = "D://第三方开放平台/wx_apiclient_cert.p12";
        File file = new File(certPath);
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }

    public String getAppID() {
        return "";
    }

    /** 微信支付商户号 */
    public String getMchID() {
        return "";
    }

    public String getKey() {
        return "";
    }

    public int getHttpConnectTimeoutMs() {
        return 8000;
    }

    public int getHttpReadTimeoutMs() {
        return 10000;
    }

    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis;
        certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }
}

 

3. 创建微信支付的控制器类
 
     3.1 初始化微信支付的SDK客户端
private WxPayConfig config;

private WXPay wxpay;

public WxPayController() {
   try {
      //初始化微信支付客户端
      config = new WxPayConfig();
      wxpay = new WXPay(config);
   } catch (Exception e) {
      e.printStackTrace();
   }
}

 

 3.2 创建预支付接口,生成支付二维码(可以在页面添加img标签,让它的url指向这里就能直接在页面特定区域显示二维码了)

/**
     * 预支付接口,生成支付二维码
     * @param order
     * @return
     * @throws Exception
     */
    @RequestMapping("/wxpay/pay")
    public void pay(HttpServletResponse response) throws Exception {
        //TODO:这里执行商户系统创建新的订单操作
        WxPayOrder order = new WxPayOrder();
        order.setOut_trade_no(System.currentTimeMillis() + "");
        wxPayService.createOrder(order);
        
        //设置请求参数
        Map<String, String> data = new HashMap<String, String>();
        data.put("body", "微信支付测试");
        data.put("out_trade_no", order.getOut_trade_no());
        data.put("device_info", "");
        data.put("fee_type", "CNY");
        data.put("total_fee", "1");
        data.put("spbill_create_ip", "192.168.0.119");
        data.put("notify_url", notify_url);
        data.put("trade_type", "NATIVE");  // 此处指定为扫码支付
        data.put("product_id", "12");

        try {
            //发起支付
            Map<String, String> resp = wxpay.unifiedOrder(data);
            //获取二维码URL
            String code_url = resp.get("code_url");
            //根据url生成二维码
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            // 设置二维码参数
            Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = multiFormatWriter.encode(code_url, BarcodeFormat.QR_CODE, 300, 300, hints);
            //返回二维码
            MatrixToImageWriter.writeToStream(bitMatrix, "jpg", response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

 3.3 创建支付结果回调接口(回调的URL必须公网可以访问,测试时可以使用花生壳等工具映射一个公网地址

/**
     * 支付结果回调
     * @return
     * @throws Exception 
     */
    @PostMapping("/wxpay/notify_url")
    public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 读取回调内容
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        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();
        
        // 支付结果通知的xml格式数据
        String notifyData = sb.toString(); 

        // 转换成map
        Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);

        //支付确认内容
        String resXml = "";
        //验证签名
        if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {        // 签名正确
            WxPayOrder order = wxPayService.getOrder(notifyMap.get("out_trade_no"));
            if(order != null) {
                if("SUCCESS".equals(notifyMap.get("result_code"))) {    //交易成功
                    // TODO:更新订单
                    System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付成功");
                } else {    //交易失败
                    System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败");
                }
            }
            // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
            
            //设置成功确认内容
            resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        }
        else {  // 签名错误,如果数据里没有sign字段,也认为是签名错误
            //设置失败确认内容
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg></return_msg>" + "</xml> ";
            System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败");
        }
        
        //发送通知
        response.getWriter().println(resXml);
    }

 

 3.4 创建申请退款接口(这里一定要注意先要下载并配置证书,否则会报错;证书下载请参考官方文档,证书配置见商户微信配置类)

/**
     * 微信申请退款接口
     * @param out_trade_no        订单号
     * @throws Exception
     */
    @RequestMapping("/wxpay/refund")
    public void refund(String out_trade_no) throws Exception {
        //设置请求参数
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("out_trade_no", out_trade_no);
        data.put("out_refund_no", out_trade_no);
        data.put("total_fee", "1");
        data.put("refund_fee", "1");
        data.put("refund_fee_type", "CNY");
        data.put("op_user_id", config.getMchID());

        try {
            //调用sdk发起退款
            Map<String, String> result = wxpay.refund(data);
            if("SUCCESS".equals(result.get("result_code"))) {
                //TODO:更新订单
                System.out.println("订单" + out_trade_no + "微信退款成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

第三步:测试支付、退款
 
1. 运行项目 mvn jetty:run
 
2. 测试支付接口:http://localhost:8080/wxpay/pay
 
3. 测试退款接口:http://localhost:8080/wxpay/refund
 
 
说明:当前项目仅实现了简单的支付和退款功能,代码大部分搬自官方示例,并不包括完整的支付流程,有什么不明白的地方,欢迎留言

以上是关于第三方支付之微信支付(扫码支付)的主要内容,如果未能解决你的问题,请参考以下文章

thinkphp整合系列之微信扫码支付

PHP对接第三方支付渠道之微信支付v3版本

微信支付之扫码支付相关代码(Java)

unity探索者之微信支付,非第三方插件

微信点餐之微信授权

微信点餐之微信授权