(13条消息)小微商户特约商户进件V3版本对接
(13条消息)⼩微商户特约商户进件V3版本对接今天我们来讲⼀下⼩微商户进件V3版本的接⼝对接。
⾸先我们来看⼀下官⽅的⽂档:
pay.weixin.qq/wiki/doc/apiv3/wxpay/tool/applyment/chapter3_1.shtml
根据⽂档提⽰,⼩微商户进件对接协议和特约商户是⼀样的,只是参数不⼀样。我们这⾥以⼩微商户说明(主要是公司需要)。
⾸先引⼊JRE包,后⾯会⽤到。这⾥使⽤的是maven。
1. <dependency>
2.    <groupId>com.github.wechatpay-apiv3</groupId>
3.    <artifactId>wechatpay-apache-httpclient</artifactId>
4.    <version>0.2.1</version>
5. </dependency>
进件需要我们先上传⾝份证照⽚,请参考
⼩微商户进件(⼆):图⽚上传
上代码
ApplymentBo.java
1. package com.pay.wechat.bo.small.v3;
2.
3. import java.io.ByteArrayInputStream;
4. import X509Certificate;
5. import java.util.HashMap;
6. import java.util.Map;
7.
8. import org.springframework.stereotype.Component;
9.
10. import com.util.OrderIDUtil;
11. import com.pay.wechat.bo.small.v3.util.CertUtil;
12. import com.pay.wechat.bo.small.v3.util.HttpUrlUtil;
13. import com.pay.wechat.bo.small.v3.util.RsaEncryptUtil;
14. import ib.apache.httpclient.util.PemUtil;
15.
16. import net.sf.json.JSONObject;
17.
18. /**
19.  * ⼩微商户进件V3版本<br>
20.  * ⽂档地址:pay.weixin.qq/wiki/doc/apiv3/wxpay/tool/applyment/chapter3_1.shtml
21.  *
22.  * @author libaibai@chinatenet
23.  * @version 1.0 2020年9⽉3⽇
24.  */
25. @Component
26. public class ApplymentBo {
27.
28. /**
29.  * 进件
30.  *
31.  * @param contactName 管理员姓名
32.  * @param contactIdNum 管理员⾝份证号码
33.  * @param contactMobile 管理员⼿机号码
34.  * @param contactMail 管理员邮箱
35.  * @param microName 门店名称
36.  * @param microAddressCode
37.  *        门店编码,参考:pay.weixin.qq/wiki/doc/apiv3/wxpay/ecommerce/applyments/chapter4_1.shtml
38.  * @param microAddress 门店地址
39.  * @param idCardCopy ⾝份证正⾯照⽚
40.  * @param idCardNational ⾝份证反⾯照⽚
41.  * @param cardPeriodBegin ⾝份证有效期开始时间,格式:2011-06-24
42.  * @param cardPeriodEnd ⾝份证有效期结束时间,格式:2011-06-24
43.  * @param servicePhone 客户电话
44.  * @param accountBank 开户⾏银⾏名称
45.  * @param bankAddressCode 开户⾏编码
46.  * @param bankName 开户银⾏全称(含⽀⾏] <pre>
47.  * 1、“开户银⾏”为17家直连银⾏⽆需填写
48.  * 2、“开户银⾏”为其他银⾏,则开户银⾏全称(含⽀⾏)和开户银⾏联⾏号⼆选⼀ //
49.  * 3、需填写银⾏全称,如"深圳农村商业银⾏XXX⽀⾏",详细参见《开户银⾏全称(含⽀⾏)对照表》
50.  * ⽰例值:施秉县农村信⽤合作联社城关信⽤社
51.  * </pre>
52.  *
53.  * @param accountNumber 银⾏卡号
54.  * @throws Exception
55.  */
56. public void exe(String contactName, String contactIdNum, String contactMobile, String contactMail, String microName, String microAddressCode,
57. String microAddress, String idCardCopy, String idCardNational, String cardPeriodBegin, String cardPeriodEnd, String servicePhone,
58. String accountBank, String bankAddressCode, String bankName, String accountNumber) throws Exception {
59.
60. // 获取平台证书并解析⽅法在后⾯
61. String certString = CertStr();
62. ByteArrayInputStream stringStream = new Bytes());
63. // 下⾯所有加密参数需要的对象
64. X509Certificate certx = PemUtil.loadCertificate(stringStream);
65.
66. // 超级管理员信息
66. // 超级管理员信息
67. Map<String, Object> contact_info = new HashMap<String, Object>();
68. String contact_name = RsaEncryptUtil.rsaEncryptOAEP(contactName, certx); // 超级管理员姓名
69. String contact_id_number = RsaEncryptUtil.rsaEncryptOAEP(contactIdNum, certx); // 超级管理员⾝份证件号码
70. String mobile_phone = RsaEncryptUtil.rsaEncryptOAEP(contactMobile, certx);// 联系⼿机
71. String contact_email = RsaEncryptUtil.rsaEncryptOAEP(contactMail, certx);// 联系邮箱
72. contact_info.put("contact_name", contact_name);
73. contact_info.put("contact_id_number", contact_id_number);
74. contact_info.put("mobile_phone", mobile_phone);
75. contact_info.put("contact_email", contact_email);
76.
77. // 主体资料
78. String subject_type = "SUBJECT_TYPE_MICRO"; // 主体类型
79. String micro_biz_type = "MICRO_TYPE_STORE"; // ⼩微经营类型
80. String micro_name = microName; // 门店名称
81. String micro_address_code = microAddressCode; // 门店省市编码
谈判方案82. String micro_address = microAddress; // 门店街道名称
83.
84. String store_entrance_pic = "oO5EoYZsdukezw2NXUxEkb9vTU7PgOu5GyMpNVdMVj5aJAwD85_8kNpakg-s4917roa97XFJf0GPdBNHEvkyf0XPzrOjeKjoBYmEL_eSk7I"; // 门店门⼝照⽚
85. String micro_indoor_copy = "oO5EoYZsdukezw2NXUxEkb9vTU7PgOu5GyMpNVdMVj5aJAwD85_8kNpakg-s4917roa97XFJf0GPdBNHEvkyf0XPzrOjeKjoBYmEL_eSk7I"; // 店内环境照⽚
86.
87. // 证件类型,IDENTIFICATION_TYPE_IDCARD
88. String id_doc_type = "IDENTIFICATION_TYPE_IDCARD";
89.
90. // String id_card_copy = idCardCopy; // ⾝份证⼈像⾯照⽚
91. // String id_card_national = idCardNational; // ⾝份证国徽⾯照⽚
92.
93. String id_card_name = RsaEncryptUtil.rsaEncryptOAEP(contactName, certx); // ⾝份证姓名
94. String id_card_number = RsaEncryptUtil.rsaEncryptOAEP(contactIdNum, certx); // ⾝份证号码
95. // String card_period_begin = "2011-06-24"; // ⾝份证有效期开始时间⽰例值:2026-06-06
96. // String card_period_end = "2021-06-24"; // ⾝份证有效期结束时间⽰例值:2026-06-06
97.
98. Map<String, Object> subject_info = new HashMap<String, Object>(); // 主体资料
99. Map<String, Object> micro_biz_info = new HashMap<String, Object>(); // ⼩微商户辅助材料
100. Map<String, Object> micro_store_info = new HashMap<String, Object>(); // 门店场所信息
101. Map<String, Object> identity_info = new HashMap<String, Object>(); // 经营者⾝份证件
102. Map<String, Object> id_card_info = new HashMap<String, Object>(); // ⾝份证信息
103.
104. micro_store_info.put("micro_name", micro_name);
105. micro_store_info.put("micro_address_code", micro_address_code);
106. micro_store_info.put("micro_address", micro_address);
107. micro_store_info.put("store_entrance_pic", store_entrance_pic);
108. micro_store_info.put("micro_indoor_copy", micro_indoor_copy);
109.
110. micro_biz_info.put("micro_biz_type", micro_biz_type);
111. micro_biz_info.put("micro_store_info", micro_store_info);
112.
113. id_card_info.put("id_card_copy", idCardCopy);
114. id_card_info.put("id_card_national", idCardNational);
115. id_card_info.put("id_card_name", id_card_name);
116. id_card_info.put("id_card_number", id_card_number);
117. id_card_info.put("card_period_begin", cardPeriodBegin);
118. id_card_info.put("card_period_end", cardPeriodEnd);
119.
120. identity_info.put("id_doc_type", id_doc_type);
121. identity_info.put("id_card_info", id_card_info);
122.
123. subject_info.put("subject_type", subject_type);
124. subject_info.put("micro_biz_info", micro_biz_info);
125. subject_info.put("identity_info", identity_info);
126.
127. // 经营资料
128. // String merchant_shortname = "张三停车场"; // 商户简称
129. // String service_phone = "0755222222"; //
130. Map<String, Object> business_info = new HashMap<String, Object>();
131. business_info.put("merchant_shortname", microName);
132. business_info.put("service_phone", servicePhone);
133.
134. // 结算规则
135. // ⼊驻结算规则ID;请选择结算规则ID,详细参见《费率结算规则对照表》⽰例值:⼩微商户:703
136. String settlement_id = "703";//
137. String qualification_type = "停车缴费"; // 所属⾏业;请填写所属⾏业名称,建议参见《费率结算规则对照表》⽰例值:餐饮
138. Map<String, Object> settlement_info = new HashMap<String, Object>();
139. settlement_info.put("settlement_id", settlement_id);
140. settlement_info.put("qualification_type", qualification_type);
141.
142. // 收款银⾏卡
143. // 账户类型若主体为⼩微,可填写:经营者个⼈银⾏卡枚举值:
144. // BANK_ACCOUNT_TYPE_PERSONAL:经营者个⼈银⾏卡
145. // ⽰例值:BANK_ACCOUNT_TYPE_CORPORATE
146. String bank_account_type = "BANK_ACCOUNT_TYPE_PERSONAL";
147.
148. String account_name = RsaEncryptUtil.rsaEncryptOAEP(contactName, certx); // 开户名称(该字段需进⾏加密处理)
149. // String account_bank = "建设银⾏"; // 开户银⾏开户银⾏,详细参见《开户银⾏对照表》⽰例值:⼯商银⾏
150. // String bank_address_code = "440300"; // 开户银⾏省市编码⾄少精确到市,详细参见《省市区编号对照表》⽰例值:110000
151.
152. // 1、“开户银⾏”为17家直连银⾏⽆需填写
153. // 2、“开户银⾏”为其他银⾏,则开户银⾏全称(含⽀⾏)和开户银⾏联⾏号⼆选⼀
154. // 3、需填写银⾏全称,如"深圳农村商业银⾏XXX⽀⾏",详细参见《开户银⾏全称(含⽀⾏)对照表》
155. // ⽰例值:施秉县农村信⽤合作联社城关信⽤社
156. // String bank_name = ""; // 开户银⾏全称(含⽀⾏]
156. // String bank_name = ""; // 开户银⾏全称(含⽀⾏]
157. String account_number = RsaEncryptUtil.rsaEncryptOAEP(accountNumber, certx); // 银⾏账号(该字段需进⾏加密处理)
158. Map<String, Object> bank_account_info = new HashMap<String, Object>();
159. bank_account_info.put("bank_account_type", bank_account_type);
160. bank_account_info.put("account_name", account_name);
161. bank_account_info.put("account_bank", accountBank);
162. bank_account_info.put("bank_address_code", bankAddressCode);
163. bank_account_info.put("bank_name", bankName);
164. bank_account_info.put("account_number", account_number);
165.
166. String business_code = OrderID(null); // 申请单号
167. Map<String, Object> map = new HashMap<String, Object>();
168. map.put("business_code", business_code);
169. map.put("contact_info", contact_info);
170. map.put("subject_info", subject_info);
171. map.put("business_info", business_info);
172. map.put("settlement_info", settlement_info);
173. map.put("bank_account_info", bank_account_info);
174. try {
175. String body = JSONObject.fromObject(map).toString();
176. String str = HttpUrlUtil.sendPost(body);
177. System.out.println(str);
178. } catch (Exception e) {
179. e.printStackTrace();
180. }
181. }
182.
183. public static void main(String[] args) {
184. String contactName = "张**"; // 超级管理员姓名
185. String contactIdNum = "520201************"; // ⾝份证号码
186. String contactMobile = "139*********"; // ⼿机号码
187. String contactMail = "3*******@qq"; // 联系邮箱
188. String microName = "联运公司停车场"; // 门店名称(也⽤于简称)
189.
春暖花开的朋友圈说说春天唯美说说短句190. // 门店省市编码
191. // 参考:pay.weixin.qq/wiki/doc/apiv3/wxpay/ecommerce/applyments/chapter4_1.shtml
192. String microAddressCode = "520200";
193. String microAddress = "**************路52号"; // 门店地址
194.
195. String idCardCopy = "eYjXW9AMg-***********************************************-w508XSWniUlM"; // ⾝份证正⾯照
196. String idCardNational = "eYjXW9AMg-************************************-RPk8-eZ7PJvD8XBtaTZ1a1YEIN1PSeuRnkM"; // ⾝份证反⾯照197.
198. String cardPeriodBegin = "2007-08-10"; // ⾝份证有效期开始时间2011-06-24
199. String cardPeriodEnd = "2027-08-10";// ⾝份证有效期结束时间2011-06-24
200. String servicePhone = "139*********";// ;⽆特殊使⽤管理员⼿机号码
201. String accountBank = "招商银⾏"; // 开户银⾏
202. String bankAddressCode = "520200"; // 开户银⾏省市编码⾄少精确到市,详细参见《省市区编号对照表》⽰例值:110000;
203.
204. // 1、“开户银⾏”为17家直连银⾏⽆需填写
205. // 2、“开户银⾏”为其他银⾏,则开户银⾏全称(含⽀⾏)和开户银⾏联⾏号⼆选⼀
206. // 3、需填写银⾏全称,如"深圳农村商业银⾏XXX⽀⾏",详细参见《开户银⾏全称(含⽀⾏)对照表》质押合同
207. // ⽰例值:施秉县农村信⽤合作联社城关信⽤社
208. String bankName = ""; // 开户银⾏全称(含⽀⾏]
209. String accountNumber = "************************"; // 银⾏账号
210.
211. ApplymentBo t = new ApplymentBo();
212. try {
213. t.exe(contactName, contactIdNum, contactMobile, contactMail, microName, microAddressCode, microAddress, idCardCopy, idCardNational, 214. cardPeriodBegin, cardPeriodEnd, servicePhone, accountBank, bankAddressCode, bankName, accountNumber);
215. } catch (Exception e) {
216. e.printStackTrace();
217. }
218. }
219. }
httpUrlUtil.java
1. package com.pay.wechat.bo.small.v3.util;
2.
3. import java.security.PrivateKey;
4. import java.security.Signature;
5. import java.util.Base64;
6.
7. import javax.Response;
8.
9. import f.jaxrs.client.WebClient;
10.
11. import com.util.Config;
12. import com.util.UUIDUtil;
13.
14. import okhttp3.HttpUrl;
15.
16. /**
17.  * HttpUrl⼯具类
18.  *
19.  * @author libaibai
20.  * @version 1.0 2020年9⽉4⽇
21.  */
22. public class HttpUrlUtil {
23.
24. public static String SCHEMA = "WECHATPAY2-SHA256-RSA2048";
25. public static String merchantId = Config.MCHIDSP; // 服务商
26.
26.
27. public static String POST = "POST";
28. public static String GET = "GET";
29.
30. public static String host = "h.weixin.qq";
31. public static String APPLY_PATH = "/v3/applyment4sub/applyment/"; // 申请单url
32. public static String CERT_PATH = "/v3/certificates"; // 获取平台证书url
33. public static String APPLY_QUERY_PATH = "/v3/applyment4sub/applyment/applyment_id/"; // 查询申请状态
34.
35. /**
36.  * POST请求
37.  */
38. public static String sendPost(String body) {
宫崎骏的所有作品电影39. String url = host + APPLY_PATH;
40. try {
41. // 获取平台商户证书序列号
42. String wxSerialNo = CertSerialNo();
43. String authorization = getToken(POST, url, body);
44. WebClient client = ate(host);
45. set();
46. client.header("Content-Type", "application/json; charset=UTF-8");
47. client.header("Accept", "application/json");
48. client.header("user-agent", "application/json");
49. client.header("Wechatpay-Serial", wxSerialNo);
50. client.header("Authorization", authorization);
51. client.path(APPLY_PATH);
52. Response r = client.post(body);
53. adEntity(String.class);
54. } catch (Exception e) {
55. return null;
56. }
57. }
58.
59. /**
60.  * get请求
61.  */
62. public static String sendGet() {
63. // 请求URL
64. String url = host + CERT_PATH;
65. try {
66. String authorization = getToken(GET, url, "");
67. WebClient client = ate(host);
68. set();
69. client.header("Content-Type", "application/json; charset=UTF-8");
70. client.header("Accept", "application/json");
71. client.header("User-Agent", "application/json");
72. client.header("Authorization", authorization);
73. client.path(CERT_PATH);
74. Response r = ();
75. adEntity(String.class);
76. } catch (Exception e) {
77. e.printStackTrace();
78. return null;
79. }
80. }
81.
82. /**
83.  * get请求
84.  */
85. public static String sendGet(String applymentId) {
86. // 请求URL
87. String url = host + APPLY_QUERY_PATH + applymentId;
88. try {
89. String authorization = getToken(GET, url, "");
90. WebClient client = ate(host);
91. set();
92. client.header("Content-Type", "application/json; charset=UTF-8");
93. client.header("Accept", "application/json");
94. client.header("User-Agent", "application/json");
95. client.header("Authorization", authorization);
96. client.path(APPLY_QUERY_PATH + applymentId);
97. Response r = ();
98. adEntity(String.class);
99. } catch (Exception e) {
100. e.printStackTrace();
101. return null;
梅花象征着什么意义
102. }
103. }
104.
105. /**
106.  * 获取加密串
107.  *
108.  * @param method
109.  * @param url
110.  * @param body
111.  * @return
112.  */
113. public static String getToken(String method, String url, String body) {
114. String nonceStr = UUID32();
115. long timestamp = System.currentTimeMillis() / 1000;
116. HttpUrl httpUrl = HttpUrl.parse(url);
116. HttpUrl httpUrl = HttpUrl.parse(url);
117. String message = buildMessage(method, httpUrl, timestamp, nonceStr, body);
118. String signature = null;
119. String certificateSerialNo = null;
120. try {
121. signature = Bytes("utf-8"));
122. certificateSerialNo = SerialNo("");
123. } catch (Exception e) {
明明是一场空在梦里浮沉是什么歌124. e.printStackTrace();
125. }
126.
127. return SCHEMA + " mchid=\"" + merchantId + "\"," + "nonce_str=\"" + nonceStr + "\"," + "timestamp=\"" + timestamp + "\"," + "serial_no=\"" 128. + certificateSerialNo + "\"," + "signature=\"" + signature + "\"";
129. }
130.
131. /**
132.  * 得到签名字符串
133.  */
134. public static String sign(byte[] message) throws Exception {
135. Signature sign = Instance("SHA256withRSA");
136. PrivateKey privateKey = PrivateKey();
137. sign.initSign(privateKey);
138. sign.update(message);
139. Encoder().encodeToString(sign.sign());
140. }
141.
142. public static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
143. String canonicalUrl = dedPath();
144. if (dedQuery() != null) {
145. canonicalUrl += "?" + dedQuery();
146. }
147. return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
148. }
149. }
CertUtil.java
1. package com.pay.wechat.bo.small.v3.util;
2.
3. import java.io.BufferedInputStream;
4. import java.io.FileInputStream;
5. import java.io.IOException;
6. import java.io.InputStream;
7. import java.nio.charset.StandardCharsets;
8. import java.nio.file.Files;
9. import java.nio.file.Paths;
10. import java.security.KeyFactory;
11. import java.security.NoSuchAlgorithmException;
12. import java.security.PrivateKey;
13. import CertificateException;
14. import CertificateExpiredException;
15. import CertificateFactory;
16. import CertificateNotYetValidException;
17. import X509Certificate;
18. import java.security.spec.InvalidKeySpecException;
19. import java.security.spec.PKCS8EncodedKeySpec;
20.
21. import dec.binary.Base64;
22.
23. import net.sf.json.JSONArray;
24. import net.sf.json.JSONObject;
25.
26. /**
27.  * 证书⼯具类
28.  *
29.  * @author libaibai
30.  * @version 1.0 2020年9⽉4⽇
31.  */
32. public class CertUtil {
33.
34. // 证书私钥路径(从商户平台下载,保存在本地)
35. public static String APICLIENT_KEY = "G:\\workspace\\dlysw\\src\\main\\resources\\conf\\cert\\apiclient_key.pem";
36.
37. // 商户证书路径(从商户平台下载,保存在本地)
38. public static String APICLIENT_CERT = "G:\\workspace\\dlysw\\src\\main\\resources\\conf\\cert\\apiclient_cert.pem";
39.
40. /**
41.  * 获取私钥。
42.  *
43.  * @param apiclient_key 私钥⽂件路径 (required)
44.  * @return 私钥对象
45.  */
46. public static PrivateKey getPrivateKey() throws IOException {
47. String content = new (APICLIENT_KEY)), StandardCharsets.UTF_8);
48. try {
49. String privateKey = place("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
50. KeyFactory kf = Instance("RSA");
51. atePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)));
52. } catch (NoSuchAlgorithmException e) {
53. throw new RuntimeException("当前Java环境不⽀持RSA", e);
54. } catch (InvalidKeySpecException e) {
55. throw new RuntimeException("⽆效的密钥格式");
56. }

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。