HBuilder打包h5实现微信支付前后端

背景:前端使用HBuilder打包h5,后端使用java.

首先在微信开放平台注册一个移动应用:https://open.weixin.qq.com/cgi-bin/index?t=home/index&lang=zh_CN

对创建的应用进行一些功能上的申请:由于我使用的是公司账号,通过绑定公司的商户号获取微信支付功能.

如图微信支付功能为已获得状态的时候,就可以继续进行下一步操作了.

微信开放平台的包名和签名有获取的规则,不过多进行叙述.

 

由于使用HBuilder打包h5,我们先看一下微信的统一下单:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

按照开放平台给的文档的规则请求:https://api.mch.weixin.qq.com/pay/unifiedorder

得到返回的订单信息:

注意点:

对统一下单接口进行请求之后返回的sign签名并不是调用支付接口需要的签名.只是生成的签名方式要保持一次.

也就是说,统一下单我们需要生成一次sign,调用支付接口还需要生成一次sign.

由于package是java的关键字,

"package","Sign=WXPay"

只能进行前端拼接,但是后端生成sign的时候还要添加进去.

到这里后端的一些处理已经基本完成.

下面是前端的一些问题:

我们进入HBuilder官网,找到支付插件配置页面:https://ask.dcloud.net.cn/article/71

以下是HBuilder给的前端实例代码:

var channel=null;  
// 1. 获取支付通道  
function plusReady(){ //uni-app中将此function里的代码放入vue页面的onLoad生命周期中  
    // 获取支付通道  
    plus.payment.getChannels(function(channels){  
        channel=channels[0];  
    },function(e){  
        alert("获取支付通道失败:"+e.message);  
    });  
}  
document.addEventListener('plusready',plusReady,false);//uni-app不需要此代码  

var ALIPAYSERVER='http://demo.dcloud.net.cn/helloh5/payment/alipay.php?total=';  
var WXPAYSERVER='http://demo.dcloud.net.cn/helloh5/payment/wxpay.php?total=';  
// 2. 发起支付请求  
function pay(id){  
    // 从服务器请求支付订单  
    var PAYSERVER='';  
    if(id=='alipay'){  
        PAYSERVER=ALIPAYSERVER;  
    }else if(id=='wxpay'){  
        PAYSERVER=WXPAYSERVER;  
    }else{  
        plus.nativeUI.alert("不支持此支付通道!",null,"捐赠");  
        return;  
    }  
    var xhr=new XMLHttpRequest(); //uni-app中请使用uni的request api联网  
    xhr.onreadystatechange=function(){  
        switch(xhr.readyState){  
            case 4:  
            if(xhr.status==200){  
                plus.payment.request(channel,xhr.responseText,function(result){  
                    plus.nativeUI.alert("支付成功!",function(){  
                        back();  
                    });  
                },function(error){  
                    plus.nativeUI.alert("支付失败:" + error.code);  
                });  
            }else{  
                alert("获取订单信息失败!");  
            }  
            break;  
            default:  
            break;  
        }  
    }  
    xhr.open('GET',PAYSERVER);  
    xhr.send();  
}

然后按下面的配置操作一番,进行打包Android版本,进行真机测试.

这时候我们发现,可以进行支付宝测试,但是无法唤起微信支付.

下面是对HBuilder前端进行的一些修改:

