微信支付流程:
1、在页面点击支付发生的动作
将订单参数传递后台->后台根据订单参数以及微信相关信息->获取支付所需要的参数->后台处理支付所需要的参数返回给前端->前端获取到支付参数->发起支付请求->支付成功的页面会显示跳回商家所设置的回调路径->后台根据回调路径处理相关业务逻辑;
2、程序案例;从官网中下载相关API
页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>every thing will be will</title>
<script type="text/javascript" src="../static/js/jquery-3.3.1.min.js"></script>
</head>
<body>
<input type="button" value="进行微信支付" id="payId">
<script type="text/javascript">
$(function(){
var appId,timeStamp,nonceStr,package,signType,paySign;
$("#payId").click(function(){
pay();
});
//从后台获取参数
function pay(){=
$.get(url,function(result) {
appId = result.appId;
timeStamp = result.timeStamp;
nonceStr = result.nonceStr;
package = result.package;
signType = result.signType;
paySign = result.paySign;
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady',
onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady',
onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady',
onBridgeReady);
}
alert("请在微信上进行支付操作!");
onBridgeReady();
} else {
onBridgeReady();
}
});
}
//去微信那边发起支付请求
function onBridgeReady(){
alert("appId:"+appId+" "+"timeStamp:"+timeStamp+" "+"nonceStr:"+nonceStr+" "+"package:"+package+" "+"signType:"+signType+" "+"paySign:"+paySign+" ");
WeixinJSBridge.invoke( 'getBrandWCPayRequest', {
"appId":appId, //公众号名称,由商户传入
"timeStamp":timeStamp, //时间戳,自1970年以来的秒数
"nonceStr":nonceStr, //随机串
"package":package,
"signType":signType, //微信签名方式:
"paySign":paySign //微信签名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
//alert('支付成功');
console.log("支付成功");
//支付成功后跳转的页面
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
alert('支付取消');
}else if(res.err_msg == "get_brand_wcpay_request:fail"){
alert('支付失败');
alert(JSON.stringify(res));
WeixinJSBridge.call('closeWindow');
} //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
});
}
})
</script>
</body>
</html>
后台业务逻辑
所需的参数:
public class WxParam {
public final static String WX_APPID = "";//商家平台ID,微信平台
public final static String WX_BODY = ""; //商品描述
public final static String WX_MCH_ID = "";//商户ID ,微信平台
public final static String WX_NONCE_STR = "";//随机字符串,UUID
public final static String WX_OPEN_ID = "";//用户OPENID
public final static String WX_OUT_TRADE_NO = "";//商户订单号
public final static String WX_SPBILL_CREATE_IP = "";//终端IP,从请求头拿到
public final static String WX_TOTAL_FEE = "";//支付金额,单位是分
public final static String WX_TRADE_TYPE = "";//交易类型;JSAPI
public final static String WX_NOTIFY_URL = "";//通知地址;用户支付成功后,返回应用程序的接口;
public final static String WX_SIGN = "";//签名,根据上面10个参数计算获得
public final static String WX_PATERNERKEY = "";//商家密钥
}
前端所需参数的处理,以及回调路径
@Controller
@RequestMapping("/wxpay")
public class WxPayAction {
/**
* 订单采用微信支付所需的参数接口
* @param request
* @return
*/
@RequestMapping("/order")
@ResponseBody
public Map<String,String> orders(HttpServletRequest request){
try {
String openId = "用户的openid";
//存放微信支付所需的参数
final Map<String,String> paraMap = new HashMap<>();
// 获取请求ip地址
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.indexOf(",") != -1) {
String[] ips = ip.split(",");
ip = ips[0].trim();
}
String uuid = UUID.randomUUID().toString();
//
paraMap.put("appid",WxParam.WX_APPID);
paraMap.put("body","微信测试商品内容" );
paraMap.put("mch_id",WxParam.WX_MCH_ID );
paraMap.put("nonce_str",uuid );
paraMap.put("openid",openId );
paraMap.put("out_trade_no",UUID.randomUUID().toString().replaceAll("-", "") );//订单号
paraMap.put("spbill_create_ip",ip );//终端IP,从请求头拿到
paraMap.put("total_fee","1" );//支付金额,1分
paraMap.put("trade_type","JSAPI" );//支付类型
paraMap.put("notify_url","回调url" );
//这里的key是商家密钥;这一步将回调路径设置到sign参数里面了
String sign = WXPayUtil.generateSignedXml(paraMap,WxParam.WX_PATERNERKEY);
paraMap.put("sign",sign );
//将map转换为xml
String xml = WXPayUtil.mapToXml(paraMap);
// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
System.out.println("xml为:" + xml);
//预支付
String xmlStr = HttpRequestUtil.httpsRequest(unifiedorder_url, "POST", xml);
System.out.println("预支付返回的信息:"+xmlStr);
//上面的数据主要是为了获得预支付id;就相当于微信上提交订单(订单包含了回调函数),然后返回一个微信的订单id;
//以下内容返回前端页面的json数据
String prepay_id = "";//预支付id
if(xmlStr.indexOf("SUCCESS") != -1){
Map<String,String> map = WXPayUtil.xmlToMap(xmlStr);
prepay_id = (String) map.get("prepay_id");
}
Map<String,String> payMap = new HashMap<>();
payMap.put("appId",WxParam.WX_APPID );
//后面为什么要加""
payMap.put("timeStamp",WXPayUtil.getCurrentTimestamp()+"" );
payMap.put("nonceStr",WXPayUtil.generateNonceStr() );
payMap.put("signType","MD5" );
payMap.put("package","prepay_id="+prepay_id);
String paySin = WXPayUtil.generateSignature(payMap, WxParam.WX_PATERNERKEY);
payMap.put("paySign",paySin );
return payMap;
}catch (Exception e){
}
return null;
}
/**
* 回调函数,处理业务逻辑
* @param request
* * @param response
* * @return
*/
@RequestMapping("/notify")
public String wxCallBack(HttpServletRequest request, HttpServletResponse response){
InputStream is = null;
try{
is = request.getInputStream();
InputStreamReader isr=new InputStreamReader(is,"utf-8");
BufferedReader br=new BufferedReader(isr);
StringBuffer buffer=new StringBuffer();
String line=null;
while((line=br.readLine())!=null){
buffer.append(line);
}
//从流中获取
String xml = buffer.toString();
Map<String,String> notifyMap = WXPayUtil.xmlToMap(xml);
System.out.println("微信返回的回调函数信息:"+xml);
if(notifyMap.get("result_code").equals("SUCCESS")){
String ordersSn = notifyMap.get("out_trade_no");//商户订单号
String amountpaid = notifyMap.get("total_fee"); //实际支付金额
BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);// 将分转换成元-实际支付金额:元
/*
* 以下是自己的业务处理------仅做参考 更新order对应字段/已支付金额/状态码
*/
System.out.println("===notify===回调方法已经被调!!!");
}
// 告诉微信服务器收到信息了,回复微信服务器信息用流发送一个xml即可
response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
}catch (Exception e){
}finally {
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
用到的工具类
public class HttpRequestUtil {
/*
* 处理https GET/POST请求
* 请求地址、请求方法、参数
* */
public static String httpsRequest(String requestUrl,String requestMethod,String outputStr){
StringBuffer buffer=null;
try{
//创建SSLContext
SSLContext sslContext=SSLContext.getInstance("SSL");
TrustManager[] tm={new MyX509TrustManager()};
//初始化
sslContext.init(null, tm, new java.security.SecureRandom());;
//获取SSLSocketFactory对象
SSLSocketFactory ssf=sslContext.getSocketFactory();
URL url=new URL(requestUrl);
HttpsURLConnection conn=(HttpsURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod(requestMethod);
//设置当前实例使用的SSLSoctetFactory
conn.setSSLSocketFactory(ssf);
conn.connect();
//往服务器端写内容
if(null!=outputStr){
OutputStream os=conn.getOutputStream();
os.write(outputStr.getBytes("utf-8"));
os.close();
}
//读取服务器端返回的内容
InputStream is=conn.getInputStream();
InputStreamReader isr=new InputStreamReader(is,"utf-8");
BufferedReader br=new BufferedReader(isr);
buffer=new StringBuffer();
String line=null;
while((line=br.readLine())!=null){
buffer.append(line);
}
}catch(Exception e){
e.printStackTrace();
}
return buffer.toString();
}
}
public class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
}