微信支付介面開發_支付寶介面開發_銀行支付通道_企業對私低費率
阿新 • • 發佈:2019-01-01
1.準備工作
首先登入微信公眾平臺,獲取並配置以下微信開發配置:
- 開發者ID【AppID和AppSecret】
- 伺服器配置
1.url伺服器地址設定
2.Token【自己設定,必須英文或數字】
3.EncodingAESKey[自己隨機生成,用於訊息加解密]
然後登入微信商戶平臺,獲取並配置以下微信支付配置:
- 商戶號(mchId)
- API祕鑰(key)
- API證書(java版主要使用:apiclient_cert.p12)
PS:需要微信公眾號支付銀行對私介面,請聯絡電話/微信17605918869
2.程式碼展示
提醒:此處粘貼出的程式碼為方便初學者比較直觀的瞭解、學習微信公眾號支付,部分程式碼並未按照編碼規範封裝成方法、工具類
將微信支付所有引數定義為 WeChatConfig.java
public classWeChatConfig{
/**公眾號AppId*/
public static final APP_ID = "";
/**公眾號AppSecret*/
public static final APP_SECRET = "";
/**微信支付商戶號*/
public static final String MCH_ID = "";
/**微信支付API祕鑰*/
public static final String KEY = "";
/**微信支付api證書路徑*/
public static final String CERT_PATH = "***/apiclient_cert.p12";
/**微信統一下單url*/
public static final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**微信申請退款url*/
public static final String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
/**微信支付通知url*/
public static final String NOTIFY_URL = "此處url用於接收微信伺服器傳送的支付通知,並處理商家的業務";
/**微信交易型別:公眾號支付*/
public static final String TRADE_TYPE_JSAPI = "JSAPI";
/**微信交易型別:原生掃碼支付*/
public static final String TRADE_TYPE_NATIVE = "NATIVE";
/**微信甲乙型別:APP支付*/
public static final String TRADE_TYPE_APP = "APP";
}
處理微信公眾號支付請求的Controller:WeChatOrderController.java
@RequestMapping(value="/m/weChat/")
@Controller("weChatOrderController")
public classWeChatOrderController{
@Autowired
private OrderService orderService;
@Autowired
private WechatPayService wechatPayService;
@Autowired
private NotifyReturnService notifyReturnService;
@RequestMapping(value = "unifiedOrder")
public String unifiedOrder(HttpServletRequest request,Model model){
//使用者同意授權,獲得的code
String code = request.getParameter("code");
//請求授權攜帶的引數【根據自己需要設定值,此處我傳的是訂單id】
String state = request.getParameter("state");
Order order = orderService.get(state);//訂單資訊
//通過code獲取網頁授權access_token
AuthToken authToken = WeChatUtils.getTokenByAuthCode(code);
//構建微信統一下單需要的引數
Map<String,Object> map = Maps.newHashMap();
map.put("openId",authToken.getOpenid());//使用者標識openId
map.put("remoteIp",request.getRemoteAddr());//請求Ip地址
//呼叫統一下單service
Map<String,Object> resultMap = WeChatPayService.unifiedOrder(order,map);
String returnCode = (String) resultMap.get("return_code");//通訊標識
String resultCode = (String) resultMap.get("result_code");//交易標識
//只有當returnCode與resultCode均返回“success”,才代表微信支付統一下單成功
if (WeChatConstant.RETURN_SUCCESS.equals(resultCode)&&WeChatConstant.RETURN_SUCCESS.equals(returnCode)){
String appId = (String) resultMap.get("appid");//微信公眾號AppId
String timeStamp = WeChatUtils.getTimeStamp();//當前時間戳
String prepayId = "prepay_id="+resultMap.get("prepay_id");//統一下單返回的預支付id
String nonceStr = WeChatUtils.getRandomStr(20);//不長於32位的隨機字串
SortedMap<String,Object> signMap = Maps.newTreeMap();//自然升序map
signMap.put("appId",appId);
signMap.put("package",prepayId);
signMap.put("timeStamp",timeStamp);
signMap.put("nonceStr",nonceStr);
signMap.put("signType","MD5");
model.addAttribute("appId",appId);
model.addAttribute("timeStamp",timeStamp);
model.addAttribute("nonceStr",nonceStr);
model.addAttribute("prepayId",prepayId);
model.addAttribute("paySign",WeChatUtils.getSign(signMap));//獲取簽名
}else {
logger.error("微信統一下單失敗,訂單編號:"+order.getOrderNumber()+",失敗原因:"+resultMap.get("err_code_des"));
return "redirect:/m/orderList";//支付下單失敗,重定向至訂單列表
}
//將支付需要引數返回至頁面,採用h5方式呼叫支付介面
return "/mobile/order/h5Pay";
}
}
微信支付前端發起頁面: weChatPayTest.jsp
- 支付按鈕href中的redirect_uri= http://自己服務的ip或者域名/m/weChat/unifiedOrder 強調部分需要進行uriEncode
- 此處程式碼為在微信公眾號內網頁呼叫,故使用的是微信網頁授權方式,將訂單id通過支付介面中state引數進行傳遞
<!DOCTYPE HTML><%@pagecontentType="text/html;charset=UTF-8"language="java" %><html><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1,user-scalable=0"><metaname="screen-orientation"content="portrait"><metaname="x5-orientation"content="portrait"><linkrel="stylesheet"href="/static/weui/dist/style/weui.min.css"><title>微信公眾號支付測試</title></head><body><divclass="container"id="container"><ahref="https://open.weixin.qq.com/connect/oauth2/authorizeappid=wx67e9c91f0bac335d&redirect_uri=http%3a%2f%2f***%2fm%2fweChat%2funifiedOrder&response_type=code&scope=snsapi_base&state=${order.id}#wechat_redirect"class="weui_btn weui_btn_primary">立即支付</a></div></body></html>
h5方式呼叫微信支付介面:h5Pay.jsp
- WeixinJSBridge為微信公眾號內建物件,所以必須在公眾號內部網頁使用
<%@ page contentType="text/html;charset=UTF-8" language="java"%><html><head><title>確認支付</title><scripttype="text/javascript"src="/static/jquery/jquery-1.11.3.min.js"></script><scripttype="text/javascript"src="/static/jquery-plugin/jquery.form.js"></script></head><body><inputtype="hidden"name="appId"value="${appId}"><inputtype="hidden"name="nonceStr"value="${nonceStr}"><inputtype="hidden"name="prepayId"value="${prepayId}"><inputtype="hidden"name="paySign"value="${paySign}"><inputtype="hidden"name="timeStamp"value="${timeStamp}"></body><script>functiononBridgeReady(){
var appId = $("input[name='appId']").val();
var nonceStr = $("input[name='nonceStr']").val();
var prepayId = $("input[name='prepayId']").val();
var paySign = $("input[name='paySign']").val();
var timeStamp = $("input[name='timeStamp']").val();
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":appId,
"timeStamp":timeStamp,
"nonceStr":nonceStr,
"package":prepayId,
"signType":"MD5",
"paySign":paySign
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
location.href="支付成功返回商家自定義頁面";
}else {//這裡支付失敗和支付取消統一處理
alert("支付取消");
location.href="支付失敗返回商家自定義頁面";
}
}
);
}
$(document).ready(function () {
if (typeof WeixinJSBridge == "undefined"){
if (document.addEventListener){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}elseif (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else {
onBridgeReady();
}
});
</script></html>
微信支付訂單Service:WeChatPayService.java
/**
*微信支付統一下單
**/
public Map<String,Object> unifiedOrder(Order order, Map<String,Object> map){
Map<String,Object> resultMap;
try {
WxPaySendData paySendData = new WxPaySendData();
//構建微信支付請求引數集合
paySendData.setAppId(WeChatConstant.APP_ID);
paySendData.setAttach("微信訂單支付:"+order.getOrderNumber());
paySendData.setBody("商品描述");
paySendData.setMchId(WeChatConfig.MCH_ID);
paySendData.setNonceStr(WeChatUtils.getRandomStr(32));
paySendData.setNotifyUrl(WeChatConfig.NOTIFY_URL);
paySendData.setDeviceInfo("WEB");
paySendData.setOutTradeNo(order.getOrderNumber());
paySendData.setTotalFee(order.getSumFee());
paySendData.setTradeType(WeChatConfig.TRADE_TYPE_JSAPI);
paySendData.setSpBillCreateIp((String) map.get("remoteIp"));
paySendData.setOpenId((String) map.get("openId"));
//將引數拼成map,生產簽名
SortedMap<String,Object> params = buildParamMap(paySendData);
paySendData.setSign(WeChatUtils.getSign(params));
//將請求引數物件轉換成xml
String reqXml = WeChatUtils.sendDataToXml(paySendData);
//傳送請求
byte[] xmlData = reqXml.getBytes();
URL url = new URL(WeChatConfig.UNIFIED_ORDER_URL);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("Content_Type","text/xml");
urlConnection.setRequestProperty("Content-length",String.valueOf(xmlData.length));
DataOutputStream outputStream = new DataOutputStream(urlConnection.getOutputStream());
outputStream.write(xmlData);
outputStream.flush();
outputStream.close();
resultMap = WeChatUtils.parseXml(urlConnection.getInputStream());
} catch (Exception e) {
throw new ServiceException("微信支付統一下單異常",e);
}
return resultMap;
/**
* 構建統一下單引數map 用於生成簽名
* @param data
* @return SortedMap<String,Object>
*/
private SortedMap<String,Object> buildParamMap(WxPaySendData data) {
SortedMap<String,Object> paramters = newTreeMap<String, Object>();
if (null != data){
if (StringUtils.isNotEmpty(data.getAppId())){
paramters.put("appid",data.getAppId());
}
if (StringUtils.isNotEmpty(data.getAttach())){
paramters.put("attach",data.getAttach());
}
if (StringUtils.isNotEmpty(data.getBody())){
paramters.put("body",data.getBody());
}
if (StringUtils.isNotEmpty(data.getDetail())){
paramters.put("detail",data.getDetail());
}
if (StringUtils.isNotEmpty(data.getDeviceInfo())){
paramters.put("device_info",data.getDeviceInfo());
}
if (StringUtils.isNotEmpty(data.getFeeType())){
paramters.put("fee_type",data.getFeeType());
}
if (StringUtils.isNotEmpty(data.getGoodsTag())){
paramters.put("goods_tag",data.getGoodsTag());
}
if (StringUtils.isNotEmpty(data.getLimitPay())){
paramters.put("limit_pay",data.getLimitPay());
}
if (StringUtils.isNotEmpty(data.getMchId())){
paramters.put("mch_id",data.getMchId());
}
if (StringUtils.isNotEmpty(data.getNonceStr())){
paramters.put("nonce_str",data.getNonceStr());
}
if (StringUtils.isNotEmpty(data.getNotifyUrl())){
paramters.put("notify_url",data.getNotifyUrl());
}
if (StringUtils.isNotEmpty(data.getOpenId())){
paramters.put("openid",data.getOpenId());
}
if (StringUtils.isNotEmpty(data.getOutTradeNo())){
paramters.put("out_trade_no",data.getOutTradeNo());
}
if (StringUtils.isNotEmpty(data.getSign())){
paramters.put("sign",data.getSign());
}
if (StringUtils.isNotEmpty(data.getSpBillCreateIp())){
paramters.put("spbill_create_ip",data.