<html>

	<head>
		<meta charset="utf-8">
		<title>Hello MUI</title>
		<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
		<meta name="apple-mobile-web-app-capable" content="yes">
		<meta name="apple-mobile-web-app-status-bar-style" content="black">
		<!--标准mui.css-->
		<link rel="stylesheet" href="css/mui.min.css">
		<link rel="stylesheet" href="css/mui.css" />

		<!--App自定义的css-->
	</head>

	<body>
		<div class="mui-content">
			<div class="top" id="testLogin">
				<input type="button" value="微信支付" class="weixin" id="weixin" />
				<input type="button" value="支付宝支付" class="zhifubao" id="zhifubao" />
			</div>
		</div>
	</body>
	<script src="js/mui.min.js"></script>
	<script>
		var wxChannel = null; // 微信支付
		var aliChannel = null; //支付宝支付
		// 支付宝支付
		//启用右滑关闭功能
		var channel = null;
		mui.init({
			swipeBack: true
		});
		mui.plusReady(function() {
			// 获取支付通道 
			plus.payment.getChannels(function(channels) {
					for(var i in channels) {
						if(channels[i].id == "wxpay") {
							wxChannel = channels[i];
						}
						if(channels[i].id == "alipay") {
							aliChannel = channels[i];
						}
					}
				},
				function(e) {
					alert("获取支付通道失败:" + e.message);
				});
		})
		document.getElementById('weixin').addEventListener('tap',
			function() {
				console.log("微信");
				pay('wxpay');
			})
		document.getElementById('zhifubao').addEventListener('tap',
			function() {
				console.log("zhifubao");
				pay('alipay');
			})
		var ALIPAYSERVER = 'http://192.168.3.3:9999/users/ALIPay?totalAmount=0.01&subject=兔子';
		var WXPAYSERVER = 'http://192.168.3.3:9999/users/WXPay?body=兔子&fee=1';
		// 2. 发起支付请求 
		function pay(id) {
			//支付宝支付
			if(id == "alipay") {
				var xhr = new XMLHttpRequest();
				xhr.onreadystatechange = function() {
					switch(xhr.readyState) {
						case 4:
							if(xhr.status == 200) {
								alert(xhr.responseText + "这是支付宝需要的参数类型");
								
								plus.payment.request(aliChannel, xhr.responseText, function(result) {
									plus.nativeUI.alert("支付成功!", function() {
										back();
									});
								}, function(error) {
									plus.nativeUI.alert("支付失败:" + error.code);
								});
							} else {
								alert("获取订单信息失败!");
							}
							break;
						default:
							break;
					}
				}
				xhr.open('GET', ALIPAYSERVER);

				xhr.send();

			} else {
				//微信支付
				// 从服务器请求支付订单 
				var PAYSERVER = '';
				var xhr = new XMLHttpRequest();
				xhr.onreadystatechange = function() {
					switch(xhr.readyState) {
						case 4:
							if(xhr.status == 200) {
								var jsonStr = JSON.parse(xhr.responseText);
								var myData = {
									retcode: 0, //5+必备参数
									retmsg: "ok", //5+必备参数
									appid: jsonStr.data.appid,
									noncestr: jsonStr.data.noncestr,
									package: "Sign=WXPay",
									partnerid: jsonStr.data.partnerid,
									prepayid: jsonStr.data.prepayid,
									timestamp: jsonStr.data.timestamp,
									sign: jsonStr.data.sign
								}
								plus.payment.request(wxChannel, myData, function(result) {
									plus.nativeUI.alert("支付成功!", function() {
										back();
									});
								}, function(error) {
									plus.nativeUI.alert("支付失败:" + error.code);
								});
							} else {
								alert("获取订单信息失败!");
							}
							break;
						default:
							break;
					}
				}
				xhr.open('GET', WXPAYSERVER);

				xhr.send();
			}
		}
	</script>

</html>

这样就能唤醒微信支付,同时完成付款了.

HBuilder打包的时候使用自有证书,同时保证签名与微信开放平台一致.

此处Appid与微信开放平台生成的一致:

HBuilder打包h5微信支付,最主要的问题就是HBuilder官网给的前端数据是有问题的.

下面是一些后端使用到的工具类;

生成sign签名:

package com.jixiu.user.utils;

import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;

import java.security.MessageDigest;
import java.util.*;

public class  EncodeSign {

    /**
     * sign 签名 (参数名按ASCII码从小到大排序(字典序)+key+MD5+转大写签名)
     * @param map
     * @return
     */
    public static String encodeSign(SortedMap<String,String> map, String key){
        if(StringUtils.isEmpty(key)){
            throw new RuntimeException("签名key不能为空");
        }
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Iterator<Map.Entry<String, String>> iterator = entries.iterator();
        List<String> values = Lists.newArrayList();

        while(iterator.hasNext()){
            Map.Entry entry = (Map.Entry) iterator.next();
            String k = String.valueOf(entry.getKey());
            String v = String.valueOf(entry.getValue());
            if (StringUtils.isNotEmpty(v) && entry.getValue() !=null && !"sign".equals(k) && !"key".equals(k)) {
                values.add(k + "=" + v);
            }
        }
        values.add("key="+ key);
        String sign = StringUtils.join(values, "&");
        System.out.println(sign+"计算之前的值");
        return MD5.MD5Encode(sign,"utf8").toUpperCase();
    }





}

调起支付接口需要的参数封装的实体类:

package com.jixiu.user.pojo;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


@Data
@Component
@ConfigurationProperties(prefix = "weixin")
@XmlAccessorType(XmlAccessType.FIELD)
//xml文件根标识
@XmlRootElement(name = "xml")
//控制JAXB绑定类中属性和字段的排序
@XmlType(propOrder = {
        "appid",
        "mch_id",
        "nonce_str",
        "body",
        "out_trade_no",
        "total_fee",
        "spbill_create_ip",
        "notify_url",
        "trade_type",
        "sign",
        "sign_type"
})
public class PlaceAnOrder {
    //应用id
    private String appid;
    //商户号
    private String mch_id;
    //随机字符串
    private String nonce_str;
    //商品描述
    private String body;
    //商户订单号
    private String out_trade_no;
    //总金额
    private String total_fee;
    //终端ip
    private String spbill_create_ip;
    //通知地址
    private String notify_url;
    //交易类型
    private String trade_type;
    //签名
    private String sign;
    //签名类型
    private String sign_type;


}

对象转XML字符串:

package com.jixiu.user.utils;


