微信支付-公眾號(hào)支付-JSAPI調(diào)用(V2——Java)

1.開發(fā)微信公眾號(hào)支付準(zhǔn)備資料

①APPID,這個(gè)數(shù)據(jù)我們可以從“申請(qǐng)微信支付成功”的郵件中獲取。

②AppSecret,這個(gè)數(shù)據(jù),大家可以看上圖中獲取。

③Mch_id,這是值是微信支付商戶號(hào),大家可以從郵件中獲取

④KEY,這個(gè)參數(shù)KEY是在商戶后臺(tái)配置的一個(gè)32位的key,微信商戶平臺(tái)-賬戶設(shè)置-安全設(shè)置-api安全,在這里設(shè)置。這個(gè)值是可以自行設(shè)置的。


微信支付必須參數(shù)

2.設(shè)置支付目錄

支付授權(quán)目錄說(shuō)明:

1、商戶最后請(qǐng)求拉起微信支付收銀臺(tái)的頁(yè)面地址我們稱之為“$\color{red}{支付目錄}$”,例如:https://www.weixin.com/pay.php。

2、商戶實(shí)際的支付目錄必須和在微信支付商戶平臺(tái)設(shè)置的一致,否則會(huì)報(bào)錯(cuò)“當(dāng)前頁(yè)面的URL未注冊(cè):”

支付授權(quán)目錄設(shè)置說(shuō)明:

登錄微信支付商戶平臺(tái)(pay.weixin.qq.com)-->產(chǎn)品中心-->開發(fā)配置,設(shè)置后一般5分鐘內(nèi)生效。

支付授權(quán)目錄校驗(yàn)規(guī)則說(shuō)明:

1、如果支付授權(quán)目錄設(shè)置為頂級(jí)域名(例如:https://www.weixin.com/ ),那么只校驗(yàn)頂級(jí)域名,不校驗(yàn)后綴;

2、如果支付授權(quán)目錄設(shè)置為多級(jí)目錄,就會(huì)進(jìn)行全匹配,例如設(shè)置支付授權(quán)目錄為https://www.weixin.com/abc/123/,則實(shí)際請(qǐng)求頁(yè)面目錄不能為https://www.weixin.com/abc/,也不能為https://www.weixin.com/abc/123/pay/,必須為https://www.weixin.com/abc/123/


設(shè)置支付目錄

具體看官方文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3

3.首先要看微信支付的業(yè)務(wù)流程,官方文檔——>開發(fā)微信支付


業(yè)務(wù)流程時(shí)序圖

微信支付的流程(主要步驟):

1、用戶訪問(wèn)微信OAuth2.0網(wǎng)站,通過(guò)OAuth2.0的重定向獲得code

2、根據(jù)code獲得用戶的標(biāo)識(shí)符openid,這個(gè)參數(shù)在調(diào)用統(tǒng)一下單接口中會(huì)用到

3、調(diào)用統(tǒng)一下單API獲得prepay_id

4、獲得prepay_id后,接下來(lái)要調(diào)用通過(guò)“網(wǎng)頁(yè)端調(diào)起支付API”,這個(gè)調(diào)用的API需要一系列參數(shù),這些參數(shù)我們?cè)诤笈_(tái)進(jìn)行組裝,通過(guò)JSON傳到前臺(tái)去

5、獲得數(shù)據(jù)后通過(guò)調(diào)用JSPAI發(fā)起微信支付

6、用戶輸入支付密碼,支付完成

7、等待微信回調(diào),回調(diào)中處理業(yè)務(wù)

8、支付流程完畢

微信支付所需依賴:

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>commons-codec</groupId>

? ? ? ? ? ? <artifactId>commons-codec</artifactId>

? ? ? ? ? ? <version>1.6</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>commons-logging</groupId>

? ? ? ? ? ? <artifactId>commons-logging</artifactId>

? ? ? ? ? ? <version>1.1.3</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.apache.httpcomponents</groupId>

? ? ? ? ? ? <artifactId>fluent-hc</artifactId>

? ? ? ? ? ? <version>4.3.6</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.apache.httpcomponents</groupId>

? ? ? ? ? ? <artifactId>httpclient</artifactId>

? ? ? ? ? ? <version>4.3.6</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.apache.httpcomponents</groupId>

? ? ? ? ? ? <artifactId>httpclient-cache</artifactId>

