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前端进行的一些修改:
Hello MUI
这样就能唤醒微信支付,同时完成付款了.
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 map, String key){if(StringUtils.isEmpty(key)){throw new RuntimeException("签名key不能为空");}Set> entries = map.entrySet();Iterator> iterator = entries.iterator();List 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 {//应用idprivate String appid;//商户号private String mch_id;//随机字符串private String nonce_str;//商品描述private String body;//商户订单号private String out_trade_no;//总金额private String total_fee;//终端ipprivate 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);// 将对象转换成输出流形式的xmlmarshaller.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 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;}
结束.
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