import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * 封装了XML转换成object,object转换成XML的代码
 *
 * @author Steven
 *
 */
public class XMLUtil {
    /**
     * 将对象直接转换成String类型的 XML输出
     *
     * @param obj
     * @return
     */
    public static String convertToXml(Object obj) {
        // 创建输出流
        StringWriter sw = new StringWriter();
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            // 将对象转换成输出流形式的xml
            marshaller.marshal(obj, sw);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return sw.toString();
    }

    /**
     * 将对象根据路径转换成xml文件
     *
     * @param obj
     * @param path
     * @return
     */
    public static void convertToXml(Object obj, String path) {
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            // 将对象转换成输出流形式的xml
            // 创建输出流
            FileWriter fw = null;
            try {
                fw = new FileWriter(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            marshaller.marshal(obj, fw);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    /**
     * 将String类型的xml转换成对象
     */
    public static Object convertXmlStrToObject(Class clazz, String xmlStr) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            // 进行将Xml转成对象的核心接口
            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader sr = new StringReader(xmlStr);
            xmlObject = unmarshaller.unmarshal(sr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }

    @SuppressWarnings("unchecked")
    /**
     * 将file类型的xml转换成对象
     */
    public static Object convertXmlFileToObject(Class clazz, String xmlPath) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            FileReader fr = null;
            try {
                fr = new FileReader(xmlPath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            xmlObject = unmarshaller.unmarshal(fr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }
}

java发送post请求:

public static String sendPost(String url, Map<String,Object> param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "application/json");
            //设置请求类型,注意第三方文档接口的要求,一定要保持一致
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            JSONObject jsonObject = new JSONObject(param);
            //配置
            jsonObject.put("grant_type", "client_credentials");
            jsonObject.put("client_id", "YXA6_9BOlrnhSWSb-FUk0fvzqw");
            jsonObject.put("client_secret", "YXA6FIe8F_euvzf-NosJ7nXCx-MMosk");
            out.print(jsonObject);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

结束.

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以实现HbuilderX 是一款集成开发环境,支持多种编程语言,包括 HTML、CSS、JavaScript、TypeScript、Vue、React、Node.js 等。可以用来开发 Web 应用、移动应用、桌面应用等。 ### 回答2: 利用HbuilderX可以实现各种跨平台开发,包括网页、微信小程序、App等。HbuilderX是一款集成了多种功能的开发工具,基于HTML5技术栈,可以进行前端开发、后端开发、移动端开发等。它提供了丰富的插件和模板,使开发人员可以更轻松地进行项目开发。 首先,HbuilderX可以用于开发网页。它支持HTML5、CSS3和JavaScript的开发,可以进行网站的搭建、页面的设计和交互效果的实现。借助插件和模板,可以快速进行页面开发,并且可以通过预览功能实时查看页面效果。 其次,HbuilderX也支持微信小程序的开发。通过HbuilderX的微信开发者工具插件,可以直接在HbuilderX中进行小程序的开发和调试。可以使用HTML、CSS和JavaScript编写小程序,同时兼具了原生小程序所拥有的各种特性和功能。 另外,HbuilderX还可以用于App的开发。它内置了Cordova插件,可以将H5应用封装成原生App,并发布到iOS和Android平台。借助HbuilderX的打包功能,可以方便地进行应用的打包和发布。 总之,利用HbuilderX可以进行各种跨平台开发,包括网页、微信小程序和App等。它提供了丰富的功能和工具,使得开发人员可以更便捷地进行项目开发,实现自己的创意和想法。 ### 回答3: 利用HbuilderX可以实现许多功能。HbuilderX是一款功能强大的集成开发环境(IDE),旨在支持开发者开发和调试多种技术栈的应用程序。通过HbuilderX,开发者可以使用HTML、CSS、JavaScript等前端语言来开发响应式的网页和移动应用。同时,HbuilderX还支持在同一个项目中集成多种框架,如Vue、React等,以便于开发者根据需求选择合适的框架进行开发。 利用HbuilderX,我们可以实现各种功能,包括但不限于: 1. 前端网页开发:可以使用HTML、CSS和JavaScript来设计和开发响应式的网页,并通过HbuilderX的调试功能进行实时调试和预览。 2. 移动应用开发:借助HbuilderX中的移动应用开发框架,如H5+等,开发者可以使用前端技术开发跨平台的移动应用,并针对不同的平台进行调试和发布。 3. 桌面应用开发:HbuilderX也支持开发桌面应用,开发者可以使用前端技术开发基于Electron等框架的跨平台桌面应用,从而在Windows、macOS和Linux等平台上运行应用程序。 4. 物联网应用开发:HbuilderX对于物联网应用开发也提供了支持,可以通过集成各种物联网协议和接口,实现设备连接和数据交互。 总而言之,利用HbuilderX,开发者可以使用前端技术和多种框架来实现各种功能,从网页开发到移动应用和桌面应用开发,乃至物联网应用开发,都可以通过HbuilderX来实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值