前提条件
1.已经开通微信支付和认证成功的微信服务号2.微信商户号的支付秘钥(而不是支付密码)3.微信公众号的秘钥。
配置步骤
一、APPID账号关联(绑定公众号)1. 登录商户平台-产品中心-账号关联(AppID绑定),进入授权申请页面;2.填写相关已认证APPID信息,阅读并签署《微信支付商户号与APPID授权协议》,点击“确认”提交,发起授权申请;3. 发起授权申请后,商户需自行前往对应平台确认授权申请。二、公众号配置网页授权域名1.登录微信公众平台--公众号设置--功能设置,设置网页授权域名2.用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回调页面,回调页面需在此域名下,以确保安全可靠。
三、微信商户设置支付配置,1、商户最后请求拉起微信支付收银台的页面地址我们称之为“支付目录2、商户实际的支付目录必须和在微信支付商户平台设置的一致,否则会报错“当前页面的URL未注册:”登录微信支付商户平台(pay.)-->产品中心-->开发配置,设置后一般5分钟内生效。
开发流程
1、每一个功能都要先以官方文档为准,这里我们先看下官方是怎么说的。官方文档:微信支付官方文档
我们只考虑必要的参数,如下
appid APPID (微信公众号平台查看)
mch_id 商户ID (微信商户号查看)
nonce_str 随机字符串(调用WXPayUtil.generateNonceStr()方法即可)
sign 签名
body 所支付的名称(支付的名称)
out_trade_no 订单号,需要唯一(自定义,不能重复)
total_fee 支付金额(金额,以分为单位,后面需要乘以100)
spbill_create_ip IP地址(IP地址,我这里是前端传过来的)
notify_url 回调地址(支付成功后,微信会带着参数请求这个地址,用于处理金额的变化等等)
trade_type 支付类型(这里是JSAPI)
openid 支付人的微信公众号对应的唯一标识(获取用户的唯一标识,属于获取用户信息的范畴,如何获取这里不多做介绍,网上有很多教程)
关键代码:
我这里是首先把微信支付的参数组合起来
//获取订单号,我这里是随机数+手机号保存的
String outTradeNo = “3” + WXPayUtil.getCurrentTimestampMs() + “” + phoneNumber;
//获取随机字符串
String nonce_str = WXPayUtil.generateNonceStr();
StringBuilder sBuilder = new StringBuilder();
sBuilder.append(“appid=”).append(appid).append("&");
sBuilder.append(“body=”).append(body).append("&");
sBuilder.append(“mch_id=”).append(mchId).append("&");
sBuilder.append(“nonce_str=”).append(nonce_str).append("&");
sBuilder.append(“notify_url=”).append(notifyUrl).append("&");
sBuilder.append(“openid=”).append(openid).append("&");
sBuilder.append(“out_trade_no=”).append(outTradeNo).append("&");
sBuilder.append(“spbill_create_ip=”).append(spbillCreateIP).append("&");
sBuilder.append(“total_fee=”).append(rechargeMoney * 100).append("&");
sBuilder.append(“trade_type=”).append(weChatBase.getTradeType()).append("&");
sBuilder.append(“key=”).append(weChatBase.getMchKey());
try {
//调用WXPayUtil.MD5进行加密
signResult = WXPayUtil.MD5(sBuilder.toString()).toUpperCase();
}
catch (Exception e) {
e.printStackTrace();
}
// 组装包含openid用于请求统一下单返回结果的XML
StringBuilder sb = new StringBuilder("");
sb.append("");
setXmlKV(sb, “appid”, appid);
setXmlKV(sb, “body”, body);
setXmlKV(sb, “mch_id”, mchId);
setXmlKV(sb, “nonce_str”, nonce_str);
setXmlKV(sb, “notify_url”, notifyUrl);
setXmlKV(sb, “openid”, openid);
setXmlKV(sb, “out_trade_no”, outTradeNo);
setXmlKV(sb, “spbill_create_ip”, spbillCreateIP);
setXmlKV(sb, “total_fee”, rechargeMoney * 100 + “”);
setXmlKV(sb, “trade_type”, “JSAPI”);
setXmlKV(sb, “sign”, signResult);
sb.append("");
logger.info(“统一下单请求:” + sb);
HttpPost httppost = new HttpPost(“https://api.mch./pay/unifiedorder”);
StringEntity reqEntity;
String strResult = “”;
try {
reqEntity = new StringEntity(new String(sb.toString().getBytes(“UTF-8”), “ISO8859-1”));
httppost.setEntity(reqEntity);
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse response = httpclient.execute(httppost);
strResult = EntityUtils.toString(response.getEntity(), Charset.forName(“utf-8”));
}
catch (Exception e) {
e.printStackTrace();
}
//把前端所需要的参数封装成一个类,返回过去,这里调用了getPayMap方法
Map < String, Object > map =getPayMap(strResult, appid, mchKey);;
wxPayMentResponse.setNoncestr((String) map.get(“nonceStr”));
wxPayMentResponse.setSignType(“MD5”);
wxPayMentResponse.setTimestamp((String) map.get(“timeStamp”));
wxPayMentResponse.setPaySign((String) map.get(“paySign”));
wxPayMentResponse.setPrepayid(“prepay_id=” + (String) map.get(“prepay_id”));
commonResponse.setCode(200);
commonResponse.setMsg(“申请支付成功”);
commonResponse.setData(wxPayMentResponse);
由于支付界面是由前端完成的,所以我们需要把一些数据返回给前端,查看官方文档
1、appId:APPID;
2、timestamp:时间戳(System.currentTimeMillis()获取)
3、 nonceStr:随机字符串,再次用WXPayUtil中的generateNonceStr()即可;
4、 package:用到了prepay_id,
5、 signType:MD5
6、 paySign:其他5个参数放到map中,key是四大配置参数中的API秘钥(paternerKey),得到了paySign后,不要忘记再将paySign put到只有5个参数的map中,这样才能凑齐最后的第6个参数。
public static Map < String, Object > getPayMap(String prePayInfoXml, String id, String key) {
Map < String, Object > map = new HashMap < String, Object >();
String prepay_id = getXmlPara(prePayInfoXml, “prepay_id”);// 统一下单返回xml中prepay_id
String timeStamp = String.valueOf((System.currentTimeMillis() / 1000));// 1970年到现在的秒数
String nonceStr = getXmlPara(prePayInfoXml, “nonce_str”);// 随机数据字符串
String packageStr = “prepay_id=” + prepay_id;
String signType = “MD5”;
String paySign = “appId=” + id + “&nonceStr=” + nonceStr + “&package=prepay_id=” + prepay_id + “&signType=”
+ signType + “&timeStamp=” + timeStamp + “&key=” + key;// 注意这里的参数要根据ASCII码
// 排
try {
paySign = WXPayUtil.MD5(paySign).toUpperCase();
}
catch (Exception e) {
e.printStackTrace();
} // 将数据MD5加密
map.put(“appId”, id);
map.put(“timeStamp”, timeStamp);
map.put(“nonceStr”, nonceStr);
map.put(“packageStr”, packageStr);
map.put(“signType”, signType);
map.put(“paySign”, paySign);
map.put(“prepay_id”, prepay_id);
logger.info(“微信支付map为*****:”+JsonUtil.Object2Json(map));
return map;
}
/**
* 解析XML 获得名称为para的参数值
*/
public static String getXmlPara(String xml, String para) {int start = xml.indexOf("<" + para + ">");int end = xml.indexOf("</" + para + ">");if (start < 0 && end < 0) {return null;}return xml.substring(start + ("<" + para + ">").length(), end).replace("<![CDATA[", "").replace("]]>", "");}
到这里微信支付后端部分已经完成了,下面就是处理充值完成后的对金额的一些处理。