微信支付4步骤搞定

Posted 别动我的猫

tags:

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

在此更正,以前的微信支付借用了网上其他一些帖子,要么半桶水,要么有所隐藏,根本没法用。

当你发现百度已经帮不了你的时候,其实你自身已经有一定的高度了。

前面本文浏览次数在100多,可能坑了一些新手,我自己也被坑。再次抱歉!

下面是我自己实际微信扫码支付的过程记录,以供分享!微信扫码支付也称为万金油支付方式,适用很多场合。

 

首先前提条件得申请微信公众号,需要花一个星期以上的时间。

1、注册公众号(必须选择服务号),注册类型必须(企业/公司,政府,媒体)三选一。

2、认证,必须认真填写材料。认证300一次,不保证成功。被驳回钱打水漂了。

3、提交申请资料:微信支付,1-5个工作日。

4、开户成功,登录商户平台验证。进行测试转账1毛钱。

5、在线签收协议。

其他一些参数的设置可以参考我另一篇文章《微信支付的5个参数获取

 

接入正题,开始开发。

前面使用了其他一些三方jar包,其实后来自己做,感觉根本没必要。一个map和xml的转换以及签名,官方的微信SDK都有。感觉根本没必要,再说也不安全,其次是可用性差。

讲讲开发者要做的事:

1、商户后台调用微信接口统一下单,并返回一个code_url。

2、后台把这个code_url发送给前端,前端生成二维码。与支付宝不同,这个二维码要我们自己生成。

3、支付结果微信会通过回调地址返回给系统,系统再返回给前端。

就这么点事,就这么简单、好多文章要么只写前端要么后台,要么简单变复杂化。所以很多新手因此而懵逼。

下面直接上步骤:

第一步:加入微信支付jar包。

这个要自己编译到maven仓库:第三方开源的不安全,参见微信支付官方提示。

怎么整呢?

把官方下载的SDK打包成jar,然后编译到maven仓库就好了。Dfile就是你打包成jar的存放地址

嫌麻烦,你把SDK那些代码拷到你的项目里直接用也是一样的。

    <!-- 微信公众号支付依赖 最新版本-->
        <!--install:install-file -Dfile=E:\\wxpay-sdk-0.0.3.jar -DgroupId=com.weixin -DartifactId=alipay-sdk-weixin -Dversion=1.0 -Dpackaging=Jar-->
        <dependency>
            <groupId>com.weixin</groupId>
            <artifactId>alipay-sdk-weixin</artifactId>
            <version>1.0</version>
        </dependency>


第二步:编写微信支付配置类PayConfig

import org.springframework.stereotype.Component;

/**
 * 微信支付配置类
 */
@Component
public class PayConfig {

    //初始化
    public final static String APP_ID = "123456"; //公众账号appid(改为自己实际的)
    public final static String APP_PATH = "";//安全证书路径,没用到
    public final static String MCH_ID = "123"; //商户号(改为自己实际的)
    public final static String API_KEY = "pass"; //(改为自己实际的)key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
    //code_url请求地址
    public final static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    public final static String NOTIFY_URL = "http://www.a.com/weixinPay/notify"; //微信支付回调接口,就是微信那边收到(改为自己实际的),需要跟微信公众号微信支付设置的一致
    //企业向个人账号付款的URL
    public final static String SEND_EED_PACK_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
  //查询订单请求URL
  private static final String ORDER_QUERY_REQUEST_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
}

第三步:微信支付控制类


(这个跟前端存在一个交互)service层的一些代码也写在了这里,有点乱。绿色部分是个人业务,不是核心。可以无视

 

import com.github.wxpay.sdk.WXPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 * 微信支付
 */
@Controller
@RequestMapping("/weixinPay")
public class PayController {


    final static Logger log = LoggerFactory.getLogger(PayController.class);

    @Resource
    private RentingtoolsBiz rentingtoolsBiz; //出租工具订单接口
    @Resource
    private CustomerOrderBiz customerOrderBiz;//客户订单接口
    @Resource
    private BrowseRecordsCommonUtil browseRecordsCommonUtil;//缓存类
    @Resource
    private WebSocketServer webSocketServer;//socket
    @Resource
    private PsUserUtils psUserUtils;//缓存类



    /**
     * 跳转到微信支付页面
     * @param request
     * @param model
     * @return
     */
    @RequestMapping("/payCode")
    public String payCode(HttpServletRequest request, Model model){
        BrowseRecordsUtil browseRecordsUtil= browseRecordsCommonUtil.getBrowseRecords(request);
        RentingToosOrder order = (RentingToosOrder)browseRecordsUtil.getPayOrder();
        model.addAttribute("order",order);
        return "business/payWeiXin";
    }