? ? ? ? ? ? <version>4.3.6</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.apache.httpcomponents</groupId>

? ? ? ? ? ? <artifactId>httpcore</artifactId>

? ? ? ? ? ? <version>4.3.3</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.apache.httpcomponents</groupId>

? ? ? ? ? ? <artifactId>httpmime</artifactId>

? ? ? ? ? ? <version>4.3.6</version>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.jsoup</groupId>

? ? ? ? ? ? <artifactId>jsoup</artifactId>

? ? ? ? ? ? <version>1.7.2</version>

? ? ? ? </dependency>

? ? ? ? <!-- FastJson -->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.alibaba</groupId>

? ? ? ? ? ? <artifactId>fastjson</artifactId>

? ? ? ? ? ? <version>1.2.1</version>

? ? ? ? </dependency>

? ? </dependencies>


4、微信支付整體流程實(shí)現(xiàn)

1.獲取code值,我這邊是通過(guò)$\color{red}{前端寫的js}$來(lái)獲取code值的


通過(guò)該JS來(lái)獲取code值

2.通過(guò)Code 獲取用戶 openid 和 access_token

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONObject;

import ***********************.WeChatConst;//一些常量

import org.apache.http.HttpResponse;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.DefaultHttpClient;

import org.apache.http.util.EntityUtils;

import java.io.*;

import java.nio.charset.Charset;

import java.util.HashMap;

import java.util.Map;

import java.util.Random;

/**

* Created by Arthur on 2015/11/10 16:45.

*/

