前面講了,獲取證書和獲取證書和上傳圖片,現在我們進入主題,講申請入駐。
首先打開官方文檔:https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_2
接口鏈接
URL地址:https://api.mch.weixin.qq.com/applyment/micro/submit
是否需要證書
請求需要雙向證書。 詳見證書使用
1. 請求參數說明
平臺證書序列號(cert_sn),請參考第一小節:獲取證書
2. 敏感信息加密
我們先看一下官方的解釋:
意思是說,我們還需要解密證書,才能得到證書內容,才能用他來加密。這裏我們使用官方的例子:
package com.pay.wechat.util;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
*
* @author libaibai
* @version 1.0 2020年5月26日
*/
public class WxAesGcmExample {
private static final String ALGORITHM = "AES/GCM/NoPadding";
private static final int TAG_LENGTH_BIT = 128;
// private static final int NONCE_LENGTH_BYTE = 12;
// private static final String TRANSFORMATION_PKCS1Padding = "RSA/ECB/PKCS1Padding";
public static String aesgcmDecrypt(String aad, String iv, String cipherText) throws Exception {
final Cipher cipher = Cipher.getInstance(ALGORITHM, "SunJCE");
SecretKeySpec key = new SecretKeySpec(Configure.AES_KEY_APIV3.getBytes(), "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(aad.getBytes());
return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
}
public static void main(String[] args) {
final String associatedData = "certificate"; // encrypt_certificate.associated_data
final String nonce = "6742f1f9f00e"; // encrypt_certificate.nonce
final String cipherText = "PFyVCE8Uh3PXuvwhhP7/kQ5m0SlNtSCE1xFtFrFWxMjdbAnxZEOxRqkeJUM2G39p/+JtdkAg0VAJcZkJAhNcuQUYSJbybG/CWPt4Pqj+OounkXFD/7+/XEudx8/oW8KBV/WgvhGdRNWrDCqJBOiWYLt9YNOh0PHdcjY06QW0GGcqPjQ2I8NGNqX99Zh9ehI6xg69VGIV1nid7U5seRboYmYbf5nJtPHT1VJDCEUzgpQ1zag+U2tCmA+1udGMmMwn4VLGham06UmN0p350oCiOJw/Z6QpkX8v+WyufwWb5RgdjkOx4ymUm6K1l7HUD07T28O/Dsk6l/v0hnvWyNo/aM8NRYCFo6FL92ivIf/tQKnCmH302nx4Ex0e+wMuNLdZ8uMk+mLBThc7vIpo2KeUScHvEC4FBiFUBhnP92jEA+V17QEfzIRH9McGuN/Wj3agsE6P8f3ZoJ5PuHND6pKjycfATphUMx+goMvZ0vTwzPRkJjFd2d9xJSTNrpf0bZouEN73ubH7qhE481pxpGNZRrhRLYT7dry3LmZGSN+yKujo270FG1HD2sp4wZr0aODGxoX+YBlvkPANKlOcd9SsRb+SDMIplt+TtX3Is8BNQs4rcYnclm8PRcoHFgewVRrGhKc7BVOzc8MoTCmbiBX1bsaqCmax2wVkfr6joLqyMlYbu3aq4ECOdzxB7OovwRWcNhtdfmZSQfoH3OftgH0If6GvRogyLKR1yI+FkREf+DGLU7cqkYuQdLMfnB68GApWQTCb8XsECGNNFCbUQ/EOW8asv+B/ICqBh10kygndkU16XDuYa+9BmNplim1AFWr7NP26oaGGcklIRBLBTbw4/pwXpyxnsZfRrRtBTcm9YqmU6HTO17yFPLa15aJlKMzcebYkQWqoYKcnkTFSqAMN56sFB5FkEmUtn768x5aDRbqgAhZRVsXChjJcTZQRTPma3hvAjHGIKK1gLn4VsXl7g4dCBdzcboCNA1EYDTIjHr6iy+ya30qsxINfR6U/J9kVt/TMKEyAAHw9U60I/R2g6dPLu5jcFa9pHw2tsO1OCgzn45SbG/K6YM5tA0pawBgnJpljqiW6nVvvQacoMIuQaXfoJ5egJ66gd52Q0f4MVbc9Tikn+RX7kvcxLamDCksGPJqqvkL2AvWIwhvS0MWA0qUrJ/s3dpb7fz7bQ3Eh/oCMQBbPpQEEHr5v2l5rw+mRpc8xcrUfSG4hsomJR0Fa9CLoP467INw6W7n4vw3Sifo5SNKMxNXCGrbAe5/IJ2FdkdXPdYql+ckpUnkw7/FNnAer4e+w8qRBJx7rHygufGGlAUTVjOAKPHvjeXXHuNL3xHQkVvOq2VM5er4CBigTwbcA7p/k1z8JpUOEC6CRwO9ZDD04U2CACtDd+UN5QsETtFwW/UEd6JyTFhENG8wYitRLaI6gVo0zYoHUL98itozosO5gqc4wTwEJMsT6CUHYrVknSHWDvmHyu37r+w5SHCcwYx84BdHmkQcDjcRI/dggyrj1J5xsCjFaSUu+kAq97KciLIuv9RZejaMzgBh4QGcqBF6JxqK+da3sJTk75LVD2sfbRGGo9rmF2Ceazd7gGN5m55NeCwjDmSnqf8+Bk3tNd0n7d7wiKuUaWJh/UpqfSABQre7Aj9iTwuALpz8P2ZbQp/YwfJ9OIoAyk7j14m29fBrvcpaHLOpq1PoE3uI+2LLnWQQ9qIQiA1PN474YUbhX6VKnofkk1uxCM+B4U2DelrxCucjIJkOtEInaxpBuCznW339cGlrnM1Wd+H3hfiI3DwIK5Gvfctnox2uGBLMo/I961wGUdhfuv8wen934VqBhHGBNlQg0JgLwgfihRfo4RxrjlmmGLrduNzdLL2pfffDfValBZ2Ia6KrU+Al5RZ81WoGR4hW/4K83XEevA9hY"; // encrypt_certificate.ciphertext
try {
String wechatpayCert = aesgcmDecrypt(associatedData, nonce, cipherText);
System.out.println("wechatpayCert=" + wechatpayCert);
} catch (Exception e) {
e.printStackTrace();
}
}
}
從以上代碼可以看得出來,主要用到了4個參數
associatedData,nonce,cipherText,aes_key_apiv3
前三個參數都可以在“獲取證書”接口的返回值的找到,apiv3則需要到商戶平臺裏面去設備,如下圖:
找到參數,直接運行main方法,得到證書明文。
然後就可以對商戶的數據,敏感信息加密了,官方也提供了加密的示例:
WxRSAEncryptUtil .java
package com.pay.wechat.util;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PublicKey;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.security.cert.X509Certificate;
/**
*
* @author libaibai
* @version 1.0 2020年5月26日
*/
public class WxRSAEncryptUtil {
// private static final String ALGORITHOM = "RSA";// 固定值,無須修改
private static final String CIPHER_PROVIDER = "SunJCE";
private static final String TRANSFORMATION_PKCS1Paddiing = "RSA/ECB/PKCS1Padding";
private static final String CHAR_ENCODING = "UTF-8";// 固定值,無須修改
// private static final String PUBLIC_KEY_FILENAME = "/path/certificate";// 平臺證書路徑,開發人員需根據具體路徑修改
// private static final String PUBLIC_KEY_FILENAME =
// "G:\\workspace\\dlys\\src\\main\\resources\\conf\\cert\\apiclient_cert.pem";//
// 平臺證書路徑,開發人員需根據具體路徑修改
// 數據加密方法
private static byte[] encryptPkcs1padding(PublicKey publicKey, byte[] data) throws Exception {
Cipher ci = Cipher.getInstance(TRANSFORMATION_PKCS1Paddiing, CIPHER_PROVIDER);
ci.init(Cipher.ENCRYPT_MODE, publicKey);
return ci.doFinal(data);
}
// 加密後的祕文,使用base64編碼方法
private static String encodeBase64(byte[] bytes) throws Exception {
return Base64.getEncoder().encodeToString(bytes);
}
/**
* 對敏感內容(入參Content)加密,其中PUBLIC_KEY_FILENAME爲存放平臺證書的路徑,平臺證書文件存放明文平臺證書內容,且爲pem格式的平臺證書(平臺證書的獲取方式參照平臺證書及序列號獲取接口,通過此接口得到的參數certificates包含了加密的平臺證書內容ciphertext,然後根據接口文檔中平臺證書解密指引,最終得到明文平臺證書內容)
*
* @param Content 內容
* @param certpath 平臺序列號接口解密後的密鑰 pem 路徑
* @return
* @throws Exception
*/
public static String rsaEncrypt(String Content, String certpath) throws Exception {
final byte[] PublicKeyBytes = Files.readAllBytes(Paths.get(certpath));
X509Certificate certificate = X509Certificate.getInstance(PublicKeyBytes);
PublicKey publicKey = certificate.getPublicKey();
return encodeBase64(encryptPkcs1padding(publicKey, Content.getBytes(CHAR_ENCODING)));
}
/**
* 直接使用接口cert解密
*
* @param Content
* @param certStr
* @return
* @throws Exception
*/
public static String rsaEncryptByCert(String Content, String certStr) throws Exception {
X509Certificate certificate = X509Certificate.getInstance(certStr.getBytes());
PublicKey publicKey = certificate.getPublicKey();
return encodeBase64(encryptPkcs1padding(publicKey, Content.getBytes(CHAR_ENCODING)));
}
// 對“hello world進行加密”
public static void main(String[] args) {
try {
// System.out.println("after encrypt: " + rsaEncrypt("hello world"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
最後直接調用,申請入駐接口
WxSmallModel .java
package com.pay.wechat.protocol;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import com.pay.wechat.util.Configure;
import com.pay.wechat.util.Signature;
import com.util.Config;
import com.util.UUIDUtil;
/**
* 小微商戶進件信息
*
* @author libaibai
* @version 1.0 2020年5月26日
*/
public class WxSmallModel {
private String version = "3.0"; // 版本號
private String cert_sn; // 平臺證書序列號
private String mch_id = Config.MCHIDSP; // 服務商商戶號
private String nonce_str = UUIDUtil.getUUID19(); // 隨機字符串
private String sign_type = "HMAC-SHA256";// 簽名類型,僅支持HMAC-SHA256 。該字段需參與簽名sign的計算。
private String sign = ""; // 簽名
private String business_code = UUIDUtil.getUUID32(); // 業務申請編號,服務商自定義的商戶唯一編號。每個編號對應一個申請單,每個申請單審覈通過後會生成一個微信支付商戶號。
private String id_card_copy; // 請填寫由圖片上傳接口預先上傳圖片生成好的media_id
private String id_card_national; // 請填寫由圖片上傳接口預先上傳圖片生成好的media_id
private String id_card_name; // 身份證姓名,
private String id_card_number; //
private String id_card_valid_time; // 身份證有效期限,例如:["1970-01-01","長期"]
private String account_bank; // 開戶銀行
private String bank_address_code; // 開戶銀行省市編碼
private String account_number = "";// 銀行賬號
private String store_name; // 門店名稱
private String store_address_code; // 門店省市編碼
private String store_street; // 門店街道名稱
private String store_entrance_pic; // 門店門口照片
private String indoor_pic; // 店內環境照片
private String merchant_shortname; // 商戶簡稱
private String service_phone; // 客服電話
private String product_desc; // 售賣商品/提供服務描述
private String rate = "0.6%"; // 費率
private String contact; // 超級管理員姓名
private String contact_phone; // 手機號碼
public WxSmallModel(String cert_sn, String id_card_copy, String id_card_national, String id_card_name, String id_card_number,
String id_card_valid_time, String account_bank, String bank_address_code, String account_number, String store_name,
String store_address_code, String store_street, String store_entrance_pic, String indoor_pic, String merchant_shortname,
String service_phone, String product_desc, String contact, String contact_phone, String key) {
this.cert_sn = cert_sn;
this.id_card_copy = id_card_copy;
this.id_card_national = id_card_national;
this.id_card_name = id_card_name;
this.id_card_number = id_card_number;
this.id_card_valid_time = id_card_valid_time;
this.account_bank = account_bank;
this.bank_address_code = bank_address_code;
this.account_number = account_number;
this.store_name = store_name;
this.store_address_code = store_address_code;
this.store_street = store_street;
this.store_entrance_pic = store_entrance_pic;
this.indoor_pic = indoor_pic;
this.merchant_shortname = merchant_shortname;
this.service_phone = service_phone;
this.product_desc = product_desc;
this.contact = contact;
this.contact_phone = contact_phone;
this.sign = Signature.getSignSha(toMap(), key);
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getCert_sn() {
return cert_sn;
}
public void setCert_sn(String cert_sn) {
this.cert_sn = cert_sn;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign_type() {
return sign_type;
}
public void setSign_type(String sign_type) {
this.sign_type = sign_type;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getBusiness_code() {
return business_code;
}
public void setBusiness_code(String business_code) {
this.business_code = business_code;
}
public String getId_card_copy() {
return id_card_copy;
}
public void setId_card_copy(String id_card_copy) {
this.id_card_copy = id_card_copy;
}
public String getId_card_national() {
return id_card_national;
}
public void setId_card_national(String id_card_national) {
this.id_card_national = id_card_national;
}
public String getId_card_name() {
return id_card_name;
}
public void setId_card_name(String id_card_name) {
this.id_card_name = id_card_name;
}
public String getId_card_number() {
return id_card_number;
}
public void setId_card_number(String id_card_number) {
this.id_card_number = id_card_number;
}
public String getId_card_valid_time() {
return id_card_valid_time;
}
public void setId_card_valid_time(String id_card_valid_time) {
this.id_card_valid_time = id_card_valid_time;
}
public String getAccount_bank() {
return account_bank;
}
public void setAccount_bank(String account_bank) {
this.account_bank = account_bank;
}
public String getBank_address_code() {
return bank_address_code;
}
public void setBank_address_code(String bank_address_code) {
this.bank_address_code = bank_address_code;
}
public String getAccount_number() {
return account_number;
}
public void setAccount_number(String account_number) {
this.account_number = account_number;
}
public String getStore_name() {
return store_name;
}
public void setStore_name(String store_name) {
this.store_name = store_name;
}
public String getStore_address_code() {
return store_address_code;
}
public void setStore_address_code(String store_address_code) {
this.store_address_code = store_address_code;
}
public String getStore_street() {
return store_street;
}
public void setStore_street(String store_street) {
this.store_street = store_street;
}
public String getStore_entrance_pic() {
return store_entrance_pic;
}
public void setStore_entrance_pic(String store_entrance_pic) {
this.store_entrance_pic = store_entrance_pic;
}
public String getIndoor_pic() {
return indoor_pic;
}
public void setIndoor_pic(String indoor_pic) {
this.indoor_pic = indoor_pic;
}
public String getMerchant_shortname() {
return merchant_shortname;
}
public void setMerchant_shortname(String merchant_shortname) {
this.merchant_shortname = merchant_shortname;
}
public String getService_phone() {
return service_phone;
}
public void setService_phone(String service_phone) {
this.service_phone = service_phone;
}
public String getProduct_desc() {
return product_desc;
}
public void setProduct_desc(String product_desc) {
this.product_desc = product_desc;
}
public String getRate() {
return rate;
}
public void setRate(String rate) {
this.rate = rate;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public String getContact_phone() {
return contact_phone;
}
public void setContact_phone(String contact_phone) {
this.contact_phone = contact_phone;
}
public Map<String, Object> toMap() {
Map<String, Object> map = new HashMap<String, Object>();
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
Object obj;
try {
obj = field.get(this);
if (obj != null) {
map.put(field.getName(), obj);
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
return map;
}
}
HttpsRequest .java
package com.pay.wechat.util;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import javax.net.ssl.SSLContext;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import com.pay.wechat.protocol.pay_protocol.ScanPayReqDataSp;
import com.pay.wechat.util.xmlstream.XStreamFactory;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
/**
* HTTP 請求類
*
* @author libaibai
* @version 1.0 2020年5月31日
*/
@Component
public class HttpsRequest {
public interface ResultListener {
public void onConnectionPoolTimeoutError();
}
private static Logger LOG = LogManager.getLogger(HttpsRequest.class);
private boolean hasInit = false;
// 連接超時時間,默認10秒
private int socketTimeout = 10000;
// 傳輸超時時間,默認30秒
private int connectTimeout = 30000;
// 請求器的配置
private RequestConfig requestConfig;
// HTTP請求器
private CloseableHttpClient httpClient;
/**
* 證書初始化
*
* @throws UnrecoverableKeyException
* @throws KeyManagementException
* @throws NoSuchAlgorithmException
* @throws KeyStoreException
* @throws IOException
*/
public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException {
init();
}
private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream instream = HttpsRequest.class.getClassLoader().getResourceAsStream(Configure.CERTLOCAL_PATHx);// 加載本地的證書進行https加密傳輸
try {
keyStore.load(instream, Configure.CERTPASSWORD.toCharArray());// 設置證書密碼
} catch (Exception e) {
LOG.error("加載證書異常", e);
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, Configure.CERTPASSWORD.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
// 根據默認超時限制初始化requestConfig
requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
hasInit = true;
}
/**
* 通過Https往API GET
*
* @param url API地址
* @return API回包的實際數據
* @throws IOException
* @throws KeyStoreException
* @throws UnrecoverableKeyException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public String sendGET(String url)
throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
if (!hasInit) {
init();
}
String result = null;
HttpGet httpGet = new HttpGet(url);
// 得指明使用UTF-8編碼,否則到API服務器XML的中文不能被成功識別
httpGet.addHeader("Content-Type", "text/xml");
// 設置請求器的配置
httpGet.setConfig(requestConfig);
try {
HttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
} catch (Exception e) {
LOG.error("HTTP Get請示異常", e);
} finally {
httpGet.abort();
}
return result;
}
/**
* 通過Https往API post
*
* @param url API地址
* @param Object 要提交的Object數據對象
* @return API回包的實際數據
* @throws IOException
* @throws KeyStoreException
* @throws UnrecoverableKeyException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public String sendPostObject(String url, HttpEntity postEntity)
throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
if (!hasInit) {
init();
}
String result = null;
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.MULTIPART_FORM_DATA.getMimeType());
httpPost.setEntity(postEntity);
// 設置請求器的配置
httpPost.setConfig(requestConfig);
try {
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
} catch (Exception e) {
LOG.error("HTTP POST 請求異常", e);
} finally {
httpPost.abort();
}
return result;
}
/**
* 通過Https往API post xml數據
*
* @param url API地址
* @param xmlObj 要提交的XML數據對象
* @return API回包的實際數據
* @throws IOException
* @throws KeyStoreException
* @throws UnrecoverableKeyException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public String sendPost(String url, Object xmlObj)
throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
if (!hasInit) {
init();
}
String result = null;
HttpPost httpPost = new HttpPost(url);
// 解決XStream對出現雙下劃線的bug
// XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8",
// new XmlFriendlyNameCoder("-_", "_")));
XStream xStream = XStreamFactory.getXStream(new XmlFriendlyNameCoder("_-", "_"));
// 將要提交給API的數據對象轉換成XML格式數據Post給API
String postDataXML = xStream.toXML(xmlObj);
LOG.info("請求微信接口->url=" + url + ",data=" + postDataXML);
// LOG.info("data="+StringEscapeUtils.unescapeXml(postDataXML));// 轉義字符
// 得指明使用UTF-8編碼,否則到API服務器XML的中文不能被成功識別
StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
// 設置請求器的配置
httpPost.setConfig(requestConfig);
try {
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
} catch (Exception e) {
LOG.error("HTTP POST 請求異常", e);
} finally {
// httpPost.abort();
httpPost.releaseConnection();
}
return result;
}
/**
* 設置連接超時時間
*
* @param socketTimeout 連接時長,默認10秒
*/
public void setSocketTimeout(int socketTimeout) {
this.socketTimeout = socketTimeout;
resetRequestConfig();
}
/**
* 設置傳輸超時時間
*
* @param connectTimeout 傳輸時長,默認30秒
*/
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
resetRequestConfig();
}
private void resetRequestConfig() {
requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
}
/**
* 允許商戶自己做更高級更復雜的請求器配置
*
* @param requestConfig 設置HttpsRequest的請求器配置
*/
public void setRequestConfig(RequestConfig requestConfig) {
this.requestConfig = requestConfig;
}
public static void main(String[] args) {
String appid = "111";
String mch_id = "2222";
String sub_appid = "3333";
String sub_mch_id = "4444";
String key = "5555";
String body = "aaaa";
String detail = "dddd";
String attach = "#*#{\"pn\":\"粵B12345\",\"aid\":\"123456789\", \"vm\":\"true\"}#*#";
String out_trade_no = "ffffff";
int total_fee = 100;
String spbill_create_ip = "2222";
String trade_type = "ggggg";
String product_id = "hhhhh";
String openid = "jjjjj";
String sub_openid = null;
ScanPayReqDataSp data = new ScanPayReqDataSp(appid, mch_id, sub_appid, sub_mch_id, key, body, detail, attach, out_trade_no, total_fee,
spbill_create_ip, trade_type, product_id, openid, sub_openid);
HttpsRequest request;
try {
request = new HttpsRequest();
request.sendPost("", data);
} catch (Exception e) {
e.printStackTrace();
}
}
}
WxSmallSubmitBo .java
package com.pay.wechat.bo.small;
import org.springframework.stereotype.Component;
import com.pay.wechat.protocol.WxSmallModel;
import com.pay.wechat.util.HttpsRequest;
import com.pay.wechat.util.WxAesGcmExample;
import com.pay.wechat.util.WxRSAEncryptUtil;
import com.util.Config;
/**
* 小微商戶進件
*
* @author libaibai
* @version 1.0 2020年5月26日
*/
@Component
public class WxSmallSubmitBo {
public void exe() {
// 獲取解密證書得到
String associatedData = ""; // encrypt_certificate.associated_data
String nonce = ""; // encrypt_certificate.nonce
String cipherText = ""; // encrypt_certificate.ciphertext
String wechatpayCert = null; // 證書
try {
wechatpayCert = WxAesGcmExample.aesgcmDecrypt(associatedData, nonce, cipherText);
System.out.println("wechatpayCert=" + wechatpayCert);
} catch (Exception e) {
e.printStackTrace();
}
try {
String key = Config.APIKEY;
String cert_sn = ""; // 證書序列號
String id_card_copy = "-BMpJciLVOAFz1iHGbR5fnI5rJC0K10Qz9KErNvvOsVYuSDBIjO-en4Z-dfzbOCpY0ldafxs"; // 請填寫由圖片上傳接口預先上傳圖片生成好的media_id
String id_card_national = "-hqdexrNmI5slGHj3QDW_E"; // 請填寫由圖片上傳接口預先上傳圖片生成好的media_id
String id_card_name = WxRSAEncryptUtil.rsaEncryptByCert("李百百", wechatpayCert); // 身份證姓名,
String id_card_number = WxRSAEncryptUtil.rsaEncryptByCert("440523xxxxxxxxx", wechatpayCert); // 身份證號碼
String id_card_valid_time = "[\"2011-06-24\",\"2021-06-24\"]"; // 身份證有效期限,例如:["1970-01-01","長期"]
String account_bank = WxRSAEncryptUtil.rsaEncryptByCert("李百百", wechatpayCert); // 開戶銀行
String bank_address_code = "440300"; // 開戶銀行省市編碼
String account_number = WxRSAEncryptUtil.rsaEncryptByCert("6212265000004604312", wechatpayCert);// 銀行賬號
String store_name = "生態園停車"; // 門店名稱
String store_address_code = "440300"; // 門店省市編碼
String store_street = "南山科技園園"; // 門店街道名稱
String store_entrance_pic = "-s4917roa97XFJf0GPdBNHEvkyf0XPzrOjeKjoBYmEL_eSk7I"; // 門店門口照片
String indoor_pic = "-s4917roa97XFJf0GPdBNHEvkyf0XPzrOjeKjoBYmEL_eSk7I"; // 店內環境照片
String merchant_shortname = "科技園停車"; // 商戶簡稱
String service_phone = "13666666666"; // 客服電話
String product_desc = "停車繳費"; // 售賣商品/提供服務描述
String contact = WxRSAEncryptUtil.rsaEncryptByCert("李百百", wechatpayCert); // 超級管理員姓名
String contact_phone = WxRSAEncryptUtil.rsaEncryptByCert("13666666666", wechatpayCert); // 手機號碼
System.out.println("contact="+ contact);
WxSmallModel small = new WxSmallModel(cert_sn, id_card_copy, id_card_national, id_card_name, id_card_number, id_card_valid_time,
account_bank, bank_address_code, account_number, store_name, store_address_code, store_street, store_entrance_pic, indoor_pic,
merchant_shortname, service_phone, product_desc, contact, contact_phone, key);
HttpsRequest request = new HttpsRequest();
String url = "https://api.mch.weixin.qq.com/applyment/micro/submit";
String str = request.sendPost(url, small);
System.out.println(str);
} catch (Exception e) {
}
}
public static void main(String[] args) {
WxSmallSubmitBo bo = new WxSmallSubmitBo();
bo.exe();
}
}
運行main方法得到
雖然微信把小微商戶進件api關閉了,但是聽說有服務商還在使用。。。。