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

使用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)用即可