public class WeChatUtil {

? ? /**

? ? * 通過(guò)Code 獲取用戶 openid 和 access_token

? ? * @param code

? ? * @return

? ? * @throws IOException

? ? */

? ? public static Map<String,Object> getOpenIdByCode(String code) throws IOException {

? ? ? ? /**

? ? ? ? * 設(shè)置訪問(wèn)路徑

? ? ? ? */

? ? ? ? HttpPost httppost = new HttpPost("https://api.weixin.qq.com/sns/oauth2/access_token");

? ? ? ? /**

? ? ? ? * 組裝請(qǐng)求參數(shù)

? ? ? ? */

? ? ? ? String reqEntityStr = "appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";

? ? ? ? reqEntityStr = reqEntityStr.replace("APPID", WeChatConst.APPID);

? ? ? ? reqEntityStr = reqEntityStr.replace("SECRET", WeChatConst.APP_SECRET);

? ? ? ? reqEntityStr = reqEntityStr.replace("CODE", code);

? ? ? ? StringEntity reqEntity = new StringEntity(reqEntityStr);

? ? ? ? /**

? ? ? ? * 設(shè)置瀏覽器

? ? ? ? */

? ? ? ? DefaultHttpClient httpclient = new DefaultHttpClient();

? ? ? ? /**

? ? ? ? * 設(shè)置參數(shù)

? ? ? ? */

? ? ? ? httppost.setEntity(reqEntity);

? ? ? ? /**

? ? ? ? * 發(fā)起請(qǐng)求

? ? ? ? */

? ? ? ? HttpResponse response = httpclient.execute(httppost);

? ? ? ? /**

? ? ? ? * 獲得請(qǐng)求內(nèi)容

? ? ? ? */

? ? ? ? String strResult = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8"));

? ? ? ? /**

? ? ? ? * 分析內(nèi)容

? ? ? ? */

? ? ? ? JSONObject jsonObject = (JSONObject) JSON.parse(strResult);

? ? ? ? Map<String,Object> map = new HashMap<>();

? ? ? ? map.put("openid",jsonObject.get("openid"));

? ? ? ? map.put("access_token",jsonObject.get("access_token"));

? ? ? ? map.put("refresh_token",jsonObject.get("refresh_token"));

? ? ? ? return map;

? ? }

? ? /**

? ? * 統(tǒng)一下單

? ? * 獲得PrePayId

? ? * @param body? 商品或支付單簡(jiǎn)要描述

? ? * @param out_trade_no 商戶系統(tǒng)內(nèi)部的訂單號(hào),32個(gè)字符內(nèi)、可包含字母

? ? * @param total_fee? 訂單總金額,單位為分

? ? * @param IP? ? APP和網(wǎng)頁(yè)支付提交用戶端ip

? ? * @param notify_url 接收微信支付異步通知回調(diào)地址

? ? * @param openid 用戶openId

? ? * @throws IOException

? ? */

? ? public static String unifiedorder(String body,String out_trade_no,Integer total_fee,String IP,String notify_url,String openid)throws IOException {

? ? ? ? /**

? ? ? ? * 設(shè)置訪問(wèn)路徑

? ? ? ? */

? ? ? ? HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");

? ? ? ? /**

? ? ? ? * 組裝請(qǐng)求參數(shù)

? ? ? ? * 按照ASCII排序

? ? ? ? */

? ? ? ? String reqEntityStr = "appid=APPID" +

? ? ? ? ? ? ? ? "&body=BODY" +

? ? ? ? ? ? ? ? "&mch_id=MCH_ID" +

? ? ? ? ? ? ? ? "&nonce_str=NONCE_STR" +

? ? ? ? ? ? ? ? "&notify_url=NOTIFY_URL" +

? ? ? ? ? ? ? ? "&openid=OPENID" +

? ? ? ? ? ? ? ? "&out_trade_no=OUT_TRADE_NO" +

? ? ? ? ? ? ? ? "&spbill_create_ip=IP" +

? ? ? ? ? ? ? ? "&total_fee=TOTAL_FEE" +

? ? ? ? ? ? ? ? "&trade_type=TRADE_TYPE"

? ? ? ? ? ? ? ? ;//這個(gè)字段是用于之后MD5加密的,字段要按照ascii碼順序排序

? ? ? ? /**

? ? ? ? * 設(shè)置數(shù)據(jù)

? ? ? ? */

? ? ? ? String nonce_str = getNonceStr().toUpperCase();//隨機(jī)數(shù)據(jù)

? ? ? ? reqEntityStr = reqEntityStr.replace("APPID", WeChatConst.APPID);

? ? ? ? reqEntityStr = reqEntityStr.replace("MCH_ID", WeChatConst.MCH_ID);

? ? ? ? reqEntityStr = reqEntityStr.replace("NONCE_STR", nonce_str);

? ? ? ? reqEntityStr = reqEntityStr.replace("BODY", body);

? ? ? ? reqEntityStr = reqEntityStr.replace("OUT_TRADE_NO", out_trade_no);

? ? ? ? reqEntityStr = reqEntityStr.replace("TOTAL_FEE", total_fee.toString());

? ? ? ? reqEntityStr = reqEntityStr.replace("IP", IP);

? ? ? ? reqEntityStr = reqEntityStr.replace("NOTIFY_URL", notify_url);

? ? ? ? reqEntityStr = reqEntityStr.replace("TRADE_TYPE", WeChatConst.TRADE_TYPE);

? ? ? ? reqEntityStr = reqEntityStr.replace("OPENID", openid);

? ? ? ? /**

? ? ? ? * 生成sign的數(shù)據(jù)

? ? ? ? */

? ? ? ? String sign = reqEntityStr + "&key="+WeChatConst.KEY;

? ? ? ? sign = MD5Util.MD5(sign).toUpperCase();

? ? ? ? /**

? ? ? ? * 組裝XML

? ? ? ? */

? ? ? ? StringBuilder sb = new StringBuilder("");

? ? ? ? sb.append("<xml>");

? ? ? ? setXmlKV(sb,"appid",WeChatConst.APPID);

? ? ? ? setXmlKV(sb,"body",body);

? ? ? ? setXmlKV(sb,"mch_id",WeChatConst.MCH_ID);

? ? ? ? setXmlKV(sb,"nonce_str",nonce_str);

? ? ? ? setXmlKV(sb,"notify_url",notify_url);

? ? ? ? setXmlKV(sb,"openid",openid);

? ? ? ? setXmlKV(sb,"out_trade_no",out_trade_no);

? ? ? ? setXmlKV(sb,"spbill_create_ip",IP);

? ? ? ? setXmlKV(sb,"total_fee",total_fee.toString());

? ? ? ? setXmlKV(sb,"trade_type",WeChatConst.TRADE_TYPE);

? ? ? ? setXmlKV(sb,"sign",sign);

? ? ? ? sb.append("</xml>");

//? ? ? ? reqEntityStr = reqEntityStr.replace("sign", sign);

? ? ? ? StringEntity reqEntity = new StringEntity(new String (sb.toString().getBytes("UTF-8"),"ISO8859-1"));//這個(gè)處理是為了防止傳中文的時(shí)候出現(xiàn)簽名錯(cuò)誤

? ? ? ? httppost.setEntity(reqEntity);

? ? ? ? DefaultHttpClient httpclient = new DefaultHttpClient();

? ? ? ? HttpResponse response = httpclient.execute(httppost);

? ? ? ? String strResult = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8"));

//? ? ? ? System.out.println(strResult);

? ? ? ? return getPrePayId(strResult);

? ? }

? ? /**

? ? * 獲得32位隨機(jī)字符串

? ? * @return

? ? */

? ? public static String getNonceStr(){

? ? ? ? String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

? ? ? ? StringBuilder sb = new StringBuilder();

? ? ? ? Random rd = new Random();

? ? ? ? for(int i = 0 ; i < 32 ; i ++ ){

? ? ? ? ? ? sb.append(str.charAt(rd.nextInt(str.length())));

? ? ? ? }

? ? ? ? return sb.toString();

? ? }

? ? /**

? ? * 插入XML標(biāo)簽

? ? * @param sb

? ? * @param Key

? ? * @param value

? ? * @return

? ? */

? ? public static StringBuilder setXmlKV(StringBuilder sb,String Key,String value){

? ? ? ? sb.append("<");

? ? ? ? sb.append(Key);

? ? ? ? sb.append(">");

? ? ? ? sb.append(value);

? ? ? ? sb.append("</");

? ? ? ? sb.append(Key);

? ? ? ? sb.append(">");

? ? ? ? return sb;

? ? }

? ? /**

? ? * 解析XML? 獲得 PrePayId

? ? * @param xml

? ? * @return

? ? */

? ? public static String getPrePayId(String xml){

? ? ? ? int start = xml.indexOf("<prepay_id>");

? ? ? ? int end = xml.indexOf("</prepay_id>");

? ? ? ? if(start < 0 && end < 0){

? ? ? ? ? ? return null;

? ? ? ? }

? ? ? ? return xml.substring(start + "<prepay_id>".length(),end)

? ? ? ? ? ? ? ? .replace("<![CDATA[","").replace("]]>","");

? ? }

}

