一 微信支付分對接(java)


1.支付分介紹

微信支付分是對個人的身份特質(zhì)、支付行為、使用歷史等情況的綜合計算分值,旨在為用戶提供更簡單便捷的生活方式。

微信用戶可以在具體應(yīng)用場景中,開通微信支付分。開通后,用戶可以在【微信—>錢包—>支付分】中查看分?jǐn)?shù)和使用記錄。(即需在應(yīng)用場景中使用過一次,錢包才會出現(xiàn)支付分入口)。

官方最新API地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter1_1.shtml

需要聯(lián)系微信方開通服務(wù),分配服務(wù)id即 service_id,同時需要證書序列號和密鑰以及ipv3密鑰等服務(wù)。

2.需要注意的點

接口調(diào)用使用微信支付API v3

相較于的之前微信支付API,主要區(qū)別是:

·遵循統(tǒng)一的Restful的設(shè)計風(fēng)格

·使用JSON作為數(shù)據(jù)交互的格式,不再使用XML

·使用基于非對稱密鑰的SHA256-RSA的數(shù)字簽名算法,不再使用MD5或HMAC-SHA256

·不再要求HTTPS客戶端證書

·使用AES-256-GCM,對回調(diào)中的關(guān)鍵信息進行加密保護

關(guān)于請求需要引入maven

maven配置

使用postman調(diào)試

需要參考:https://github.com/wechatpay-apiv3/wechatpay-postman-script

同時正確鍵入?private_key(證書密鑰)、mch_id(商戶號)、serialNo(證書序列號)

代碼調(diào)用加密部分

/**

* 獲取請求頭

* @param method 方法

* @param url 地址

* @param body 傳輸json

* @return

* @throws IOException

* @throws SignatureException

* @throws NoSuchAlgorithmException

* @throws InvalidKeyException

*/

public? MapgetToken(String method, HttpUrl url, String body)throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException {

String nonceStr =? CreateNumber.getRandom(32);

? ? long timestamp = System.currentTimeMillis() /1000;

? ? String message =buildMessage(method, url, timestamp, nonceStr, body);

? ? String signature = sign(message.getBytes(StandardCharsets.UTF_8));

? ? Map map=new HashMap();

? ? map.put("sign","mchid=\""+MCH_ID+"\","

? ? ? ? ? ? +"nonce_str=\""+nonceStr+"\","

? ? ? ? ? ? +"timestamp=\""+timestamp+"\","

? ? ? ? ? ? +"serial_no=\""+SERIAL_NO+"\","

? ? ? ? ? ? +"signature=\""+signature+"\"");

? ? map.put("timestamp",timestamp);

? ? map.put("noncestr",nonceStr);

? ? return map;

}


/**

* 簽名 生成 signature

* @param message

* @return

* @throws NoSuchAlgorithmException

* @throws IOException

* @throws SignatureException

* @throws InvalidKeyException

*/

public Stringsign(byte[] message)throws NoSuchAlgorithmException, IOException,? SignatureException, InvalidKeyException {

Signature sign = Signature.getInstance("SHA256withRSA");

? ? sign.initSign(getPrivateKey(KEYSTORE_PATH));

? ? sign.update(message);

? ? return Base64.getEncoder().encodeToString(sign.sign());

}

/**

* 拼接傳輸數(shù)據(jù)

* @param method

* @param url

* @param timestamp

* @param nonceStr

* @param body

* @return

*/

static StringbuildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {

String canonicalUrl = url.encodedPath();

? ? if (url.encodedQuery() !=null) {

canonicalUrl +="?" + url.encodedQuery();

? ? }

System.err.println(method +"\n"

? ? ? ? ? ? + canonicalUrl +"\n"

? ? ? ? ? ? + timestamp +"\n"

? ? ? ? ? ? + nonceStr +"\n"

? ? ? ? ? ? + body +"\n");

? ? return method +"\n"

? ? ? ? ? ? + canonicalUrl +"\n"

? ? ? ? ? ? + timestamp +"\n"

? ? ? ? ? ? + nonceStr +"\n"

? ? ? ? ? ? + body +"\n";

}

/**

* 獲取密鑰

* @param filename

* @return

* @throws IOException

*/

public? PrivateKeygetPrivateKey(String filename)throws IOException {

String content =new String(Files.readAllBytes(Paths.get(filename)), "utf-8");

? ? try {

String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")

.replace("-----END PRIVATE KEY-----", "")

.replaceAll("\\s+", "");

? ? ? ? KeyFactory kf = KeyFactory.getInstance("RSA");

? ? ? ? return kf.generatePrivate(

new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));

? ? }catch (NoSuchAlgorithmException e) {

throw new RuntimeException("當(dāng)前Java環(huán)境不支持RSA", e);

? ? }catch (InvalidKeySpecException e) {

throw new RuntimeException("無效的密鑰格式");

? ? }

}

