微信支付之App支付
项目接入微信支付的准备工作:
- 注册成为开发者,进行资质认证,这里是需要300元的审核费用的;
- 在微信商户平台创建应用,提交等待审核(大致需要5-7个工作日);
- 应用审核通过之后,进入应用,开通微信支付,提交审核(大致需要2-3个工作日);
- 审核通过之后,微信会给注册的邮箱发送商户号,用户和密码等信息。
接入App支付的业务流程主要如下图所示:
接下来,就描述一下接入项目的详细步骤:
- 基础信息配置文件:WeiChartConfig.java
- 调用API接口的工具类:WeiChartUtil.java
- 对外接口:WeiChartController.java
WeiChartConfig.java
此文件主要配置接入微信支付需要的基础信息,例如:商户号、AppId、密钥、异步通知地址等信息,以及微信支付Api地址等信息。
import com.erenju.util.GlobleConfig; /**
* 微信支付基础信息配置
* 沙箱测试地址前边添加:sandboxnew 例如:https://api.mch.weixin.qq.com/sandboxnew/pay/orderquery
* @author rxn
* @date 2018/04/23
*
*/
public class WeiChartConfig { /**
* 预支付请求接口(统一下单)
*/
public static final String PrePayUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
// public static final String PrePayUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder"; /**
* 异步通知回调地址 ,外网可访问
*/
public static final String notify_url = GlobleConfig.getProperty("PayNotifyUrl")+"/wxpay/notify.json"; /**
* 查询订单地址
*/
public static final String OrderUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
// public static final String OrderUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/orderquery"; /**
* 关闭订单地址
*/
public static final String CloseOrderUrl = "https://api.mch.weixin.qq.com/pay/closeorder";
// public static final String CloseOrderUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/closeorder"; /**
* 申请退款地址
*/
public static final String RefundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
// public static final String RefundUrl = "https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/refund"; /**
* 查询退款地址
*/
public static final String RefundQueryUrl = "https://api.mch.weixin.qq.com/pay/refundquery";
// public static final String RefundQueryUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/refundquery"; /**
* 商户AppId
*/
public static final String AppId = "wx****************"; /**
* 商户号,10位数字
*/
public static final String MchId = "**********"; /**
* 商户密钥 (32位),正式环境和沙箱环境的商户密钥是不同的
*/
public static final String AppSercret = "*****";//正式
/**
* Api Key(32位)
*/
public static final String ApiKey = "*****"; /**
* 商品描述
*/
public static final String body = "****"; /**
* 退款需要证书文件,证书文件的地址
*/
public static final String refund_file_path = "";
}
WeiChartUtil.java
将业务逻辑和调用Api接口的逻辑分开写了,这样业务逻辑没有那么复杂,还增加了代码的复用率。
主要涉及的API如下图所示:(详细的API,请参考微信支付开放平台https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1)
package com.xhgx.web.pay.weiChart; import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set; import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element; import com.xhgx.util.HttpClientUtil;
import com.xhgx.util.StringUtil; import common.Logger; /**
* 微信支付调用API接口
* @author rxn
* @date 2018/04/23
*
*/
public class WeiChartUtil { public static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); public static Logger log = Logger.getLogger(WeiChartUtil.class); public static void main(String[] args) { Map map = new HashMap<>();
map.put("mch_id", WeiChartConfig.MchId);
map.put("nonce_str", getRandomString());
String sign = getSign(map);
map.put("sign", sign);
System.out.println(map.get("mch_id"));
System.out.println(map.get("nonce_str"));
System.out.println(sign); String string = HttpClientUtil.sendHttpPost("http://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey", map);
System.out.println(string);
} /**
* 请求获取预支付订单
* @param orderId 订单id
* @param totalFee 总金额(单位:分)
* @return
*/
public static Map<String, Object> getPrepayOrderInfo(String orderId,String totalFee){
Map<String, Object> m = new HashMap<String, Object>();
try {
for(int i=0;i<1;i++){
if(StringUtil.isEmpty(orderId)){
m.put("code", -1);
m.put("message", "订单号不能为空");
break;
}
if(Double.parseDouble(totalFee)<=0){
m.put("code", -1);
m.put("message", "订单金额有误");
break;
} Map<String,String> resultMap = getPreyId(orderId, totalFee, "义龙出行"); System.out.println("resultMap:"+resultMap); String return_code = resultMap.get("return_code");//返回状态码
String return_msg = resultMap.get("return_msg");//返回信息
//签名失败
/*if(!StringUtil.isEmpty(return_msg)){
m.put("code", -1);
m.put("message", return_msg);
break;
}*/ if("SUCCESS".equals(return_code)){
// String appid = resultMap.get("appid");//应用APPID
String mch_id = resultMap.get("mch_id");//商户号
// String device_info = resultMap.get("device_info");//设备号
String nonce_str = resultMap.get("nonce_str");//随机字符串
String sign = resultMap.get("sign");//签名
String result_code = resultMap.get("result_code");//业务结果 if("SUCCESS".equals(result_code)){
String trade_type = resultMap.get("trade_type");//交易类型:APP
String prepay_id = resultMap.get("prepay_id");//预支付交易会话标识,有效期为两个小时 //重新生成sign
Map<String,String> signMap = new HashMap<String,String>();
String timeStamp = getTenTimes();
// signMap.put("appid", appid);
signMap.put("appid", WeiChartConfig.AppId);
signMap.put("partnerid", mch_id);
signMap.put("prepayid", prepay_id);
signMap.put("package", "Sign=WXPay");
signMap.put("noncestr", nonce_str);
signMap.put("timestamp", timeStamp);//时间戳:10位 String newSign = getSign(signMap);
// System.out.println("String:"+newSign);
System.out.println(creatXml(signMap));
m.put("sign", newSign);
// m.put("sign", sign);
m.put("appid", WeiChartConfig.AppId);
m.put("mch_id", mch_id);
m.put("nonce_str", nonce_str);
m.put("trade_type", trade_type);
m.put("prepay_id", prepay_id);
m.put("package", "WXPay");
m.put("timestamp", timeStamp); m.put("code", 0);
m.put("message", "请求成功");
break;
}else{
String err_code = resultMap.get("err_code");//错误代码
String err_code_des = resultMap.get("err_code_des");//错误代码描述 m.put("code", -1);
m.put("err_code", err_code);
m.put("message", err_code_des);
break;
} }else{
m.put("code", -1);
m.put("message", "请求失败");
break;
} }
} catch (Exception e) {
e.printStackTrace();
m.put("code", -1);
m.put("message", "程序异常");
}
return m;
} /**
* 统一下单
* @param orderId 订单id
* @param totalFee 总金额(分)
* @param schoolLabel
* @return
*/
public static Map<String, String> getPreyId(String orderId,String totalFee,String schoolLabel){
Map<String,String> m = new HashMap<String,String>();
m.put("appid", WeiChartConfig.AppId);//应用id
m.put("body", "【"+schoolLabel+"】"+WeiChartConfig.body);//商品描述
m.put("mch_id", WeiChartConfig.MchId);//商户号
m.put("nonce_str", getRandomString());//随机字符串
m.put("notify_url", WeiChartConfig.notify_url);//通知地址
m.put("out_trade_no", orderId);//订单号
m.put("spbill_create_ip", getHostIp());//用户端实际ip
Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR_OF_DAY, 2);//有效时间
m.put("time_expire", sdf.format(cal.getTime()));//交易结束时间,非必填
Calendar cal1 = Calendar.getInstance();
m.put("time_start", sdf.format(cal1.getTime()));//交易起始时间,非必填
// m.put("total_fee", totalFee);//总金额
m.put("total_fee", 1+"");//总金额
m.put("trade_type", "APP");//交易类型
m.put("sign", getSign(m));//签名 String reqStr = creatXml(m);
String retStr = HttpClientUtil.postHtpps(WeiChartConfig.PrePayUrl, reqStr); System.out.println("微信调起统一下单接口返回结果:"+retStr);
return getInfoByXml(retStr);
} /**
* 查询订单
* @param orderId
* @return
*/
public static Map<String, String> getOrder(String orderId){
Map<String, String> m = new HashMap<String,String>();
m.put("appid", WeiChartConfig.AppId);
m.put("mch_id", WeiChartConfig.MchId);
m.put("nonce_str", getRandomString());
m.put("out_trade_no", orderId);//商户订单号
m.put("sign", getSign(m)); String reqStr = creatXml(m);
String retStr = HttpClientUtil.postHtpps(WeiChartConfig.OrderUrl, reqStr);
return getInfoByXml(retStr);
} /**
* 关闭订单
* @param orderId
* @return
*/
public static Map<String, String> closeOrder(String orderId){
Map<String, String> m = new HashMap<String,String>();
m.put("appid", WeiChartConfig.AppId);
m.put("mch_id", WeiChartConfig.MchId);
m.put("out_trade_no", orderId);//商户订单号
m.put("nonce_str", getRandomString());
m.put("sign", getSign(m)); String reqStr = creatXml(m);
String retStr = HttpClientUtil.postHtpps(WeiChartConfig.CloseOrderUrl, reqStr);
return getInfoByXml(retStr);
} /**
* 退款
* @param orderId 订单号
* @param refundId 退款单号
* @param totalFee 订单金额(分)
* @param refundFee 退款金额(分)
* @return
*/
public static Map<String, String> refund(String orderId,String refundId,String totalFee,String refundFee){
Map<String, String> m = new HashMap<String,String>();
m.put("appid", WeiChartConfig.AppId);
m.put("mch_id", WeiChartConfig.MchId);
m.put("nonce_str", getRandomString());
m.put("out_trade_no", orderId);//商户订单号
m.put("out_refund_no", refundId);//退款单号
m.put("total_fee", totalFee);//订单金额
m.put("refund_fee", refundFee);//退款金额
m.put("sign", getSign(m)); String reqStr = creatXml(m);
String retStr = "";
try {
retStr = HttpClientUtil.postHttplientNeedSSL(WeiChartConfig.RefundUrl, reqStr, WeiChartConfig.refund_file_path, WeiChartConfig.MchId);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
return getInfoByXml(retStr);
}
/**
* 查询退款
* @param orderId
* @return
*/
public static Map<String, String> getOrderRefundQueryInfo(String orderId){
Map<String,String> m = new HashMap<String,String>();
m.put("appid", WeiChartConfig.AppId);
m.put("mch_id", WeiChartConfig.MchId);
m.put("nonce_str", getRandomString());
m.put("out_trade_no", orderId);//订单号
m.put("sign", getSign(m)); String reqStr = creatXml(m);
String retStr = HttpClientUtil.postHtpps(WeiChartConfig.RefundQueryUrl, reqStr);
return getInfoByXml(retStr);
} /**
* 得到随机字符串
*
* @param length
* @return
*/
public static String getRandomString() {
int length = 32;
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; ++i) {
int number = random.nextInt(62);// [0,62)
sb.append(str.charAt(number));
}
return sb.toString();
} /**
* 得到本地机器的IP
*
* @return
*/
private static String getHostIp() {
String ip = "";
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return ip;
}
/**
* 生成为头为XML的xml字符串,例如:<xml><key>123</key></xml>
* @param reqMap
* @return
*/
public static String creatXml(Map<String, String> reqMap){
Set<String> set = reqMap.keySet();
StringBuffer b = new StringBuffer();
b.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
b.append("<xml>");
for(String key : set){
b.append("<"+key+">").append(reqMap.get(key)).append("</"+key+">");
}
b.append("</xml>");
return b.toString();
} /**
* 生成签名
*
* @param map
* @return
*/
public static String getSign(Map<String, String> map) {
String[] keys = map.keySet().toArray(new String[0]);
Arrays.sort(keys);
StringBuffer reqStr = new StringBuffer();
for (String key : keys) {
String v = map.get(key);
if (v != null && !v.equals("")) {
reqStr.append(key).append("=").append(v).append("&");
}
}
reqStr.append("key").append("=").append(WeiChartConfig.ApiKey); return getMd5ByOrder(reqStr.toString()).toUpperCase();
} /**
* 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
* @return boolean
*/
public static boolean isTenpaySign(Map<String, String> map) { String sign = map.get("sign");//获取微信返回的sign,进行比较
map.remove("sign");//生成签名时,去除sign String[] keys = map.keySet().toArray(new String[0]);
Arrays.sort(keys);
StringBuffer reqStr = new StringBuffer();
for (String key : keys) {
String v = map.get(key);
if (v != null && !v.equals("")) {
reqStr.append(key).append("=").append(v).append("&");
}
}
reqStr.append("key").append("=").append(WeiChartConfig.ApiKey); //算出摘要
String mysign = getMd5ByOrder(reqStr.toString()).toLowerCase();
String tenpaySign = sign.toLowerCase(); // System.out.println(tenpaySign + " " + mysign);
return tenpaySign.equals(mysign);
} /**
* 解析xml
*
* @param xmlStr
* @return
*/
public static Map<String, String> getInfoByXml(String xmlStr) {
try {
Map<String, String> m = new HashMap<String, String>();
Document d = DocumentHelper.parseText(xmlStr);
Element root = d.getRootElement();
for (Iterator<?> i = root.elementIterator(); i.hasNext();) {
Element element = (Element) i.next();
String name = element.getName();
if (!element.isTextOnly()) {
// 不是字符串 跳过。确定了微信放回的xml只有根目录
continue;
} else {
m.put(name, element.getTextTrim());
}
}
Map<String,String> map = new HashMap<String,String>();
map.putAll(m);
// 对返回结果做校验.去除sign 字段再去加密
String retSign = m.get("sign");
m.remove("sign");
String rightSing = getSign(m);
if (rightSing.equals(retSign)) {
return map;
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
} /**
* 获取10位的时间戳
* @return
*/
public static String getTenTimes(){
String time = System.currentTimeMillis()+"";
return time.substring(0, time.length()-3);
}
/**
* 将文本转排序后,换成MD5加密后的字符串
* @param s
* @return
* @author Rxn
* @date 2018-05-08
*/
public static String getMd5ByOrder(String s){
MessageDigest md;
StringBuilder sStringBuilder = new StringBuilder();
try {
md = MessageDigest.getInstance("MD5");
md.reset();
try {
md.update(s.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
byte[] digest = md.digest();
sStringBuilder.setLength(0); for (int i = 0; i < digest.length; ++i) {
int b = digest[i] & 255;
if (b < 16) {
sStringBuilder.append('0');
} sStringBuilder.append(Integer.toHexString(b));
} return sStringBuilder.toString().toUpperCase(); } catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} return null;
}
}
WeiChartController.java
这里主要涉及一些业务处理,代码中我主要粘了对外的异步通知接口(主要作用是App支付成功后,会有一个支付成功的返回信息告知商户),其他需要的接口已经在WeiChartUtil.java中处理过了,直接调用即可。
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.xhgx.util.StringUtil;
import com.xhgx.web.SpringContextUtil;
import common.Logger; /**
*
* @author rxn
* @data 2018/05/03
*
*/
@Controller
public class WeiChartController{ public static Logger log = Logger.getLogger(WeiChartController.class); public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static SimpleDateFormat ymdhms = new SimpleDateFormat("yyyyMMddHHmmss"); /**
* 异步通知,回调方法
* @param request
* @param response
* @throws IOException
*/
@ResponseBody
@RequestMapping("/wxpay/notify.json")
public static void getNotifyInfo(HttpServletRequest request, HttpServletResponse response) throws IOException{
System.out.println("微信APP异步通知,回调方法");
//读取参数
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(); String reqStr = new String(sb);
//将xml解析成map
Map<String, String> reqMap = WeiChartUtil.getInfoByXml(reqStr); //过滤空
Map<String,String> paramMap = new HashMap<String,String>();
Iterator it = reqMap.keySet().iterator();
while (it.hasNext()) {
String name = (String) it.next();
String value = reqMap.get(name); String v = "";
if(value!=null){
v = value.trim();
}
paramMap.put(name, v);
} String resXml="";//响应数据
//创建一个对象,保存通知信息,可以根据业务需求自己定义
PayNotifyTbl payNotifyTbl = new PayNotifyTbl();
payNotifyTbl.setPay_type(1);//支付类型: 1微信 2支付宝
payNotifyTbl.setCreate_dt(new Date());
//验证签名
if(WeiChartUtil.isTenpaySign(paramMap)){
String return_code = paramMap.get("return_code");//返回状态码
String return_msg = paramMap.get("return_msg");//返回信息
String result_code = paramMap.get("result_code");
String err_code = paramMap.get("err_code");
String err_code_des = paramMap.get("err_code_des"); payNotifyTbl.setReturn_code(return_code);
payNotifyTbl.setReturn_msg(return_msg);
payNotifyTbl.setResult_code(result_code);
payNotifyTbl.setErr_code(err_code);
payNotifyTbl.setErr_code_des(err_code_des); if("SUCCESS".equals(return_code)&&"SUCCESS".equals(result_code)){
String appid = paramMap.get("appid");
String mch_id = paramMap.get("mch_id");
String openid = paramMap.get("openid");
String trade_type = paramMap.get("trade_type");
String total_fee = paramMap.get("total_fee");//单位:分
String transaction_id = paramMap.get("transaction_id");//微信支付订单号
String out_trade_no = paramMap.get("out_trade_no");//商户订单号
String time_end = paramMap.get("time_end");//支付完成时间 payNotifyTbl.setAppid(appid);
payNotifyTbl.setOpenid(openid);
payNotifyTbl.setOrder_id(out_trade_no);
payNotifyTbl.setTrade_type(trade_type);
payNotifyTbl.setTotal_fee(Double.parseDouble(total_fee)/100.00);
payNotifyTbl.setTransaction_id(transaction_id);
try {
payNotifyTbl.setTime_end(sdf.format(ymdhms.parse(time_end)));
} catch (ParseException e) {
e.printStackTrace();
} //业务处理,查询订单
OrderTbl order = orderTblService.get(Integer.parseInt(out_trade_no));
//安全起见,添加金额作比较
if(!WeiChartConfig.MchId.equals(mch_id) || order==null || Double.parseDouble(total_fee)/100!=getIntRound(order.getPrice().doubleValue()){
payNotifyTbl.setPay_result("参数错误");
log.info("支付失败,错误信息:" + "参数错误");
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[参数错误]]></return_msg>" + "</xml> ";
}else{
if(order.getOrder_status()==7){
//逻辑处理,支付完成,修改订单状态
order.setOrder_status(OrderStatus.STEP_08.getNodeId());//订单完成
order.setTotal_price(Double.parseDouble(total_fee)/100);//支付费用
order.setPay_way(1);//微信支付
order.setPay_time(new Date());//支付时间
order = ycOrderTblService.save(order); payNotifyTbl.setPay_result("支付成功");
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
}else{
payNotifyTbl.setPay_result("订单已经被处理");
log.info("订单已经被处理");
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} } }else{
payNotifyTbl.setPay_result(paramMap.get("return_msg"));
log.info("微信支付异步通知返回的错误信息:"+paramMap.get("return_msg"));
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
} }else{
payNotifyTbl.setPay_result("微信支付异步通知签名验证失败");
log.info("微信支付异步通知签名验证失败");
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[通知签名验证失败]]></return_msg>" + "</xml> ";
} if(payNotifyTblService==null){
payNotifyTblService= (PayNotifyTblService) SpringContextUtil.getBean(PayNotifyTblService.class);
} payNotifyTbl = payNotifyTblService.save(payNotifyTbl);
//返回微信支付系统告知成功接收
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} }
在接入微信支付时,入了很多坑,特别注意:生成签名时传入参数的顺序,不同的顺序会导致生成的签名与微信返回的签名不一致。尤其注意调用统一下单接口后,重新生成签名的顺序,一定要按照appid,partnerid,prepayid,noncestr,timestamp,package的顺序,否则App会调起支付页面失败,报签名异常的错误。另外注意:异步通知地址一定是外网可以访问的,而且和微信平台上配置的异步通知地址一致。
微信支付之App支付的更多相关文章
- asp.net core 微信扫码支付(扫码支付,H5支付,公众号支付,app支付)之1
2018-08-13更新生成二维码的方法 在做微信支付前,首先要了解你需要什么方式的微信支付,目前本人做过的支付包含扫码支付.H5支付.公众号支付.App支付等,本人使用的是asp.net mvc c ...
- 微信支付(APP支付)-服务端开发(一)
微信支付,首先需要注册一个商户平台公众账号,(网址:https://pay.weixin.qq.com/index.php/home/d_login) 目前微信支付的接入方式有四种方式:公众号支付,A ...
- 微信、支付宝App支付-JPay0.0.2发布
JPay 对微信App支付.支付宝App支付的二次封装,对外提供一个相对简单的接口以及支付结果的回调 GitHub:https://github.com/Javen205/JPay OsChina:h ...
- asp.net core 微信APP支付(扫码支付,H5支付,公众号支付,app支付)之4
微信app支付需要以下参数,类封装如下 public class WxPayModel { /// <summary> /// 应用ID /// </summary> publ ...
- uni-app - 支付(app支付、小程序支付、h5(微信端)支付)
App支付.小程序支付.h5(微信端)支付 APP支付(内置) appPay.js /** * 5+App支付,仅支持支付宝以及微信支付 * * 支付宝Sdk集成,微信sdk未集成 * * @para ...
- 微信JSAPI 公众号支付 H5支付以及APP支付 WEBAPI接口开发测试
统一下单入口 调用该方法入口: public void WxPayAPI() { //string PayPrice ="99.9"; ////订单号 //string Payor ...
- ThinkPHP 5 整合支付宝微信支付(支付宝H5,微信H5、APP支付、公众号支付)
因项目没有PC站所以没有写电脑网站支付. Pay.php支付控制器 <?php // +----------------------------------------------------- ...
- php支付走过的坑(微信篇 包含h5支付和app支付 注册 秘钥 环境等等配置)
支付这东西,说容易也容易,说难也难 代码这玩意还比较好说 但是 如果没有demo 直接去看官方文档 十有八九一脸懵逼 今天就整理一下 支付这块走过的坑 涉及 微信h5支付 支付宝h5支付 (api文档 ...
- asp.net core 微信公众号支付(扫码支付,H5支付,公众号支付,app支付)之3
在微信公众号中访问手机网站,当需要调用支付时候无法使用H5支付,只有使用微信公众号支付,使用公众号支付用户必须关注该公众号同时该公众号必须开通公众号支付功能. 1.获取用户的OpenId ,参考之前写 ...
随机推荐
- HTTP中Post与Put的区别
PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同. POST请求 ...
- weblogic的基础安装
安装java环境 不能使用centos自带的openjdk 必须使用源码安装 把下载的jdk-8u181-linux-x64.tar 解压到 /usr/src目录下 tar zxvf jd ...
- 学号 20175201张驰 《Java程序设计》第5周学习总结
学号 20175201张驰 <Java程序设计>第5周学习总结 教材学习内容总结 第六章 ·1.接口的接口体中只可以有常量和abstract方法. ·2.和类一样,接口也是Java中一种重 ...
- eclipse中tomcat的add and Remove找不到项目
在我们运行项目前,都需要将项目部署到tomcat上,但是有时我们会遇到这种情况:项目明明存在,但是eclipse中tomcat的add and remove找不到项目,无法部署,那么这个问题该如何解决 ...
- FG面经: Interval问题合集
How to insert interval to an interval list. List is not sorted O(N) solution: package fb; import jav ...
- windows----------Windows10 远程桌面连接失败,报CredSSP加密oracle修正错误解决办法
1.通过运行gpedit.msc进入组策略配置(需要win10专业版,家庭版无解),策略路径:“计算机配置”->“管理模板”->“系统”->“凭据分配”,设置名称: 加密 Oracl ...
- beego 初体验 - 上传文件
页面: controller: 将form表单文件上传到本地,并保存.
- dede织梦手机站m文件夹功能基础详解
织梦2015年6月8日更新后,就添加了很多针对手机移动端的设计,最大的设计就是添加了生成二维码的织梦标签和织梦手机模板功能,织梦更新后,默认的 default模板中就包含手机模板,所以我们可以给织梦网 ...
- centos7 安装 redis-4.0.9
下载地址:https://redis.io/download 下载 安装: $ wget http://download.redis.io/releases/redis-4.0.9.tar.gz $ ...
- spring-boot 参考链接
http://blog.csdn.net/jsu_9207/article/details/66472096 http://blog.csdn.net/lu1005287365/article/det ...