zoukankan      html  css  js  c++  java
  • 第三方支付之微信支付(扫码支付)


     
    第一步:注册微信支付账户,开通扫码支付
    具体流程请参照官方说明
     
    第二步:创建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
     
     
    说明:当前项目仅实现了简单的支付和退款功能,代码大部分搬自官方示例,并不包括完整的支付流程,有什么不明白的地方,欢迎留言
  • 相关阅读:
    DropDownList 禁止选择某一项
    C语言文件操作函数(ANSI)详解(二)
    c语言中break与continue的区别
    指针函数
    C语言文件操作函数(ANSI)详解(一)
    结构体指针
    ASCII\UNICODE编码的区别
    函数调用二维数组例子
    getchar()函数getch()函数区别
    C语言 二维数组做函数参数的几种情况
  • 原文地址:https://www.cnblogs.com/gdufs/p/7230950.html
Copyright © 2011-2022 走看看