微信支付之H5
申请用户授权
@GetMapping("/getWxAuthCode")
public String getWxAuthCode() throws UnsupportedEncodingException {
// 这里重定向到微信授权服务器
return "redirect:" + WxUtil.getWxAuthCode();
}
服务器接收到用户授权的Code
根据用户授权code获取用户的openid,跳转到服务统一下单地址
/**
* 根据授权码code 获取 用户的 opendId
*
* @param code 用户授权的code
* @param state 传参返回的
* @return 重定向到预支付地址
*/
@GetMapping("/wx‐oauth‐code‐return‐url")
public String wxOAuth2CodeReturn(@RequestParam String code, @RequestParam String state) {
//申请openid
ResponseEntity<String> exchange = new RestTemplate().exchange(WxUtil.getWxTokenURL(code), HttpMethod.GET, null, String.class);
String response = exchange.getBody();
String openid = JSONObject.parseObject(response).getString("openid");
//携带openid跳转至统一下单地址 return "redirect:http://xfc.nat300.top/transaction/wxjspay?openid=" + openid;
//携带openid跳转至统一下单地址
return "redirect:http://xfc.nat300.top/transaction/wxjspay?openid=" + openid;
}
统一下单地址请求微信服务器,发起预支付
==请求微信服务器形成预支付,得到微信服务器返回的预支付 “prepay_id”,把返回的请求与appid包装返回前端页面,在微信浏览器调起微信支付 ==
/**
* 统一下单接口
*
* @param openid 用户openid
* @return 返回下单界面,到微信客户端。然后调起微信客户端的JS-API调起微信支付
*/
@GetMapping("/wxjspay")
public ModelAndView wxjspay(@RequestParam String openid) {
try {
//微信支付渠道参数
// 构造微信预支付客户端
WXPay wxpay = new WXPay(WxUtil.getWXPayConfig(WxUtil.mchID));
//按照微信统一下单接口要求构造请求参数
// https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
Map<String, String> requestParam = new HashMap<String, String>();
//订单描述
requestParam.put("body", "iphone8");
//订单号
requestParam.put("out_trade_no", "1234567");
//人民币
requestParam.put("fee_type", "CNY");
//金额
requestParam.put("total_fee", String.valueOf(1));
//客户端ip
requestParam.put("spbill_create_ip", "127.0.0.1");
//微信异步通知支付结果接口,暂时不用
requestParam.put("notify_url", "none");
requestParam.put("trade_type", "JSAPI");
requestParam.put("openid", openid);
// 发起微信预支付
//调用微信统一下单API
Map<String, String> resp = wxpay.unifiedOrder(requestParam);
// 得到微信预支付响应参数
// 拼接微信响应参数到 H5 界面
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
Map<String, String> jsapiPayParam = new HashMap<>();
jsapiPayParam.put("appId", resp.get("appid"));
jsapiPayParam.put("package", "prepay_id=" + resp.get("prepay_id"));
jsapiPayParam.put("timeStamp", timestamp);
jsapiPayParam.put("nonceStr", UUID.randomUUID().toString());
jsapiPayParam.put("signType", "HMAC‐SHA256");
jsapiPayParam.put("paySign", WXPayUtil.generateSignature(jsapiPayParam, WxUtil.key, WXPayConstants.SignType.HMACSHA256));
log.info("微信JSAPI支付响应内容:" + jsapiPayParam);
// 返回H5 界面到浏览器
return new ModelAndView("wxpay", jsapiPayParam);
// 浏览器界面中调起JS-API进行支付
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
统一下单接口2 发起微信预支付
/**
* 统一下单接口2
*
* @param openid 用户openid
* @return 返回下单界面,到微信客户端。然后调起微信客户端的JS-API调起微信支付
*/
@GetMapping("/wxjspay2")
public ModelAndView wxjspay2(@RequestParam String openid, HttpServletRequest request) {
WxPayMpOrderResult payResult = null;
try {
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
// 订单编号规则 yyMMddHHmmss+userId
orderRequest.setOutTradeNo("11233321123");
orderRequest.setOpenid(openid);
orderRequest.setBody("手机");
// 元转成分
int fee = 0;
BigDecimal actualPrice =new BigDecimal("10");
fee = actualPrice.multiply(new BigDecimal(100)).intValue();
orderRequest.setTotalFee(fee);
// 设置设备
orderRequest.setSpbillCreateIp(IPUtil.getIpAddr(request));
// 根据商户id 和 秘钥请求预支付
payResult = WxUtil.getWXPayService("***", "**").createOrder(orderRequest);
// 返回H5 界面到浏览器
return new ModelAndView("wxpay", "payResult", payResult);
// 浏览器界面中调起JS-API进行支付
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
前端H5页面调起微信支付
H5页面发起微信支付并相应,支付成功或者失败
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta name="renderer" content="webkit">
<meta http-equiv="Expires" content="0">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>同步通知</title>
<script>
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId" : "${appId}", // 公众号名称,由商户传入
"timeStamp" : "${timeStamp}", // 时间戳,自1970年以来的秒数
"nonceStr" : "${nonceStr}", // 随机串
"package" : "${package}",
"signType" : "${signType}", // 微信签名方式:
"paySign" : "${paySign}" // 微信签名,paySign 采用统一的微信支付 Sign 签名生成方法,注意这里 appId 也要参与签名,appId 与 config 中传入的 appId 一致,即最后参与签名的参数有appId, timeStamp, nonceStr, package, signType。
},
function(res) {
if(res.err_msg == "get_brand_wcpay_request:ok" ) { // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
alert('支付成功!');
} else {
alert('支付失败:' + res.err_msg);
}
WeixinJSBridge.call('closeWindow');
}
);
}
if (typeof WeixinJSBridge == "undefined") {
if ( document.addEventListener ) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
</script>
</head>
<body>
<div id="app">
</div>
</body>
</html>
其他的一些工具类
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.github.wxpay.sdk.IWXPayDomain;
import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayConstants;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/**
* <p> 微信工具类 </p>
*
* @author: ZHT
* @create: 2021-03-25 09:25
**/
@Component
public class WxUtil {
/**
* appID 申请微信公众号时拥有
*/
public static String appID = "***";
/**
* 设置的商户id
*/
public static String mchID = "***";
/**
* 申请微信公众号时拥有
*/
public static String appSecret = "**";
/**
* API调用时的秘钥,保密,商户秘钥Key
*/
public static String key = "**";
/**
* 申请授权码地址
*/
public static String wxOAuth2RequestUrl = "https://open.weixin.qq.com/connect/oauth2/authorize";
/**
* 授权回调地址,此域名为前边设置的微信网页授权域名
*/
public static String wxOAuth2CodeReturnUrl = "http://xfc.nat300.top/transaction/wx‐oauth‐code‐return‐url";
/**
* 请求code的带参,微信申请授权code会传回来
*/
public static String state = "";
/**
* 根据商户id 获取微信支付配置
*
* @param mchID 商户id
* @return 微信支付配置
*/
public static WXPayConfig getWXPayConfig(String mchID) {
return new WXPayConfig() {
@Override
protected String getAppID() {
return appID;
}
@Override
protected String getMchID() {
return mchID;
}
@Override
protected String getKey() {
return key;
}
@Override
protected InputStream getCertStream() {
return null;
}
@Override
protected IWXPayDomain getWXPayDomain() {
return new IWXPayDomain() {
@Override
public void report(String s, long l, Exception e) {
}
@Override
public DomainInfo getDomain(WXPayConfig wxPayConfig1) {
return new DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
}
};
}
/**
* 微信授权码地址
*
* @return 微信授权码地址URL
* @throws UnsupportedEncodingException 地址转码失败
*/
public static String getWxAuthCode() throws UnsupportedEncodingException {
return String.format("%s?appid=%s&scope=snsapi_base&state=%s&redirect_uri=%s", wxOAuth2RequestUrl, appID, state, URLEncoder.encode(wxOAuth2CodeReturnUrl, "UTF-8"));
}
/**
* 获取微信openid地址
*
* @return 获取微信openid地址URL
*/
public static String getWxTokenURL(String code) {
return String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appID, appSecret, code);
}
/**
* 获取微信openid地址
* @param mchId 商户id
* @param mchKey 商户秘钥key
* @return 请求支付服务
*/
public static WxPayService getWXPayService(String mchId, String mchKey) {
WxPayService wxPayService = new WxPayServiceImpl();
WxPayConfig wxPayConfig = new WxPayConfig();
wxPayConfig.setAppId(appID);
wxPayConfig.setMchId(mchId);
wxPayConfig.setMchKey(mchKey);
wxPayConfig.setSignType("MD5");
wxPayConfig.setTradeType("JSAPI");
wxPayConfig.setNotifyUrl("");
wxPayConfig.setKeyPath("");
wxPayService.setConfig(wxPayConfig);
return wxPayService;
}
}