public interface WeChatConst {

? ? String APPID = "";//填寫APPID

? ? String APP_SECRET = "";//填寫AppSecret

? ? String MCH_ID = "";//Mch_id,這是值是微信支付商戶號(hào),大家可以從郵件中獲取

? ? String KEY = "";//這個(gè)參數(shù)KEY是在商戶后臺(tái)配置的一個(gè)32位的key,微信商戶平臺(tái)-賬戶設(shè)置-安全設(shè)置-api安全

? ? /**

? ? * 交易類型

? ? */

? ? String TRADE_TYPE = "JSAPI";

}

我們可以調(diào)用里面的“getOpenIdByCode”方法通過(guò)code 獲得openid,這個(gè)openid我們先記錄下來(lái),稍后會(huì)用到的,接下來(lái)我們要經(jīng)行調(diào)用統(tǒng)一下單接口

3.然后通過(guò)可以調(diào)用里面的“unifiedorder”獲取prepay_id

后臺(tái)調(diào)傭統(tǒng)一下單的API,獲得prepay_id

**這步我們先要設(shè)置支付授權(quán)目錄**

微信公眾平臺(tái)→微信支付→開發(fā)配置→測(cè)試授權(quán)目錄和測(cè)試白名單。

直接配置支付授權(quán)目錄也行。

后臺(tái)獲得到需要用戶支付的金額,以及一些列的產(chǎn)品信息后,系統(tǒng)經(jīng)行預(yù)下單,也是就調(diào)用調(diào)用統(tǒng)一下單的API,生成一個(gè)需要支付的訂單,獲得prepay_id,該值用于在前端頁(yè)面,通過(guò)JSAPI中調(diào)用微信支付需要用到,代碼看下面的? "JSONObjectdoRecharge(HttpServletRequest request, String code)" 的方法,以及WeChatUtil。

統(tǒng)一下單大家可以調(diào)用我剛剛提供給大家的工具類中的WeChatUtil.unifiedorder這個(gè)方法,參數(shù)在方法上面的注釋有寫清楚。