    /**
     * 获取微信支付二维码(前端根据这个返回的数据生成二维码)
     * @param request
     */
    @ResponseBody
    @RequestMapping("/weixinCode")
    public RestObject qrcode(HttpServletRequest request) {
        try {
            String data = weixinPay(request);
            return RestObject.newOk("ok",data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 微信平台发起的回调方法,
     * 调用我们这个系统的这个方法接口,将扫描支付的处理结果告知我们系统
     * @throws
     * @throws Exception
     */
    @RequestMapping(value = "/notify")
    public void weixinNotify(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成map
        Map<String, String> map = WXPayUtil.xmlToMap(sb.toString());
        // 账号信息
        String key = PayConfig.API_KEY; //key
        String userId = psUserUtils.getUserId(request);
        //判断签名是否正确
        if(WXPayUtil.isSignatureValid(sb.toString(),key)) {
            //------------------------------
            //处理业务开始
            //------------------------------
            String resXml = "";
            if("SUCCESS".equals((String)map.get("result_code"))){
                // 这里是支付成功
                //////////执行自己的业务逻辑////////////////
                //String mch_id = (String)map.get("mch_id");
                //String openid = (String)map.get("openid");
                //String is_subscribe = (String)map.get("is_subscribe");
                //String out_trade_no = (String)map.get("out_trade_no");
                String total_fee = (String)map.get("total_fee");//注意这个金额单位是分
                //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                        //这里处理更新数据库订单支付成功的信息#######################

            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }
            //------------------------------
            //处理业务完毕
            //------------------------------
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            webSocketServer.sendInfo("微信支付失败!","service"+userId);
        } else{
            System.out.println("通知签名验证失败");
        }

    }
    
    
    /**
     * 发起微信支付
     * @param request
     * @param
     * @return
     * @throws Exception
     */
    public String weixinPay(HttpServletRequest request) throws Exception {
        BrowseRecordsUtil browseRecordsUtil= browseRecordsCommonUtil.getBrowseRecords(request);
        Order order=browseRecordsUtil.getPayOrder();//获取缓存里的订单信息
        Map packageParams=new HashMap();
        //这里暂时只处理A类型的业务
        if(order instanceof RentingToosOrder){
            RentingToosOrder order1=(RentingToosOrder)order;
            //注意这里的参数都是String类型,否则会报类型转换错误
            packageParams.put("appid", PayConfig.APP_ID);//公众账号ID
            packageParams.put("mch_id", PayConfig.MCH_ID);//商户ID
            packageParams.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
            packageParams.put("body", "腾讯视频");  //(调整为自己的名称)
            packageParams.put("out_trade_no", order1.getId());//订单编号
            DecimalFormat decimalFormat = new DecimalFormat("###################.###########");
            packageParams.put("total_fee",decimalFormat.format(order1.getTotalPrice() * 100)); //价格的单位为分
            packageParams.put("spbill_create_ip",request.getLocalAddr());//请求ip        
            packageParams.put("notify_url", PayConfig.NOTIFY_URL);//异步回调地址  
            packageParams.put("trade_type", "NATIVE");//交易类型   
        } 
        try { 
        
        //支付请求参数,WXPayUtil生成签名并转成xml 
        String xmlParam = WXPayUtil.generateSignedXml(packageParams, PayConfig.API_KEY); 
        
        //2.发送请求,HttpClientUtil类是封装的一个HttpClient类包含了Https请求兼容的处理方法  
        HttpClientUtil httpClient=new HttpClientUtil(PayConfig.UFDODER_URL); 
        httpClient.setHttps(true); httpClient.setXmlParam(xmlParam); httpClient.post(); 
        
        //3.获取结果。这里做一个说明,微信支付jsapi支付授权目录必须跟请求页面地址匹配:例如请求页面是www.a.com/weixinPay/weixin.html       
        // 那么jsapi支付授权目录必须要有www.a.com/weixinPay/的授权地址。其次回调地址要跟设置的一样       
        // 否则返回的数据为空 
        
        String xmlResult = httpClient.getContent(); 
        //log.error("打印微信支付返回的xml"+xmlResult); 
        Map<String, String> mapResult = WXPayUtil.xmlToMap(xmlResult); 
        //log.error("打印微信支付返回的map"+mapResult); 
    log.error("打印微信支付返回的map"+mapResult);
    String urlCode = mapResult.get("code_url");
    log.error(urlCode);
    //对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX
        return urlCode;
        } catch (Exception e) {
            e.printStackTrace(); 
        } 
            return null; 
    } 
}

 


第四步:前端

前端主要是生成了一个二维码,这里用的是纯前端技术qrious.js。没有后台生成,减少了后台的压力。
再者前端和后台建了socket连接,因此前台也不用轮询请求后台支付是否成功。支付成功后台会告诉前台,且只有一次。
没有建立socket连接的只用后台把支付结果保存,然后前端setInterval()轮询ajax请求返回即可。

HTML
  <div id="tab-page">
     <img id="codeImg" alt="微信支付二维码"  width="300px" height="300px">
  </div>

 获取二维码

$.ajax({
    type: "POST",//请求类型
    url: path + "/weixinPay/weixinCode",//请求的url
    dataType: "json",//ajax接口(请求url)返回的数据类型
    success: function (data) {//data:返回数据(json对象)
        if(data.data!=""){
            var qr = new QRious({
                element:document.getElementById("codeImg"),
                size:300,
                level:\'L\',
                value:data.data
            });
        }else {
            errerInformation("获取微信支付二维码失败!","javascript:void(0);");//弹窗告诉前台下单失败!
        }
    }
});

  socket通知

    //获得消息事件
    socket.onmessage = function(msg) {
        console.log(msg.data);
        //发现消息进入    开始处理前端触发逻辑,连接成功不提示,烦
        if(msg.data!="连接成功"){
            errerInformation(msg.data,"javascript:void(0);");//alert弹窗socket信息
            setTimeout(function () {
                if(msg.data=="微信支付成功!"){
                    window.location.href=path+"/index";//成功返回首页
                }
            },2000);
        }
    };
    

 







以上是关于微信支付4步骤搞定的主要内容,如果未能解决你的问题,请参考以下文章

Cordova - 彻底搞定安卓中的微信支付插件!

Cordova - 彻底搞定安卓中的微信支付插件!

10分钟搞定支付宝和微信支付 的 各种填坑

10分钟搞定支付宝和微信支付的各种填坑

微信支付的几种场景及步骤

两张图看懂APP微信支付、APP支付宝支付