/**

* post請求 租借、修改、撤銷、完結(jié)等使用

* @param url

* @param params

* @return

*/

public? MapsendBodyPost(String url, Object params) {

OutputStreamWriter out =null;

? ? BufferedReader in =null;

? ? StringBuilder result =new StringBuilder();

? ? Map map =new HashMap<>();

? ? try {

URL realUrl =new URL(url);

? ? ? ? HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();

? ? ? ? String param = JSONObject.toJSONString(params);

? ? ? ? // 發(fā)送POST請求必須設(shè)置如下兩行

? ? ? ? conn.setDoOutput(true);

? ? ? ? conn.setDoInput(true);

? ? ? ? // POST方法

? ? ? ? conn.setRequestMethod("POST");

? ? ? ? // 設(shè)置通用的請求屬性

? ? ? ? conn.setRequestProperty("accept", "*/*");

? ? ? ? conn.setRequestProperty("connection", "Keep-Alive");

? ? ? ? conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

? ? ? ? conn.setRequestProperty("Content-Type", "application/json");

? ? ? ? map = getToken("POST", HttpUrl.parse(url), param);

? ? ? ? conn.setRequestProperty("Authorization", "WECHATPAY2-SHA256-RSA2048" +" " + map.get("sign"));

? ? ? ? conn.connect();

? ? ? ? // 獲取URLConnection對象對應(yīng)的輸出流

? ? ? ? out =new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8);

? ? ? ? // 發(fā)送請求參數(shù)

? ? ? ? logger.info("param:" + param);

? ? ? ? out.write(param);

? ? ? ? // flush輸出流的緩沖

? ? ? ? out.flush();

? ? ? ? // 定義BufferedReader輸入流來讀取URL的響應(yīng)

? ? ? ? in =new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));

? ? ? ? String line;

? ? ? ? while ((line = in.readLine()) !=null) {

result.append(line);

? ? ? ? }

}catch (Exception e) {

e.printStackTrace();

? ? ? ? result.append("error");

? ? }

// 使用finally塊來關(guān)閉輸出流、輸入流

? ? finally {

try {

if (out !=null) {

out.close();

? ? ? ? ? ? }

if (in !=null) {

in.close();

? ? ? ? ? ? }

}catch (IOException ex) {

ex.printStackTrace();

? ? ? ? ? ? result.append("error");

? ? ? ? }finally {

Map maps =new HashMap<>();

? ? ? ? ? ? if (result.toString().contains("error")) {

maps.put("result", result.toString());

? ? ? ? ? ? }else {

maps.put("result", JSONObject.parseObject(result.toString()));

? ? ? ? ? ? }

maps.put("sign", map.get("sign"));

? ? ? ? ? ? maps.put("timestamp", map.get("timestamp"));

? ? ? ? ? ? maps.put("noncestr", map.get("noncestr"));

? ? ? ? ? ? return maps;

? ? ? ? }

}

}


/**

* Get請求 多用于查詢租借訂單

* @param url

* @param params

* @param param

* @return

*/

public? StringdoGet(String url, Map params,String param) {

String result ="";

? ? HttpClient httpClient = HttpClientBuilder.create().build();

? ? HttpGet httpGet =null;

? ? try {

URIBuilder uriBuilder =new URIBuilder(url);

? ? ? ? if (null != params && !params.isEmpty()) {

for (Map.Entry entry : params.entrySet()) {

uriBuilder.addParameter(entry.getKey(), entry.getValue());

? ? ? ? ? ? }

}

URI uri = uriBuilder.build();

? ? ? ? // 創(chuàng)建get請求

? ? ? ? httpGet =new HttpGet(uri);

? ? ? ? httpGet.setHeader("accept", "*/*");

? ? ? ? httpGet.setHeader("connection", "Keep-Alive");

? ? ? ? httpGet.setHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

? ? ? ? httpGet.setHeader("Authorization","WECHATPAY2-SHA256-RSA2048"+" "+getToken("GET", HttpUrl.parse("https://api.mch.weixin.qq.com/v3/payscore/serviceorder?"+param),"").get("sign"));

? ? ? ? HttpResponse response = httpClient.execute(httpGet);

? ? ? ? Header[] s=httpGet.getHeaders("Authorization");

? ? ? ? System.err.println(String.valueOf(s[0]));

? ? ? ? result = EntityUtils.toString(response.getEntity());

? ? }catch (Exception e) {

ExceptionUtils.getStackTrace(e);

? ? ? ? result="error";

? ? ? ? return result;

? ? }finally {

if (null != httpGet) {

httpGet.releaseConnection();

? ? ? ? }

}

return result;

}

使用接口發(fā)起調(diào)用即可

調(diào)用示例
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容