微信支付分很多种,其中微信H5支付是给在手机浏览器上使用,在手机上发起付款,自动跳转到微信并付款
微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
微信H5支付文档:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1
微信统一下单接口:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_1
微信H5支付流程:
1、用户在商户侧完成下单,使用微信支付进行支付
2、由商户后台向微信支付发起下单请求(调用统一下单接口)注:交易类型trade_type=MWEB
3、统一下单接口返回支付相关参数给商户后台,如支付跳转url(参数名“mweb_url”),商户通过mweb_url调起微信支付中间页
4、中间页进行H5权限的校验,安全性检查(此处常见错误请见下文)
5、如支付成功,商户后台会接收到微信侧的异步通知
6、用户在微信支付收银台完成支付或取消支付,返回商户页面(默认为返回支付发起页面)
7、商户在展示页面,引导用户主动发起支付结果的查询
8,9、商户后台判断是否接到收微信侧的支付结果通知,如没有,后台调用我们的订单查询接口确认订单状态
10、展示最终的订单支付结果给用户
支付部分代码:
代码语言:javascript复制 /**
* 微信H5支付2号方案
*/
@RequestMapping("/wapPay")
@ResponseBody
public net.sf.json.JSONObject pay(HttpServletRequest request, HttpServletResponse response, Integer userid, Double money, Integer num)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
net.sf.json.JSONObject json = new net.sf.json.JSONObject();
String ip = null;
//以下代码为获取请求的公网IP
//X-Forwarded-For:Squid 服务代理
String ipAddresses = request.getHeader("X-Forwarded-For");
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//Proxy-Client-IP:apache 服务代理
ipAddresses = request.getHeader("Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//WL-Proxy-Client-IP:weblogic 服务代理
ipAddresses = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//HTTP_CLIENT_IP:有些代理服务器
ipAddresses = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//X-Real-IP:nginx服务代理
ipAddresses = request.getHeader("X-Real-IP");
}
//有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
if (ipAddresses != null && ipAddresses.length() != 0) {
ip = ipAddresses.split(",")[0];
}
//还是不能获取到,最后再通过request.getRemoteAddr();获取
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ip = request.getRemoteAddr();
}
if (StrKit.isBlank(ip)) {
ip = "127.0.0.1";
}
int intMoney =(int)(money * 100);
//商户相关资料
String appid = "***";//公众号appid
String appsecret = "***";//公众号秘钥
String partner = "***";//商户号
String partnerkey = "***";//商户API秘钥
//用于获取随机数
String currTime = TenpayUtil.getCurrTime();//获取当前时间
String strTime = currTime.substring(8, currTime.length());//8位日期
String strRandom = TenpayUtil.buildRandom(4) "";//四位随机数
String strReq = strTime strRandom;//10位序列号,可以自行调整
String orderNo=appid userid Sha1Util.getTimeStamp();//随机生成了一个订单号
//商户号
String mch_id = partner;
//设备号 非必输
String device_info="WEB";
//随机数
String nonce_str = strReq;
//商品描述
String body = "号码筛选充值";
//附加数据
String attach = "shengyu";
//商户订单号
String out_trade_no = orderNo;
//总金额以分为单位,不带小数点
int total_fee = intMoney;
// String spbill_create_ip = request.getRemoteAddr();
String spbill_create_ip = ip;
String trade_type = "MWEB";//H5支付方式
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", appid);
packageParams.put("mch_id", mch_id);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", body);
packageParams.put("attach", attach);
packageParams.put("out_trade_no", out_trade_no);
packageParams.put("total_fee", String.valueOf((intMoney)));
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", notify_url);
packageParams.put("trade_type", trade_type);
RequestHandler reqHandler = new RequestHandler(request, response);
reqHandler.init(appid, appsecret, partnerkey);
//获取签名
String sign = reqHandler.createSign(packageParams);
String xml="<xml>"
"<appid>" appid "</appid>"
"<mch_id>" mch_id "</mch_id>"
"<nonce_str>" nonce_str "</nonce_str>"
"<sign>" sign "</sign>"
"<body>" body "</body>"
"<attach>" attach "</attach>"
"<out_trade_no>" out_trade_no "</out_trade_no>"
"<total_fee>" total_fee "</total_fee>"
"<spbill_create_ip>" spbill_create_ip "</spbill_create_ip>"
"<notify_url>" notify_url "</notify_url>"
"<out_trade_no>" orderNo "</out_trade_no>"
"<trade_type>" trade_type "</trade_type>"
"</xml>";
String allParameters = "";//没用
try {
allParameters = reqHandler.genPackage(packageParams);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//请求微信统一下单接口,成功后返回预支付交易会话标识prepay_id
String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String prepay_id = "";
String mweb_url="";
try {
Map<String ,String> returnmap= new GetWxOrderno().getPayNo(createOrderURL, xml);
prepay_id=returnmap.get("prepay_id");
mweb_url=returnmap.get("mweb_url");
if(prepay_id.equals("")){
json.put("msg","统一支付接口获取预支付订单出错");
return json;
}
//这里可以放增加订单信息
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//生成H5调起微信支付API相关参数(前端页面js的配置参数)
SortedMap<String, String> finalpackage = new TreeMap<String, String>();
String timestamp = Sha1Util.getTimeStamp();//当前时间的时间戳
String packages = "prepay_id=" prepay_id;;//订单详情扩展字符串
finalpackage.put("appId", appid);//公众号appid
finalpackage.put("timeStamp", timestamp);
finalpackage.put("nonceStr", strReq); //随机数
finalpackage.put("package", packages);
finalpackage.put("signType", "MD5");//签名方式
String finalsign = reqHandler.createSign(finalpackage);//签名
String returnurl_1="";
try {
returnurl_1=returnurl;
// 将普通字符创转换成application/x-www-from-urlencoded字符串
returnurl_1 = URLEncoder.encode(returnurl, "GBK");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
json.put("appId", appid);
json.put("timeStamp", timestamp);
json.put("nonceStr", strReq);
json.put("packages", packages);
json.put("sign", finalsign);
json.put("mweb_url", mweb_url "&redirect_url=" returnurl);// "&redirect_url=wap/rechargeSuccess.html"
return json;
}
/**
* 支付完成的回调,修改订单状态等
* @return
*/
@ResponseBody
@RequestMapping("/trueOrder")
public String notify(HttpServletRequest request, HttpServletResponse response)
throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
StringBuilder jsonStr = sb;
Map<String, Object> dataMap = new HashMap<String, Object>();
Map map = doXMLParse(jsonStr.toString());
String out_trade_no = (String) map.get("out_trade_no");//获取订单号
//下面是根据订单号修改订单状态、账户余额等
//返回,如果不加可能会请求多次
return "<xml>"
"<return_code><![CDATA[SUCCESS]]></return_code>"
"<return_msg><![CDATA[支付成功]]></return_msg>"
"</xml>";
}