這里如果你們想自行封裝需要注意一個(gè)編碼問(wèn)題,這個(gè)會(huì)導(dǎo)致你回調(diào)產(chǎn)生簽名錯(cuò)誤。

獲得prepay_id后,我們需要在后臺(tái)組裝,調(diào)用微信JSAPI的接口數(shù)據(jù)。

以下是需要組裝起來(lái)的參數(shù),也是進(jìn)行微信支付的必須參數(shù)

"appId": "", //公眾號(hào)ID,由商戶傳入

"timeStamp": "", //時(shí)間戳?

"nonceStr": "", //隨機(jī)串? ?

"package": "", //獲得PrePayId

"signType": "MD5", //微信簽名方式:? ?

"paySign": "" //微信簽名

4.前端所需參數(shù),通過(guò)這些參數(shù)可以進(jìn)行支付

獲取這些參數(shù)來(lái)源是需要——>進(jìn)行預(yù)下單——>方法如下:

/**

* 微信支付——進(jìn)行預(yù)下單

*

* @param request

* @param code

* @return

* @throws IOException

*/

@RequestMapping(value ="/WxPay")

public static JSONObjectdoRecharge(HttpServletRequest request, String code)throws IOException {

//獲取openId的方法

? ? Map openIdByCode = WeChatUtil.getOpenIdByCode(code);

? ? System.out.println("openId:" + openIdByCode.get("openid"));

? ? String body = WeChatConst.BOBY;

? ? //商戶訂單號(hào)

? ? String out_trade_no = UUIDUtils.getUUID().toUpperCase();

? ? System.out.println("商戶訂單號(hào):" + out_trade_no);

? ? //支付金額

? ? int total_fee =1;

? ? //IP

? ? String IP = WeChatConst.IP;

? ? //支付成功后回調(diào)的地址

? ? String openid = (String) openIdByCode.get("openid");

? ? //在業(yè)務(wù)層調(diào)用 WeChatUtil.unifiedorder方法獲得prepay_id

? ? String prepay = WeChatUtil.unifiedorder(body, out_trade_no, total_fee, IP, WeChatConst.NOTIFY_URL, openid);

? ? System.out.println("prepay_id" + prepay);

? ? //將參數(shù)組裝起來(lái)

? ? String prepay_id = prepay;

? ? //1970年到現(xiàn)在的秒數(shù)

? ? String timeStamp = String.valueOf((System.currentTimeMillis() /1000));

? ? //數(shù)據(jù)字符串

? ? String nonceStr = WeChatUtil.getNonceStr().toUpperCase();

? ? //prepay_id

? ? String packageStr ="prepay_id=" + prepay_id;

? ? String signType ="MD5";

? ? //簽名

? ? String paySign =

"appId=" + WeChatConst.APPID +

"&nonceStr=" + nonceStr +

"&package=prepay_id=" + prepay_id +

"&signType=" + signType +

"&timeStamp=" + timeStamp +

"&key=" + WeChatConst.KEY;//注意這里的參數(shù)要根據(jù)ASCII碼 排序

? ? //將數(shù)據(jù)MD5加密

? ? paySign = Md5Utils.encrypt(paySign).toUpperCase();

? ? JSONObject object =new JSONObject();

? ? object.put("appId", WeChatConst.APPID);

? ? object.put("timeStamp", timeStamp);

? ? object.put("nonceStr", nonceStr);

? ? object.put("package", packageStr);

? ? object.put("signType", signType);

? ? object.put("paySign", paySign);

? ? return object;

}

通過(guò)該方法——>JSONObjectdoRecharge——>獲取進(jìn)行支付參數(shù)

5.將這些參數(shù)(appId、nonceStr、package、signType、timeStamp、key)填寫到如下頁(yè)面:

支付頁(yè)面wxPay.html

5、將該參數(shù)設(shè)置好的頁(yè)面HTML放到 "支付授權(quán)目錄"(授權(quán)目錄第3步驟有講到)

6、直接訪問(wèn)該html文件,就可以進(jìn)行支付了

比如我存放到服務(wù)器當(dāng)中的https://xx.lxx-xx.com/h5/fjyc/wxPay.html 目錄

而這個(gè)項(xiàng)目當(dāng)中目錄是支付授權(quán)目錄,那我直接訪問(wèn)該鏈接(https://xx.lxx-xx.com/h5/fjyc/wxPay.html )


喚醒支付


支付完成
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容