• 微信二维码支付(native方式)


    1.微信支付的官网对接手册:

    地址:https://pay.weixin.qq.com/wiki/doc/api/index.html

    微信对接分多中方式,而native是调用微信支付服务在网页生成二维码,客户扫描二维码支付。

    2.准备工作

    (1)申请服务号,需要审核认证,300块钱。

    (2)服务号申请通过后,在微信公众平台开通微信支付

    开通参考地址:https://jingyan.baidu.com/album/e8cdb32b0bb7de37042bad7b.html?picindex=3

    简单说下开通流程,需要几个重要信息,身份证正反面照片,一个对公的银行账户和卡号,申请提交后等待3-5个工作日进行审核。开通的时候回填一个邮箱,开通成功后回把一些信息发到邮箱上面。

    (3)开通微信支付的邮箱接收到的商品平台信息:

    开通之后,APPID是知道了,商户号也知道了。 

    (4)登录微信商用平台

    地址:https://pay.weixin.qq.com/ 

    去设置API密匙,下载证书,密匙设置好后不会显示,所以记得保存。

    注意:证书是退款是用到的,不光退款,是你的钱往外出的时候用到证书,可以不用管,下面会讲到退款怎么处理。

    设置回调接口,就是微信支付成功之后,微信会回调,填写一个回调地址。

    此时,API密匙有了,签名加密方式就用MD5就行,证书也有了。

    (5)另外需要的参数

    还剩一个开发者密码:

    这个应该是申请服务号之后设置的,设置之后不会显示,所以提前需要保存。(我是用公司的服务号,都是开通好的,但是不知道开发者密码,只能选择重置)

     重置:

    (6)参数已经全了,说一些题外的。

    微信分公众平台,开放平台,商户平台总共三个平台。了解一下三个平台的区别。

    微信三个平台区分(开放,公众,商户平台):https://blog.csdn.net/atongmu2017/article/details/94728996

    ps:微信开放平台中可以在查看移动应用中去开通微信支付功能,但是这个是对接微信支付的另一种方式,好像是app拉起微信支付,类似于外卖下单支付的时候跳到微信手机客户端的支付界面。(注意这个区分)

    查看界面:

    3.下载 SDK

    地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

    下载的压缩包解压出来有几个类:

    扔到项目下:

    我项目用的是jdk1.8,WXPayXmlUtil这个类会报错,提示XMLConstants.FEATURE_SECURE_PROCESSING找不到。

     解决办法:把下面这个jar包从libraries中移除,报错消失。消失之后,再次加入libraries中,也不再报错。

    4.生成订单二维码

    页面请求生成二维码有关的类:

     CommonUtil.java

    有两个方法,一个是发送http请求,用于发送xml参数给微信服务器,另一个是获取ip,xml参数中有个参数是ip

     
    package com.jeeplus.modules.wxpay;
     
     
     
    import java.io.BufferedReader;
     
    import java.io.InputStream;
     
    import java.io.InputStreamReader;
     
    import java.io.OutputStream;
     
    import java.net.URL;
     
    import java.util.Iterator;
     
    import java.util.Map;
     
    import java.util.Set;
     
    import java.util.SortedMap;
     
     
     
    import javax.net.ssl.HttpsURLConnection;
     
    import javax.servlet.http.HttpServletRequest;
     
    import org.apache.commons.lang.StringUtils;
     
    import third.wxpay.WXPayUtil;
     
     
     
    public class CommonUtil {
     
     
     
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
     
    try {
     
    URL url = new URL(requestUrl);
     
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
     
    conn.setDoOutput(true);
     
    conn.setDoInput(true);
     
    conn.setUseCaches(false);
     
    // 设置请求方式(GET/POST)
     
    conn.setRequestMethod(requestMethod);
     
    conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
     
    // 当outputStr不为null时向输出流写数据
     
    if (null != outputStr) {
     
    OutputStream outputStream = conn.getOutputStream();
     
    // 注意编码格式
     
    outputStream.write(outputStr.getBytes("UTF-8"));
     
    outputStream.close();
     
    }
     
    // 从输入流读取返回内容
     
    InputStream inputStream = conn.getInputStream();
     
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
     
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
     
    String str = null;
     
    StringBuffer buffer = new StringBuffer();
     
    while ((str = bufferedReader.readLine()) != null) {
     
    buffer.append(str);
     
    }
     
    // 释放资源
     
    bufferedReader.close();
     
    inputStreamReader.close();
     
    inputStream.close();
     
    inputStream = null;
     
    conn.disconnect();
     
    return buffer.toString();
     
    } catch (Exception e) {
     
    e.printStackTrace();
     
    }
     
    return null;
     
    }
     
     
     
     
     
    /**
     
    * 获取ip
     
    * @param request
     
    * @return
     
    */
     
    public static String getIp(HttpServletRequest request) {
     
    if (request == null)
     
    return "";
     
    String ip = request.getHeader("X-Requested-For");
     
    if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
     
    ip = request.getHeader("X-Forwarded-For");
     
    }
     
    if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
     
    ip = request.getHeader("Proxy-Client-IP");
     
    }
     
    if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
     
    ip = request.getHeader("WL-Proxy-Client-IP");
     
    }
     
    if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
     
    ip = request.getHeader("HTTP_CLIENT_IP");
     
    }
     
    if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
     
    ip = request.getHeader("HTTP_X_FORWARDED_FOR");
     
    }
     
    if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
     
    ip = request.getRemoteAddr();
     
    }
     
    return ip;
     
    }
     
     
     
    }

    ConfigUtil.java

    存放一些支付参数和回调接口信息

     
    package com.jeeplus.modules.wxpay;
     
     
     
    public class ConfigUtil {
     
    /**
     
    * 服务号相关信息
     
    */
     
    public final static String APPID = "";//服务号的应用号
     
    public final static String MCH_ID = "";//商户号
     
    public final static String APP_SECRECT = "";//服务号的应用密码
     
    public final static String API_KEY = "";//API密钥
     
    public final static String SIGN_TYPE = "MD5";//签名加密方式
     
    public final static String CERT_PATH = "D:/project/cert/apiclient_cert.p12";//微信支付证书存放路径地址
     
     
     
    public final static String TOKEN = "";//服务号的配置token
     
    //微信支付统一接口的回调action
     
    //填写自己网站的接口
     
    public final static String NOTIFY_URL = "http://www.baidu.com";
     
     
     
    }

    MatrixToImageWriter.java

    地址变成二维码图片的类,用到 com.google.zxing.common.BitMatrix这个类,用到zxing这个jar包

    package com.jeeplus.modules.wxpay;
     
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.EncodeHintType;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.common.BitMatrix;
    import javax.imageio.ImageIO;
    import java.io.File;
    import java.io.OutputStream;
    import java.io.IOException;
    import java.util.Hashtable;
    import java.awt.image.BufferedImage;
     
    
    public final 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);
     
    }
     
    }
     
     
     
    public static void main(String[] args) throws Exception {
     
    String text = "www.baidu.com";
     
    int width = 300;
     
    int height = 300;
     
    String format = "gif";
     
    Hashtable hints = new Hashtable();
     
    hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
     
    BitMatrix bitMatrix = new MultiFormatWriter().encode(text,
     
    BarcodeFormat.QR_CODE, width, height, hints);
     
    File outputFile = new File("d:"+File.separator+"new.gif");
     
    MatrixToImageWriter.writeToFile(bitMatrix, format, outputFile);
     
    }
     
    }

    创建订单的方法:

    private void doWx(HttpServletRequest request,HttpServletResponse response) throws Exception {
     
    String number=request.getParameter("number")==null?"":request.getParameter("number");
     
    Productorder p = productorderService.findUniqueByProperty("number", number);
     
    Date date=new Date();
     
    SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
     
    String timeStart=sdf.format(date);
     
    Calendar cal=Calendar.getInstance();
     
    cal.add(Calendar.DAY_OF_MONTH, 1);
     
    Date date1=cal.getTime();
     
    String timeExpire=sdf.format(date1);
     
    SortedMap<String,String> parameters = new TreeMap<String,String>();
     
    parameters.put("appid", ConfigUtil.APPID);
     
    parameters.put("body", p.getPname());
     
    parameters.put("mch_id", ConfigUtil.MCH_ID);
     
    parameters.put("out_trade_no", number);
     
    parameters.put("spbill_create_ip",CommonUtil.getIp(request));
     
    DecimalFormat df = new DecimalFormat("#");
     
    parameters.put("total_fee", df.format(Double.parseDouble(p.getOrdermoney())*100));
     
    parameters.put("trade_type", "NATIVE");
     
    parameters.put("time_expire", CommonUtil.getOrderExpireTime(startData,5*60*1000L));//二维码过期时间5分钟
     
    parameters.put("nonce_str", WXPayUtil.generateNonceStr());
     
    parameters.put("notify_url", ConfigUtil.NOTIFY_URL);//支付成功后回调的action,与JSAPI相同
     
    String generateSignature = WXPayUtil.generateSignature(parameters, ConfigUtil.API_KEY, SignType.MD5);
     
    parameters.put("sign", generateSignature);
     
    String generateSignedXml = WXPayUtil.generateSignedXml(parameters, ConfigUtil.API_KEY);
     
    System.out.println("微信支付预下单请求xml格式::"+generateSignedXml);
     
    String result =CommonUtil.httpsRequest(ConfigUtil.UNIFIED_ORDER_URL, "POST", generateSignedXml);
     
    System.out.println(result);
     
    Map<String, String> map;
     
    try {
     
     
     
    map = WXPayUtil.xmlToMap(result);
     
    String returnCode = map.get("return_code");
     
    String resultCode = map.get("result_code");
     
    if(returnCode.equalsIgnoreCase("SUCCESS")&&resultCode.equalsIgnoreCase("SUCCESS")){
     
    String codeUrl = map.get("code_url");
     
    //TODO 拿到codeUrl,写代码生成二维码
     
    System.out.println("codeUrl="+codeUrl);
     
    int width = 300;
     
    int height = 300;
     
    //二维码的图片格式
     
    String format = "JPEG";
     
    Hashtable hints = new Hashtable();
     
    //内容所使用编码
     
    hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
     
    BitMatrix bitMatrix = new MultiFormatWriter().encode(codeUrl,
     
    BarcodeFormat.QR_CODE, width, height, hints);
     
    // response.setContentType("image/JPEG");
     
    MatrixToImageWriter.writeToStream(bitMatrix, format, response.getOutputStream());
     
     
     
    }
     
    } catch (Exception e) {
     
    e.printStackTrace();
     
    }

    可以把生成二维码的方法写成一个接口,测试调用接口,页面会显示二维码

    扫描二维码:

    5.创建订单生成二维码注意的问题

    (1)签名算法,需要参数拼接起来,加上密匙参数,拼接后MD5加密得到sign这个参数。而其他参数拼接的时候注意要按参数名ASCII码从小到大排序(字典序),所以用到SortedMap

    SortedMap<String,String> parameters = new TreeMap<String,String>();

    (2)测试的时候生成二维码,之后修改订单金额,请求后显示不出来二维码,微信返回信息如下,原因是同一个订单不允许前后两次请求金额不同。

    <err_code><![CDATA[INVALID_REQUEST]]></err_code><err_code_des><![CDATA[201 商户订单号重复]]></err_code_des>

    (3)total_fee这个订单金额参数需要注意,单位是分,所以需要把元转换成分。

    解决办法:字符串金额转换成double类型,乘以100,然后去掉小数点后的一个零

    1.  
      DecimalFormat df = new DecimalFormat("#");
    2.  
      parameters.put("total_fee", df.format(Double.parseDouble(p.getOrdermoney())*100));

    有个特别容易出错的地方,如果金额是12.34,转换成double类型,然后乘100,你以为最后返回的是1234这个数,其实是1234.0,然后传给微信也是不成功的。必须是整数。

    下面是金额不对的时候,微信返回的错误提示信息: 

    <xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[invalid total_fee]]></return_msg>

    6.回调接口

    支付成功之后,微信会回调你在商用平台上设置的微信回调接口,里面处理支付成功后的业务逻辑。下面的提供参考: 

    /**
     
    * 微信回调接口
     
    * http://127.0.0.1:8080/qcloud/a/payInterface/notifyWeiXinPay
     
    * @param request
     
    * @param response
     
    * @return
     
    * @throws Exception
     
    */
     
    @RequestMapping(value="/notifyWeiXinPay",produces="text/html;charset=utf-8")
     
    @ResponseBody
     
    public String notifyWeiXinPay(HttpServletRequest request, HttpServletResponse response) throws Exception {
     
    Map<String,String> return_data = new HashMap<String,String>();
     
    //读取参数
     
    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());
     
    //判断签名是否正确
     
    // if(true) {
     
     
     
    if(WXPayUtil.isSignatureValid(map, ConfigUtil.API_KEY)) {
     
    if(!map.get("return_code").toString().equals("SUCCESS")){
     
    return_data.put("return_code", "FAIL");
     
    return_data.put("return_msg", "return_code不正确");
     
    }else{
     
    if(!map.get("result_code").toString().equals("SUCCESS")){
     
    return_data.put("return_code", "FAIL");
     
    return_data.put("return_msg", "result_code不正确");
     
    return WXPayUtil.mapToXml(return_data);
     
    }
     
     
     
    String orderno = (String)map.get("out_trade_no");//商户订单号
     
    String transaction_id = (String)map.get("transaction_id");//微信支付订单号
     
    String time_end = (String)map.get("time_end");//支付完成时间yyyyMMddHHmmss
     
    BigDecimal total_fee = new BigDecimal(map.get("total_fee").toString());
     
    //付款完成后,支付宝系统发送该交易状态通知
     
    Productorder order = productorderService.findUniqueByProperty("order_no", orderno);
     
    if(order==null) {
     
    System.out.println("订单不存在");
     
    return_data.put("return_code", "FAIL");
     
    return_data.put("return_msg", "订单不存在");
     
    return WXPayUtil.mapToXml(return_data);
     
    }
     
     
     
    BigDecimal num = new BigDecimal("100");
     
    BigDecimal ordermoney = new BigDecimal(order.getOrdermoney());
     
    ordermoney = ordermoney.multiply(num);
     
    //订单已经支付
     
    if(order.getOrderstatus().equals("1")){
     
    System.out.println("订单已经支付");
     
    return_data.put("return_code", "SUCCESS");
     
    return_data.put("return_msg", "OK");
     
    return WXPayUtil.mapToXml(return_data);
     
    }
     
    //如果支付金额不等于订单金额返回错误
     
    if(ordermoney.compareTo(total_fee)!=0){
     
    System.out.println("资金异常");
     
    return_data.put("return_code", "FAIL");
     
    return_data.put("return_msg", "金额异常");
     
    return WXPayUtil.mapToXml(return_data);
     
    }
     
    //更新订单信息
     
    try {
     
    System.out.println("更新订单信息");
     
    SimpleDateFormat sdf1=new SimpleDateFormat("yyyyMMddHHmmss");
     
    SimpleDateFormat sdf2=new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
     
    order.setOrderstatus("1");
     
    order.setPaytime(sdf2.format(sdf1.parse(time_end)));
     
    order.setPaymentway("1");
     
    productorderService.update(order);
     
     
     
    System.out.println("插入已经支付的订单表");
     
    //插入已经支付的订单表(product_order_pay)
     
    List<String> goodsIds = productgoodsService.getGoodsIdsByOrderno(orderno);
     
    for (String gid : goodsIds) {
     
    Productorderpay productorderpay = new Productorderpay();
     
    productorderpay.setUserid(order.getUserid());
     
    productorderpay.setPpid(gid);
     
    productorderpay.setEndtime(order.getOrderendtime());
     
    productorderpayService.insert(productorderpay);
     
    }
     
     
     
    return_data.put("return_code", "SUCCESS");
     
    return_data.put("return_msg", "OK");
     
    return WXPayUtil.mapToXml(return_data);
     
    } catch (Exception e) {
     
    e.printStackTrace();
     
    return_data.put("return_code", "FAIL");
     
    return_data.put("return_msg", "更新订单失败");
     
    return WXPayUtil.mapToXml(return_data);
     
    }
     
    }
     
    } else{
     
    System.out.println("通知签名验证失败");
     
    return_data.put("return_code", "FAIL");
     
    return_data.put("return_msg", "签名错误");
     
    }
     
    return WXPayUtil.mapToXml(return_data);
     
    }

    7.支付页面

    (1)显示二维码:页面中img标签来显示二维码,img的src指向的是生成二维码的请求。

    (2)查询订单支付状态:同一个页面,去写一个定时异步请求方法,去查询订单是否支付成功,支付成功做下一步处理。

    (3)页面代码参考: 

    <body>
     
    <!--nav-->
     
    <jsp:include page="/eb_headerhs2017.jsp" />
     
    <div class="section">
     
    <div class="section_div">
     
    <div class="section_div_top clear">
     
    <p class="section_div_p">订单提交成功,请尽快付款!订单号:${orderNo}</p>
     
    <p class="section_div_p2">
     
    应付金额 <span class="section_div_span">${orderMoney}</span></p>
     
    </div>
     
    <div class="section_div_bottom clear">
     
    <p class="section_bottom_p">微信支付</p>
     
    <div class="QRcode">
     
    <img class="QRcode_img"
     
    src="填写生成二维码接口?orderNo=${orderNo}" alt="二维码">
     
    <div class="QRcode_div clear">
     
    <img class="QRcode_div_img"
     
    src="images/hs/weixinzhifuerweima_10.png" alt="">
     
    <div class="QRcode_div_div">
     
    <p>请使用微信扫一扫</p>
     
    <p>扫描二维码支付</p>
     
    </div>
     
    </div>
     
    </div>
     
    <img class="phone_saosao" src="images/hs/phone_saosao_03.png" alt="">
     
    <p class="section_bottom_p2">选择其他支付方式</p>
     
    </div>
     
    </div>
     
     
     
    </div>
     
    <script type="text/javascript">
     
    var wxTM = setInterval(function() {
     
    getWxPayStatus();
     
    },5000)
     
    function getWxPayStatus(){
     
    jQuery.ajax({
     
    type: 'POST',
     
    url: "填写查询支付状态接口?orderNo=${orderNo}",
     
    dataType: 'json',
     
    success: function(result){
     
    if(result.res==1){
     
    clearInterval(wxTM);
     
    window.location.href="ebHsPay.jsp?payStatus=1&orderNo=${orderNo}";
     
    }
     
    }
     
    });
     
    }
     
    </script>
     
    <div class="con_bot"></div>
     
    <!--bottom-->
     
    <jsp:include page="/eb_footerhs2017.jsp" />
     
    </body>

    8.订单支付状态接口

    微信提供了查询订单状态的接口,但是一般不去对接微信。对接微信的只涉及一个生产二维码接口。

    怎么去查询支付状态,在支付回调的接口中已经知道订单支付成功还是失败,把状态更新到数据库对应的订单数据中。查询订单状态是从数据库差的,而不是非得去对接微信的查询订单状态接口。

    9.退款

    上面提到自己的账户往外掏钱(退款、发红包)会用到证书,但是退款一般也不对接微信。

    退款的业务逻辑:可以创建一个退款申请表,记录用户退款申请,项目中有这么一个版块。让使用项目管理员去查看这些数据,联系用户为什么退款,让管理员自己处理,真正退款是在微信商用平台上面去退款。平台上有退款的功能,而不是去写代码对接微信退款。

    原因:一方面不用写这块代码。另一方面,万一你这个网站退款的接口被黑会是个问题。还有就是退款请求不会太多,何必走接口。

    10.其他

    自己也是第一次对接微信,有些细节需要注意的地方,我是向经常做商品支付项目的公司同事询问了解的。

    支付这块考虑详细点,代码的可扩展,复用等。越详细越好。不至于之后客户一提需求就改动这块代码,或者这块代码根本用不了。

    (1)建表:一般是订单表和商品表,订单只存订单的信息,商品去关联订单。比如考虑是否有优惠折扣,创建对应的表。

    订单表字段参考

    (2)查询用户是否订购过这个订单

    订单表是从一开始数据是不会删除的,里面的数据只会越来越多。里面有支付成功的订单,超时支付失效的订单等等。

    比如,用户订购了一个视频,查询用户是否订购了这个视频,是否能播放。不可能去查询原始的订单表,到后面数据量大了,查询速度特别慢。需要另建一个表,里面只保存支付成功的订单,一些关键信息,如订单编号,订单用户,到期时间。去查询这个表,之后可以把这个表里的过期订单删除。

    (3)订单编号

    一开始我的订单编号是随机生成的十六位数字,但是不要这样做。

    订单号要一眼能看到这个订单的信息,比如BOOK20190511xxxx,VIDEO20180613xxx,当看到这个订单就知道这个订单是订购的什么,订购的时间。在订单编号里面加上用户信息等等,到时候去查询这个订单的时候,看到这个订单编号大致先了解这个订单的信息,而不是一堆随机数据,什么信息也看不出来。

    (4)支付从页面到后台的流程

    我看到一个电商平台的项目代码,里面的流程可以参考下。

    页面用img的src属性去请求一个controller的pay方法,这个方法中什么都没做,只是处理下请求参数,然后然后请求到原来的页面。二维码怎么生成,在请求返回的过程中,拦截器拦截了请求,根据参数生成二维码返回原来页面。

     

    11.补充

    (1)微信回调

    上面因为我只有一个类型的订单,回调写在回调的方法里,但是这样写不好。

    回调方法处理是个入口,根据不同的订单类型再去跳转不同的回调处理方法。便于之后的扩展,调整修改方便,而不是一改动就去改统一的那个回调方法。

    (2)手机app接微信支付

    因为这种支付方式注意是网站生成二维码,用户扫描支付的。

    手机app接微信支付,最好使接像上面提到的,类似美团的,订外卖支付直接跳转到微信。

    现在这种方式也可以,需要注意一些地方:

    ①微信创建订单接口,会返回一个支付地址,之前是把这个地址生成二维码图片展示,而手机app是直接打开这个地址,手机会跳到微信支付。

    ②支付成功的页面,需要判断是从网站来的还是手机来的,分别显示不同的页面。

    ③支付成功之后的回调,手机app会跳到空白页,苹果的会打开赛风浏览器显示支付成功的页面。再跳回app很多余

    原文链接:https://blog.csdn.net/atongmu2017/article/details/94725934

  • 相关阅读:
    多姿多彩的线程
    字典操作
    字符串语法
    购物车
    列表常用语法
    整数划分问题
    计算N的阶层
    判断是否是素数
    快速排序
    冒泡排序
  • 原文地址:https://www.cnblogs.com/zmjc/p/13685953.html
Copyright © 2020-2023  润新知