微信小微商戶進件(三):申請入駐

 

前面講了,獲取證書和獲取證書和上傳圖片,現在我們進入主題,講申請入駐。

 

首先打開官方文檔: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關閉了,但是聽說有服務商還在使用。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章