项目背景:

小微商户根据接口申请入驻、查看状态、进行签约。商户信息配置、Native扫码及小程序发起支付、查询订单、进行退款、查询退款。小微商户资料修改及提现。

一、小微商户进件

遇到问题:

1、返回错误信息及解决办法

(1)、输入商户号后、平台提示证书不存在。API文档中也没有具体解释(如图1-1)?

图 1-1

已解决:关键在于参数中的商户号输入错误,经过沟通发现该商户号有两个,换个账号就可以解决问题

(2)解密敏感信息失败                                        已解决--------仔细查看需要进行加密的参数,当时手机号没有加密导致微信方解密敏感信息失败

(3)签名失败                                                      已解决--------参数中的sign字段应方在最后再进行签名,不能跟api中的参数顺序一样

(4)身份证正面识别失败                                    已解决--------过期或失效的身份证无法识别成功

2、Java实现AES加密,抛出异常(如图1-2):

图 1-2

去该地址http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html下载${jdk_home}/jre/lib/security和${jre_home}/lib/security目录下的 local_policy.jar 和 US_export_policy.jar文件并且将其覆盖

3、小微商户进件流程

  • 申  请  入  驻:  (1)、先获取平台证书及序列号,并用返回的参数对证书进行解密得到平台证书的原文。ps:该原文用于对敏感信息加密

(2)、使用加密方法对敏感信息进行加密

(3)、将图片上传到接口获取图片id填写到请求入驻参数中

(4)、剩下的参数依次填入map中最后进行签名使用证书通过接口上传商户信息,ps:注意中文编码

  • 查询申请状态:(1)、查询时使用自定义的编号或者微信返回的申请单号其一即可查询,ps:签名也是在最后的参数

(2)、将会返回审核状态,如果已审核成功变成待签约状态将会返回链接,商户扫码即可

二、小微商户配置

遇到问题:

1、 返回错误信息及解决办法

(1)绑定APPID时注意接口sub_appid参数示例                           已解决:此处的sub_appid对小程序支付有影响,需配置为小程序的id否则在下单时会造成公众号id与sub_appid不匹配

2、配置流程

(1)将商户的商户号与固定小程序id绑定即可

三、小微商户交易

遇到问题:(appid-公众号id,mchid-商户号,subappid-小程序id及签名所需公钥请联系相关人员)

1、返回错误信息及解决办法

(1)参数的必填项为可选填,结果返回缺少参数                         已解决:每个参数看好备注,不同的交易方式参数的可填项不一样

(2)native交易方式返回的支付URL打开无法支付                      已解决:必须生成二维码后进行扫码支付,无法直接打开链接支付

(3)每天在没有余额时退款失败                                                  已解决:每天都会自动提现到银行卡内导致账户无余额,无法直接退款,必须有余额

(4)查询退款时可能有多单返回                                                  已解决:查询退款时,尽量使用退款单号查询,一个订单号会有退款总金额不超过订单金额的退款单数,当超过20单时必须使用退款单号

2、交易流程

(1)提交自己内部的唯一商品订单号、商品详情、金额(分)、交易方式等参数返回扫码地址或小程序调起支付的参数

(2)查询订单时提供商户号、微信订单号或商户订单号即可

(3)订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟,提供商户号、商户订单号即可关闭订单

                 (4)必须提供微信及内部订单号、内部唯一退款单号、订单总金额、退款金额申请退款,一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号再次申请退款

(5)查询退款提供退款单号即可

四、小微商户资料修改及提现

修改及提现流程:

(1)输入商户号及提现单的日期即可,提现单的日期是前一天的金额的提现,不是当天的交易金额

(2)提供商户号及银行名称、加密后的银行卡号即可修改成功

(3)重新发起提现时,如果提现一号的交易请提供2号的日期

(4)联系人信息提供后即可修改信息

五、代码实现

    本项目使用SSM模型开发

1 public classWeiXinAccountController {2 @Resource3 WeiXinAccountService weiXinAccountService;4     /**
5 * 上传图片的序列id6 *@return状态7      */
8     public ReturnModel<?>getPhotoid(@RequestBody WXPhotoModel wxPhotoModel){9         ReturnModel returnModel =weiXinAccountService.getPhotoid(wxPhotoModel);10         returnreturnModel;11 }12
13     /**
14 * 查询审核状态15 *@return状态16      */
17     public ReturnModel<?>queryForApply(@RequestBody WXApplyStateModel wxApplyStateModel){18         ReturnModel returnModel =weiXinAccountService.queryForApply(wxApplyStateModel);19         returnreturnModel;20 }21
22     /**
23 * 提交参数进行审核24 *@paramwxApplyForEntryModel 参数25 *@return是否提交成功//商户存在时不可编辑(不可再次提交)26      */
27     public ReturnModel<?>submitInfo(@RequestBody WXApplyForEntryModel wxApplyForEntryModel){28         returnweiXinAccountService.submitInfo(wxApplyForEntryModel);29 }30
31     /***32 * 绑定AppID配置33 *@paramwxAddSubDevConfigModel34 *@throws
35      */
36     public ReturnModel<?>addSubDevConfig(@RequestBody WXAddSubDevConfigModel wxAddSubDevConfigModel){37         returnweiXinAccountService.addSubDevConfig(wxAddSubDevConfigModel);38 }39
40     /**
41 * 统一下单native42 *@paramwxUnifiedOrderModel43 *@return
44      */
45     public ReturnModel<?>unifiedOrderByNATIVE(@RequestBody WXUnifiedOrderModel wxUnifiedOrderModel, HttpServletRequest httpServletRequest){46         String ip =WXHttpUtil.getSpbillCreateIp(httpServletRequest);47 wxUnifiedOrderModel.setSpbillCreateIp(ip);48         returnweiXinAccountService.unifiedOrderByNATIVE(wxUnifiedOrderModel);49 }50     /**
51 * 统一下单jsapi52 *@paramwxUnifiedOrderModel53 *@return
54      */
55     public ReturnModel<?>unifiedOrderByJSAPI(@RequestBody WXUnifiedOrderModel wxUnifiedOrderModel, HttpServletRequest httpServletRequest){56         String ip =WXHttpUtil.getSpbillCreateIp(httpServletRequest);57 wxUnifiedOrderModel.setSpbillCreateIp(ip);58         returnweiXinAccountService.unifiedOrderByJSAPI(wxUnifiedOrderModel);59 }60     /**
61 * 查询订单62 *@paramwxOrderQueryModel63 *@return
64      */
65     public ReturnModel<?>orderQuery(@RequestBody WXOrderQueryModel wxOrderQueryModel){66         returnweiXinAccountService.orderQuery(wxOrderQueryModel);67 }68     /**
69 * 关闭订单,如果支付失败则需要关闭订单避免重复支付或超时系统退出不再受理也需要关闭70 *@paramwxCloseOrderModel71 *@return
72      */
73     public ReturnModel<?>closeOrder(@RequestBody WXCloseOrderModel wxCloseOrderModel){74         returnweiXinAccountService.closeOrder(wxCloseOrderModel);75 }76
77     /**
78 * 申请退款79 *@paramwxRefundModel80 *@return
81      */
82     public ReturnModel<?>refund(@RequestBody WXRefundModel wxRefundModel){83         returnweiXinAccountService.refund(wxRefundModel);84 }85
86     /**
87 * 查询退款88 *@paramwxRefundQueryModel89 *@return
90      */
91     public ReturnModel<?>refundQuery(@RequestBody WXRefundQueryModel wxRefundQueryModel){92         returnweiXinAccountService.refundQuery(wxRefundQueryModel);93 }94
95     /**
96 * 提现状态查询97 *@paramwxQueryAutoWithdrawByDate98 *@return
99      */
100     public ReturnModel<?>queryAutoWithdrawByDate(@RequestBody WXQueryAutoWithdrawByDate wxQueryAutoWithdrawByDate){101         returnweiXinAccountService.queryAutoWithdrawByDate(wxQueryAutoWithdrawByDate);102 }103
104     /**
105 * 修改银行卡号106 *@parammodifyarchives107 *@return
108 *@throwsException109      */
110     public ReturnModel<?> modifyArchives(@RequestBody WXModifyArchivesModel modifyarchives) throwsException {111         returnweiXinAccountService.modifyArchives(modifyarchives);112 }113
114     /**
115 * 重新发起提现116 *@paramreautowithdrawbydate117 *@return
118      */
119     public ReturnModel<?>reAutoWithdrawByDate(@RequestBody WXQueryAutoWithdrawByDate reautowithdrawbydate) {120         returnweiXinAccountService.reAutoWithdrawByDate(reautowithdrawbydate);121 }122
123     /**
124 * 修改商户联系信息125 *@parammodifycontactinfo126 *@return
127 *128 *@throwsException129      */
130     public ReturnModel<?> modifyContactInfo(@RequestBody WXModifyContactInfoModel modifycontactinfo) throwsException {131         returnweiXinAccountService.modifyContactInfo(modifycontactinfo);132 }133 }

WXController

1 public class WeiXinAccountServiceImpl implementsWeiXinAccountService {2     private final Logger LOGGER = LoggerFactory.getLogger(WeiXinAccountServiceImpl.class);3     /**
4 * 准备申请入驻的参数5 *@return入驻的参数6 *@throwsException7      */
8     public SortedMap<String, String> applyForEntry(WXApplyForEntryModel wxApplyForEntryModel) throwsException {9         //先获取平台证书及序列号,并用返回的参数对证书进行解密得到平台证书的原文。10         //ps:该原文用于对敏感信息加密
11         String certificatesInfo =getCertficates();12         if(("fail").equals(certificatesInfo) || ("").equals(certificatesInfo)){13             return null;14 }15         JSONArray data =JSONObject.parseArray(16                 JSONObject.parseObject(certificatesInfo).getString("data"));17         //得到平台系列号
18         String serialNo =JSONObject.parseObject(19                 JSONObject.toJSONString(data.get(0))).getString("serial_no");20         //得到用于加密敏感信息的证书原文
21         String cert =WXPayUtil.getWXCert(data);22         String name =RSAEncryptUtil.rsaEncrypt(wxApplyForEntryModel.getIdCardName(),cert);23         wxApplyForEntryModel.setVersion("3.0");24 wxApplyForEntryModel.setCertSn(serialNo);25 wxApplyForEntryModel.setMchId(WXConstant.MCHID);26         wxApplyForEntryModel.setNonceStr(String.valueOf(newDate().getTime()));27 wxApplyForEntryModel.setSignType(WXConstant.SIGNTTYPE);28 wxApplyForEntryModel.setIdCardNumber(29 RSAEncryptUtil.rsaEncrypt(wxApplyForEntryModel.getIdCardNumber(),cert));30 wxApplyForEntryModel.setIdCardName(name);31 wxApplyForEntryModel.setAccountName(name);32 wxApplyForEntryModel.setAccountNumber(33 RSAEncryptUtil.rsaEncrypt(wxApplyForEntryModel.getAccountNumber(),cert));34 wxApplyForEntryModel.setContact(name);35 wxApplyForEntryModel.setContactPhone(36 RSAEncryptUtil.rsaEncrypt(wxApplyForEntryModel.getContactPhone(),cert));37         SortedMap reqPara =AnnotationUtil.parseObjectToMap(wxApplyForEntryModel);38         returnreqPara;39 }40     /**
41 * 得到平台证书包含的参数json42 *@return
43      */
44     publicString getCertficates(){45         SortedMap<String, String> reqDataToZS = new TreeMap<>();46         reqDataToZS.put("mch_id", WXConstant.MCHID);//服务商商户号
47         reqDataToZS.put("nonce_str", WXPayUtil.getRandomString(32));//随机字符串
48         reqDataToZS.put("sign_type", WXConstant.SIGNTTYPE);//签名类型
49         reqDataToZS.put("sign", WXPayUtil.generateSignature(reqDataToZS,WXConstant.KEY,WXConstant.HMACSHA256TYPE));//签名
50         String returnStr = WXPayHttpUtil.WXHttpPostXMLWithoutCert(WXConstant.ZHENGSHUURL,reqDataToZS);//证书接口返回所需参数
51         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);52         if(("FAIL").equals(result.get("result_code"))){53             return "fail";54 }55         return result.get("certificates");56 }57
58     /**
59 * 得到上传照片的id60 *@paramwxPhotoModel 图片61 *@return图片id62      */
63 @Override64     public ReturnModel<?>getPhotoid(WXPhotoModel wxPhotoModel){65         String cent = "";66         InputStream fileInputStream = null;67         DataInputStream dis = null;68         byte[] bufferOut;69         try{70             URL url = newURL(wxPhotoModel.getFileUrlPath());71             HttpURLConnection httpUrl =(HttpURLConnection) url.openConnection();72             httpUrl.setDoInput(true);73             httpUrl.setRequestMethod("GET");74             fileInputStream =httpUrl.getInputStream();75             dis = newDataInputStream(fileInputStream);76             bufferOut = new byte[httpUrl.getContentLength()];77 dis.read(bufferOut);78             cent =MD5.md5HashCode(bufferOut);79         } catch(Exception e) {80 LOGGER.error(e.getMessage());81             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),e.getMessage());82         }finally{83             if (fileInputStream!=null) {84                 try{85 fileInputStream.close();86                 } catch(IOException e) {87 LOGGER.error(e.getMessage());88                     return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),e.getMessage());89 }90 }91             if(dis!=null){92                 try{93 dis.close();94                 } catch(IOException e) {95 LOGGER.error(e.getMessage());96                     return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),e.getMessage());97 }98 }99 }100         if ("".equals(cent) || fileInputStream == null)101             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"图片未获取到");102         SortedMap<String, String> reqData = new TreeMap<>();103         reqData.put("mch_id", WXConstant.MCHID);104         reqData.put("sign_type", WXConstant.SIGNTTYPE);105         reqData.put("media_hash", cent);106         reqData.put("sign", WXPayUtil.generateSignature(reqData,107 WXConstant.KEY, WXConstant.HMACSHA256TYPE));108         MultipartEntityBuilder builder =MultipartEntityBuilder.create();109         builder.addTextBody("mch_id",WXConstant.MCHID, ContentType.MULTIPART_FORM_DATA);110         builder.addBinaryBody("media",bufferOut, ContentType.DEFAULT_BINARY,wxPhotoModel.getFileName());111         builder.addTextBody("media_hash",cent, ContentType.MULTIPART_FORM_DATA);112         builder.addTextBody("sign_type",WXConstant.SIGNTTYPE, ContentType.MULTIPART_FORM_DATA);113         builder.addTextBody("sign",reqData.get("sign"), ContentType.MULTIPART_FORM_DATA);114         String returnStr =WXPayHttpUtil.WXHttpPostFormWithCert(WXConstant.MEDIAUURL,115 WXConstant.MCHID,WXConstant.CERTPATH,builder);116         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);117         if(result.isEmpty()){118             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"未获取到微信方图片id");119 }120         return new ReturnModel<>(result);121 }122
123 @Override124     public ReturnModel<?>unifiedOrderByNATIVE(WXUnifiedOrderModel wxUnifiedOrderModel) {125         wxUnifiedOrderModel.setProductId(WXPayUtil.getRandomString(32));126         wxUnifiedOrderModel.setTradeType("NATIVE");127         returnunifiedOrder(wxUnifiedOrderModel);128 }129
130 @Override131     public ReturnModel<?>unifiedOrderByJSAPI(WXUnifiedOrderModel wxUnifiedOrderModel) {132 wxUnifiedOrderModel.setSubAppid(WXConstant.SUBAPPID);133         wxUnifiedOrderModel.setTradeType("JSAPI");134         returnunifiedOrder(wxUnifiedOrderModel);135 }136
137     /**
138 * 查询审核状态139 *@paramapplyState 参数-商户号、服务商自定义的用户编号140 *@return
141      */
142 @Override143     public ReturnModel<?>queryForApply(WXApplyStateModel applyState){144         applyState.setVersion("1.0");145 applyState.setMchId(WXConstant.MCHID);146         applyState.setNonceStr(WXPayUtil.getRandomString(32));147 applyState.setSignType(WXConstant.SIGNTTYPE);148         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(applyState);149         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithCert(WXConstant.QUERYURL,150 reqData,WXConstant.CERTPATH);151         if(("").equals(returnStr)){152             return new ReturnModel<>(ErrorCode.SERVER_ERROR.getCode(),"安全证书无法解析");153 }154         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);155         if(("FAIL").equals(result.get("return_code"))){156             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));157 }158         if(("SUCCESS").equals(result.get("return_code"))){159             return new ReturnModel<>(result);160 //String applymentStateDesc = "申请状态:"+result.get("applyment_state_desc");161 //if(("REJECTED").equals(result.get("applyment_state"))){162 //                //审核结果json163 //JSONArray audit_detail = JSONObject.parseArray(164 //JSONObject.parseObject(165 //result.get("audit_detail")).getString("audit_detail"));166 //                //得到审核详情167 //String reject_reason = JSONObject.parseObject(168 //JSONObject.toJSONString(audit_detail.get(0))).getString("reject_reason");169 //return applymentStateDesc+"\t审核详情:"+reject_reason;170 //}171 //if(("TO_BE_SIGNED").equals(result.get("applyment_state"))){172 //return applymentStateDesc+"\t小微商户号:"173 //+result.get("sub_mch_id")+"\t签约链接:"174 //+result.get("sign_url");175 //}176 //if(("FINISH").equals(result.get("applyment_state"))){177 //return applymentStateDesc+"\t小微商户号:"+result.get("sub_mch_id");178 //}179 //return applymentStateDesc;
180 }181         return new ReturnModel<>(ErrorCode.SERVER_ERROR.getCode(),"结果解析错误");182 }183
184     /**
185 * 提交商户申请186 *@paramwxApplyForEntryModel 请求商户信息187 *@return
188      */
189 @Override190     public ReturnModel<?>submitInfo(WXApplyForEntryModel wxApplyForEntryModel) {191         SortedMap<String,String> reqData = new TreeMap<>();192         try{193             reqData =applyForEntry(wxApplyForEntryModel);194         } catch(Exception e) {195 LOGGER.error(e.getMessage());196
197 }198         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithCert(WXConstant.SUBMITURL,199 reqData, WXConstant.CERTPATH);200         if(("").equals(returnStr)){201             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"安全证书无法解析");202 }203         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);204         if(("FAIL").equals(result.get("return_code"))){205             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),206                     "返回信息:"+result.get("return_msg")+"错误描述:"+result.get("err_code_des"));207 }208         if(("SUCCESS").equals(result.get("return_code"))){209             return new ReturnModel<>(result);210 //if(("SUCCESS").equals(result.get("result_code"))){211 //return "微信分配的申请单号:"+result.get("applyment_id");212 //}213 //if(("FAIL").equals(result.get("result_code"))){214 //if(("EXIST").equals(result.get("err_code"))){215 //return "商户已存在,对应的申请单当前状态不可编辑";216 //}217 //return result.get("err_code_des");218 //}
219 }220         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");221 }222
223     /**
224 * 提现状态225 *@paramwxQueryAutoWithdrawByDate226 *@return
227      */
228 @Override229     public ReturnModel<?>queryAutoWithdrawByDate(WXQueryAutoWithdrawByDate wxQueryAutoWithdrawByDate) {230 wxQueryAutoWithdrawByDate.setMchId(WXConstant.MCHID);231 wxQueryAutoWithdrawByDate.setSignType(WXConstant.SIGNTTYPE);232         wxQueryAutoWithdrawByDate.setNonceStr(WXPayUtil.getRandomString(32));233         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(wxQueryAutoWithdrawByDate);234         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithCert(WXConstant.QUERYAUTOWITHDRAWURL,235 reqData,WXConstant.CERTPATH);236         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);237         if("SUCCESS".equals(result.get("return_code"))){238             return new ReturnModel<>(result);239 //if("SUCCESS".equals(result.get("result_code"))){240 //if ("PROCESSING".equals(result.get("withdraw_status"))){241 //return result.get("withdraw_status");242 //}else if ("SUCCESS".equals(result.get("withdraw_status"))){243 //return result.get("date")+"\t金额(分):"+result.get("amount")+"\t提现成功时间:"244 //+result.get("success_time");245 //}246 //return result.get("withdraw_status");247 //}else if ("FAIL".equals(result.get("result_code"))){248 //if(result.get("err_code_des") != null && !"".equals(result.get("err_code_des"))){249 //return result.get("err_code_des");250 //}251 //return result.get("err_code");252 //}
253         }else if("FAIL".equals(result.get("return_code"))){254             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));255 }256         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");257 }258
259     /**
260 * 统一下单261 *@paramwxUnifiedOrderModel262 *@return
263      */
264 @Override265     public ReturnModel<?>unifiedOrder(WXUnifiedOrderModel wxUnifiedOrderModel) {266 wxUnifiedOrderModel.setAppid(WXConstant.APPID);267 wxUnifiedOrderModel.setMchId(WXConstant.MCHID);268         wxUnifiedOrderModel.setNonceStr(WXPayUtil.getRandomString(32));269 wxUnifiedOrderModel.setSignType(WXConstant.SIGNTTYPE);270 wxUnifiedOrderModel.setNotifyUrl(WXConstant.NOTIFYURL);271         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(wxUnifiedOrderModel);272         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithoutCert(WXConstant.UNIFIEDORDERURL, reqData);273         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);274         if(("SUCCESS").equals(result.get("return_code"))){275             if(("SUCCESS").equals(result.get("result_code"))){276 //if ("NATIVE".equals(wxUnifiedOrderModel.getTradeType())){277 //return new ReturnModel<>(result);278 //}else
279                     if("JSAPI".equals(wxUnifiedOrderModel.getTradeType())){280                     Map<String,String> payinfo = new HashMap<>();281                     payinfo.put("appId",wxUnifiedOrderModel.getAppid());282                     payinfo.put("nonceStr",WXPayUtil.getRandomString(32));283                     payinfo.put("package","prepay_id="+result.get("prepay_id"));284                     payinfo.put("signType",WXConstant.MD5TYPE);285                     payinfo.put("timeStamp",String.valueOf(newDate().getTime()));286                     payinfo.put("paySign",WXPayUtil.generateSignature(payinfo,WXConstant.KEY,WXConstant.MD5TYPE));287 //String info = JSONObject.toJSONString(payinfo);
288                     return new ReturnModel<>(payinfo);289 }290 }291 //if(("FAIL").equals(result.get("result_code"))){292 //return result.get("err_code_des");293 //}
294             return new ReturnModel<>(result);295         }else if(("FAIL").equals(result.get("return_code"))){296             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));297 }298         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");299 }300
301     /**
302 * 绑定AppID配置303 *@paramwxAddSubDevConfigModel304 *@return
305      */
306 @Override307     public ReturnModel<?>addSubDevConfig(WXAddSubDevConfigModel wxAddSubDevConfigModel) {308 wxAddSubDevConfigModel.setAppid(WXConstant.APPID);309 wxAddSubDevConfigModel.setMchId(WXConstant.MCHID);310 wxAddSubDevConfigModel.setSubAppid(WXConstant.SUBAPPID);311         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(wxAddSubDevConfigModel);312         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithCert(WXConstant.ADDSUBDEVCONFIGURL, reqData, WXConstant.CERTPATH);313         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);314         if(("SUCCESS").equals(result.get("return_code"))) {315             return new ReturnModel<>(result);316 //if(("SUCCESS").equals(result.get("result_code"))){317 //return "配置成功";318 //}else if(("FAIL").equals(result.get("result_code"))){319 //return result.get("err_code_des").replaceAll("[a-zA-Z]","");320 //}
321         }else if(("FAIL").equals(result.get("return_code"))){322             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));323 }324         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");325 }326
327     /**
328 * 订单查询329 *@paramwxOrderQueryModel330 *@return
331      */
332 @Override333     public ReturnModel<?>orderQuery(WXOrderQueryModel wxOrderQueryModel) {334 wxOrderQueryModel.setSubAppid(WXConstant.SUBAPPID);335 wxOrderQueryModel.setAppid(WXConstant.APPID);336 wxOrderQueryModel.setMchId(WXConstant.MCHID);337         wxOrderQueryModel.setNonceStr(WXPayUtil.getRandomString(32));338 wxOrderQueryModel.setSignType(WXConstant.SIGNTTYPE);339         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(wxOrderQueryModel);340         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithoutCert(WXConstant.ORDERQUERYURL, reqData);341         Map<String,String> result=WXPayXmlUtil.parseXMLToMap(returnStr);342         if(("SUCCESS").equals(result.get("return_code"))){343             return new ReturnModel<>(result);344 //if(("SUCCESS").equals(result.get("result_code")) && ("SUCCESS").equals(result.get("trade_state"))){345 //return result.get("trade_state_desc");346 //}else if(("SUCCESS").equals(result.get("result_code"))){347 //return result.get("out_trade_no")+"交易状态:"+result.get("trade_state");348 //}else if(("FAIL").equals(result.get("result_code"))){349 //return result.get("err_code_des");350 //}
351         }else if (("FAIL").equals(result.get("return_code"))){352             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));353 }354         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");355 }356
357     /**
358 * 关闭订单359 *@paramwxCloseOrderModel360 *@return
361      */
362 @Override363     public ReturnModel<?>closeOrder(WXCloseOrderModel wxCloseOrderModel) {364 wxCloseOrderModel.setAppid(WXConstant.APPID);365 wxCloseOrderModel.setMchId(WXConstant.MCHID);366         wxCloseOrderModel.setNonceStr(WXPayUtil.getRandomString(32));367         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(wxCloseOrderModel);368         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithoutCert(WXConstant.CLOSEORDERURL,reqData);369         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);370         if(("SUCCESS").equals(result.get("return_code"))){371             return new ReturnModel<>(result);372 //if(("SUCCESS").equals(result.get("result_code"))){373 //return "关闭成功";374 //}else if(("FAIL").equals(result.get("result_code"))){375 //if(("ORDERPAID").equals(result.get("err_code"))){376 //return "订单已支付,不能发起关单,请当作已支付的正常交易";377 //}else if(("SYSTEMERROR").equals(result.get("err_code"))){378 //return "系统异常,请重新调用";379 //}else if(("ORDERCLOSED").equals(result.get("err_code"))){380 //return "订单已关闭,无需继续调用";381 //}else if(("SIGNERROR").equals(result.get("err_code"))){382 //return "请检查签名参数和方法是否都符合签名算法要求";383 //}else if(("REQUIRE_POST_METHOD").equals(result.get("err_code"))){384 //return "请检查请求参数是否通过post方法提交";385 //}else if(("REQUIRE_POST_METHOD").equals(result.get("err_code"))){386 //return "请检查XML参数格式是否正确";387 //}388 //}
389         }else if(("FAIL").equals(result.get("return_code"))){390             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));391 }392         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");393 }394
395     /**
396 * 申请退款397 *@paramwxRefundModel398 *@return
399      */
400 @Override401     public ReturnModel<?>refund(WXRefundModel wxRefundModel) {402 wxRefundModel.setSubAppid(WXConstant.SUBAPPID);403 wxRefundModel.setAppid(WXConstant.APPID);404 wxRefundModel.setMchId(WXConstant.MCHID);405         wxRefundModel.setNonceStr(WXPayUtil.getRandomString(32));406 wxRefundModel.setNotifyUrl(WXConstant.NOTIFYURL);407 wxRefundModel.setSignType(WXConstant.SIGNTTYPE);408         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(wxRefundModel);409         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithCert(WXConstant.REFUNDURL,410 reqData,WXConstant.CERTPATH);411         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);412         if(("SUCCESS").equals(result.get("return_code"))){413             return new ReturnModel<>(result);414 //if(("SUCCESS").equals(result.get("result_code"))){415 //return "申请退款成功";416 //}else if(("FAIL").equals(result.get("result_code"))){417 //return result.get("err_code_des");418 //}
419         }else if(("FAIL").equals(result.get("return_code"))){420             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));421 }422         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");423 }424
425     /**
426 * 查询退款(微信退款id查询,只查一笔)427 *@paramwxRefundQueryModel428 *@return
429      */
430 @Override431     public ReturnModel<?>refundQuery(WXRefundQueryModel wxRefundQueryModel) {432 wxRefundQueryModel.setSubAppid(WXConstant.SUBAPPID);433 wxRefundQueryModel.setAppid(WXConstant.APPID);434 wxRefundQueryModel.setMchId(WXConstant.MCHID);435 wxRefundQueryModel.setSignType(WXConstant.SIGNTTYPE);436         wxRefundQueryModel.setNonceStr(WXPayUtil.getRandomString(32));437         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(wxRefundQueryModel);438         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithoutCert(WXConstant.REFUNDQUERYURL,reqData);439         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);440         if(("SUCCESS").equals(result.get("return_code"))){441             return new ReturnModel<>(result);442 //if(("SUCCESS").equals(result.get("result_code"))){443 //return result.get("refund_status_0");444 //}else if(("FAIL").equals(result.get("result_code"))){445 //return result.get("err_code_des");446 //}
447         }else if(("FAIL").equals(result.get("return_code"))){448             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));449 }450         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");451 }452
453     /**
454 * 修改银行卡号455 *@parammodifyarchives456 *@return
457      */
458 @Override459     public ReturnModel<?>modifyArchives(WXModifyArchivesModel modifyarchives) {460         modifyarchives.setVersion("1.0");461 modifyarchives.setMchId(WXConstant.MCHID);462         modifyarchives.setNonceStr(WXPayUtil.getRandomString(32));463 modifyarchives.setSignType(WXConstant.SIGNTTYPE);464         String certificatesInfo =getCertficates();465         if(("fail").equals(certificatesInfo) || ("").equals(certificatesInfo)){466             return new ReturnModel<>(ErrorCode.SERVER_ERROR.getCode(),"安全证书无法解析");467 }468         JSONArray data =JSONObject.parseArray(469                 JSONObject.parseObject(certificatesInfo).getString("data"));470         //得到平台系列号
471         String serialNo =JSONObject.parseObject(472                 JSONObject.toJSONString(data.get(0))).getString("serial_no");473         //得到用于加密敏感信息的证书原文
474         String cert =WXPayUtil.getWXCert(data);475 modifyarchives.setCertSn(serialNo);476         modifyarchives.setAccountNumber(RSAEncryptUtil.rsaEncrypt("6214830195599542",cert));477
478         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(modifyarchives);479         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithCert(WXConstant.MODIFYARCHIVESURL,reqData,WXConstant.CERTPATH);480         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);481         if("SUCCESS".equals(result.get("return_code"))){482             return new ReturnModel<>(result);483 //if("FAIL".equals(result.get("result_code"))){484 //return result.get("err_code");485 //}else if ("SUCCESS".equals(result.get("result_code"))){486 //return result.get("sub_mch_id")+"商户下的银行卡号修改成功";487 //}
488         }else if ("FAIL".equals(result.get("return_code"))){489             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));490 }491         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");492 }493
494     /**
495 * 重新发起提现496 *@paramreautowithdrawbydate497 *@return
498      */
499 @Override500     public ReturnModel<?>reAutoWithdrawByDate(WXQueryAutoWithdrawByDate reautowithdrawbydate) {501 reautowithdrawbydate.setSignType(WXConstant.SIGNTTYPE);502 reautowithdrawbydate.setMchId(WXConstant.MCHID);503         reautowithdrawbydate.setNonceStr(WXPayUtil.getRandomString(32));504         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(reautowithdrawbydate);505         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithCert(WXConstant.REAUTOWITHDRAWBYDATEURL,506 reqData,WXConstant.CERTPATH);507         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);508         if("SUCCESS".equals(result.get("return_code"))){509             return new ReturnModel<>(result);510 //if ("SUCCESS".equals(result.get("result_code"))){511 //return result.get("date")+"\t金额:"+result.get("amount");512 //}else if ("FAIL".equals(result.get("result_code"))){513 //return result.get("err_code")+result.get("err_code_des");514 //}
515         }else if ("FAIL".equals(result.get("return_code"))){516             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));517 }518         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");519 }520
521     /**
522 * 修改商户联系信息523 *@parammodifycontactinfo524 *@return
525      */
526 @Override527     public ReturnModel<?>modifyContactInfo(WXModifyContactInfoModel modifycontactinfo) {528         modifycontactinfo.setVersion("1.0");529 modifycontactinfo.setMchId(WXConstant.MCHID);530         modifycontactinfo.setNonceStr(WXPayUtil.getRandomString(32));531 modifycontactinfo.setSignType(WXConstant.SIGNTTYPE);532         String certificatesInfo =getCertficates();533         if(("fail").equals(certificatesInfo) || ("").equals(certificatesInfo)){534             return new ReturnModel<>(ErrorCode.SERVER_ERROR.getCode(),"安全证书无法解析");535 }536         JSONArray data =JSONObject.parseArray(537                 JSONObject.parseObject(certificatesInfo).getString("data"));538         //得到平台系列号
539         String serialNo =JSONObject.parseObject(540                 JSONObject.toJSONString(data.get(0))).getString("serial_no");541         //得到用于加密敏感信息的证书原文
542         String cert =WXPayUtil.getWXCert(data);543 modifycontactinfo.setCertSn(serialNo);544 modifycontactinfo.setMobilePhone(RSAEncryptUtil.rsaEncrypt(modifycontactinfo.getMobilePhone(),cert));545 modifycontactinfo.setEmail(RSAEncryptUtil.rsaEncrypt(modifycontactinfo.getEmail(),cert));546         SortedMap<String,String> reqData =AnnotationUtil.parseObjectToMap(modifycontactinfo);547         String returnStr =WXPayHttpUtil.WXHttpPostXMLWithCert(WXConstant.MODIFYCONTACTINFOURL,548 reqData,WXConstant.CERTPATH);549         Map<String,String> result =WXPayXmlUtil.parseXMLToMap(returnStr);550         if ("SUCCESS".equals(result.get("return_code"))){551             return new ReturnModel<>(result);552 //if ("SUCCESS".equals(result.get("result_code"))){553 //return result.get("sub_mch_id")+"商户修改信息成功";554 //}else if ("FAIL".equals(result.get("result_code"))){555 //return result.get("err_code")+result.get("err_code_des");556 //}
557         }else if ("FAIL".equals(result.get("return_code"))){558             return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),result.get("return_msg"));559 }560         return new ReturnModel<>(ErrorCode.BUSINESS_ERROR.getCode(),"结果解析错误");561 }562 }

service实现层

1 public classWXPayHttpUtil {2     private static final Logger LOGGER = LoggerFactory.getLogger(WXPayHttpUtil.class);3
4     private final static String UTFCHARSET = "UTF-8";5     private final static String XMLCONTENT = "text/xml;charset=utf-8";6     private final static String FORMCONTENT = "multipart/form-data;charset=utf-8";7     /**
8 * 需证书上传form表单形式接口9 *@paramurl 接口地址10 *@parammcdId 商户号即密码11 *@paramcertPath 证书文件位置12 *@parambuilder 表单参数13 *@return
14      */
15     public staticString WXHttpPostFormWithCert(String url, String mcdId, String certPath, MultipartEntityBuilder builder){16         HttpPost uploadFile = newHttpPost(url);17         SSLConnectionSocketFactory sslsf = null;18         StringBuilder stringBuilder = newStringBuilder();19         //读取本机存放的PKCS12证书文件
20         ClassLoader classLoader = WXPayHttpUtil.class.getClassLoader();21         URL resource =classLoader.getResource(certPath);22         try(FileInputStream pkcfile = new FileInputStream(newFile(resource.getPath()));23 ){24             //指定读取证书格式为PKCS12
25             KeyStore keyStore = KeyStore.getInstance("PKCS12");26             //"100000"为密码即商户号
27 keyStore.load(pkcfile,  mcdId.toCharArray());28             SSLContext sslcontext =SSLContexts.custom().loadKeyMaterial(keyStore,  mcdId.toCharArray()).build();29             //指定TLS版本
30             sslsf = newSSLConnectionSocketFactory(sslcontext);31         } catch(Exception e) {32 LOGGER.debug(e.getMessage());33             return "";34 }35         HttpEntity multipart =builder.build();36 uploadFile.setEntity(multipart);37         uploadFile.setHeader("Content-Type", FORMCONTENT);38         try(CloseableHttpClient client =HttpClients.custom().setSSLSocketFactory(sslsf).build();39             CloseableHttpResponse response =client.execute(uploadFile);)40 {41             if(response != null && response.getEntity() != null){42                 HttpEntity entity =response.getEntity();43                 try(44                         InputStream in =entity.getContent();45                         BufferedReader reader = new BufferedReader(new InputStreamReader(in,"UTF-8")))46 {47                     reader.lines().forEach(line->{48 stringBuilder.append(line);49 });50 }51 }52         } catch(IOException e) {53 LOGGER.debug(e.getMessage());54             return "";55 }56
57
58         returnstringBuilder.toString();59 }60
61     /**
62 * 不需证书上传xml形式接口63 *@paramurl   接口地址64 *@paramreqDataTo  请求参数65 *@return
66      */
67     public static String WXHttpPostXMLWithoutCert(String url,SortedMap<String, String>reqDataTo){68         HttpPost httpPost = newHttpPost(url);69         StringEntity postEntity = newStringEntity(WXPayXmlUtil.parseMapToXML(reqDataTo), UTFCHARSET);70         httpPost.setHeader("Content-Type", XMLCONTENT);71 httpPost.setEntity(postEntity);72         StringBuilder stringBuilder = newStringBuilder();73         try(CloseableHttpClient client =HttpClients.createDefault();74             CloseableHttpResponse response =client.execute(httpPost);)75         {if(response != null && response.getEntity() != null){76             HttpEntity entity =response.getEntity();77             try(78                     InputStream in =entity.getContent();79                     BufferedReader reader = new BufferedReader(new InputStreamReader(in,"UTF-8")))80 {81                 reader.lines().forEach(line->{82 stringBuilder.append(line);83 });;84 }85 }86         } catch(IOException e) {87 LOGGER.debug(e.getMessage());88             return "";89 }90         returnstringBuilder.toString();91 }92
93     /**
94 * 需证书上传xml形式接口95 *@paramurl 接口地址96 *@paramreqData 参数97 *@paramcertPath 证书文件位置98 *@return
99      */
100     public static String WXHttpPostXMLWithCert(String url,SortedMap<String, String>reqData,String certPath){101         HttpPost queryState = newHttpPost(url);102         SSLConnectionSocketFactory sslsf = null;103         //读取本机存放的PKCS12证书文件
104         ClassLoader classLoader = ConfigTool.class.getClassLoader();105         URL resource =classLoader.getResource(certPath);106         try(FileInputStream pkcfile = new FileInputStream(newFile(resource.getPath()));107 ){108             //指定读取证书格式为PKCS12
109             KeyStore keyStore = KeyStore.getInstance("PKCS12");110             //"100000"为密码即商户号
111             keyStore.load(pkcfile,  reqData.get("mch_id").toCharArray());112             SSLContext sslcontext =SSLContexts.custom().loadKeyMaterial(113                     keyStore,  reqData.get("mch_id").toCharArray()).build();114             sslsf = newSSLConnectionSocketFactory(sslcontext,115                     new String[]{"TLSv1"},116                     null,117                     newDefaultHostnameVerifier());118         } catch(Exception e) {119 LOGGER.debug(e.getMessage());120             return "";121 }122         StringBuilder stringBuilder = newStringBuilder();123         StringEntity postEntity = new StringEntity(WXPayXmlUtil.parseMapToXML(reqData), "UTF-8");124 queryState.setEntity(postEntity);125         queryState.setHeader("Content-Type", XMLCONTENT);126         try(CloseableHttpClient client =HttpClients.custom().setSSLSocketFactory(sslsf).build();127             CloseableHttpResponse response =client.execute(queryState);)128 {129             if(response != null && response.getEntity() != null){130                 HttpEntity entity =response.getEntity();131                 try(132                         InputStream in =entity.getContent();133                         BufferedReader reader = newBufferedReader(134                                 new InputStreamReader(in,"UTF-8")))135 {136                     reader.lines().forEach(line->{137 stringBuilder.append(line);138 });139 }140 }141         } catch(IOException e) {142 LOGGER.debug(e.getMessage());143             return "";144 }145         returnstringBuilder.toString();146 }147
148 }

WXPayHttpUtil

1 public classWXPayUtil {2     private static final String ALGORITHM = "AES/GCM/NoPadding";3     private static final int TAG_LENGTH_BIT = 128;4     private static final String AES_KEY = "9bbbd2223e5240bb2252d05222210c27"; //APIv3密钥
5
6     /**
7 *8 *@paramaad9 *@paramiv10 *@paramcipherText11 *@return
12 *@throwsException13      */
14     private staticString aesgcmDecrypt(String aad, String iv, String cipherText){15         try{16             final Cipher cipher = Cipher.getInstance(ALGORITHM, "SunJCE");17             SecretKeySpec key = new SecretKeySpec(AES_KEY.getBytes(), "AES");18             GCMParameterSpec spec = newGCMParameterSpec(TAG_LENGTH_BIT, iv.getBytes());19 cipher.init(Cipher.DECRYPT_MODE, key, spec);20 cipher.updateAAD(aad.getBytes());21             return newString(cipher.doFinal(Base64.getDecoder().decode(cipherText)));22         } catch(Exception e) {23             return "fail";24 }25 }26     public staticString getWXCert(JSONArray data) {27         //敏感信息证书生成所需参数
28         String encryptCertificate =JSONObject.parseObject(29                 JSONObject.toJSONString(data.get(0))).getString("encrypt_certificate");30         String nonce =JSONObject.parseObject(31                 encryptCertificate).getString("nonce");32         String associatedData =JSONObject.parseObject(33                 encryptCertificate).getString("associated_data");34         //要被解密的证书字符串
35         String cipherText =JSONObject.parseObject(36                 encryptCertificate).getString("ciphertext");37         String wechatpayCert = "";38         try{39             wechatpayCert =aesgcmDecrypt(associatedData, nonce, cipherText);40         } catch(Exception e) {41             returnwechatpayCert;42 }43         returnwechatpayCert;44 }45     /**
46 * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。47 *48 *@paramdata 待签名数据49 *@paramkey API密钥50 *@paramsignType 签名方式51 *@return签名52      */
53     public static String generateSignature(final Map<String, String>data, String key, String signType) {54         Set<String> keySet =data.keySet();55         String[] keyArray = keySet.toArray(newString[keySet.size()]);56 Arrays.sort(keyArray);57         StringBuilder sb = newStringBuilder();58         for(String k : keyArray) {59             if (k.equals("sign")) {60                 continue;61 }62             if (data.get(k).trim().length() > 0) //参数值为空,则不参与签名
63                 sb.append(k).append("=").append(data.get(k).trim()).append("&");64 }65         sb.append("key=").append(key);66         if ("MD5".equals(signType)) {67             returnMD5.getMD5(sb.toString()).toUpperCase();68 }69         else if ("HMACSHA256".equals(signType)) {70             returnHMACSHAUtil.getHMACSHA256(sb.toString(), key);71 }72         returnsignType;73 }74     //获取指定位数的随机字符串(包含小写字母、大写字母、数字,0<length)
75     public static String getRandomString(intlength) {76         //随机字符串的随机字符库
77         String KeyString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";78         StringBuffer sb = new StringBuffer(); int len =KeyString.length();79         for (int i = 0; i < length; i++) {80             sb.append(KeyString.charAt((int) Math.round(Math.random() * (len - 1))));81 }82         returnsb.toString();83     }

WXPayUtil

1 public final classWXPayXmlUtil {2     public static DocumentBuilder newDocumentBuilder() throwsParserConfigurationException {3         DocumentBuilderFactory documentBuilderFactory =DocumentBuilderFactory.newInstance();4         documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);5         documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);6         documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);7         documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);8         documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);9         documentBuilderFactory.setXIncludeAware(false);10         documentBuilderFactory.setExpandEntityReferences(false);11
12         returndocumentBuilderFactory.newDocumentBuilder();13 }14
15     public static Document newDocument() throwsParserConfigurationException {16         returnnewDocumentBuilder().newDocument();17 }18
19     /**
20 * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。21 *22 *@paramstrXML23 *@return
24      */
25     public staticMap parseXMLToMap(String strXML) {26         Map<String, String> data = new HashMap<String, String>();27         try{28             DocumentBuilder documentBuilder =WXPayXmlUtil.newDocumentBuilder();29             InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));30             Document doc =documentBuilder.parse(stream);31 doc.getDocumentElement().normalize();32             NodeList nodeList =doc.getDocumentElement().getChildNodes();33             for (int idx = 0; idx < nodeList.getLength(); ++idx) {34                 Node node =nodeList.item(idx);35                 if (node.getNodeType() ==Node.ELEMENT_NODE) {36                     org.w3c.dom.Element element =(org.w3c.dom.Element) node;37 data.put(element.getNodeName(), element.getTextContent());38 }39 }40             try{41 stream.close();42             } catch(Exception ex) {43                 returndata;44 }45         } catch(Exception ex) {46                 returndata;47 }48         returndata;49 }50
51     /**
52 * map转xml53 *@paramdata54 *@return
55      */
56     public static String parseMapToXML(SortedMap<String, String>data) {57 //StringBuffer sb = new StringBuffer();58 //sb.append("<xml>");59 //Set es = parameters.entrySet();60 //Iterator it = es.iterator();61 //while (it.hasNext()) {62 //Map.Entry entry = (Map.Entry)it.next();63 //String k = (String)entry.getKey();64 //String v = (String)entry.getValue();65 //if (null != v && !"".equals(v)) {66 //sb.append("<" + k + ">" + parameters.get(k) + "</" + k + ">\n");67 //}68 //}69 //sb.append("</xml>");70 //return sb.toString();71 //}
72         Document document = null;73         try{74             document =WXPayXmlUtil.newDocument();75         } catch(ParserConfigurationException e) {76 e.printStackTrace();77 }78         org.w3c.dom.Element root = document.createElement("xml");79 document.appendChild(root);80         for(String key: data.keySet()) {81             String value =data.get(key);82             if (value == null) {83                 value = "";84 }85             value =value.trim();86             if(!("").equals(value)){87                 org.w3c.dom.Element filed =document.createElement(key);88 filed.appendChild(document.createTextNode(value));89 root.appendChild(filed);90 }91
92 }93         TransformerFactory tf =TransformerFactory.newInstance();94         Transformer transformer = null;95         StringWriter writer = newStringWriter();96         String output = "";97         try{98             transformer =tf.newTransformer();99             DOMSource source = newDOMSource(document);100             transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");101             transformer.setOutputProperty(OutputKeys.INDENT, "yes");102             StreamResult result = newStreamResult(writer);103 transformer.transform(source, result);104             output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
105         } catch(Exception e) {106             returnoutput;107         }finally{108             try{109 writer.close();110             } catch(IOException e) {111                 returnoutput;112 }113 }114         returnoutput;115 }116 }

WXPayXmlUtil

1 public classRSAEncryptUtil {2     private static final String CIPHER_PROVIDER = "SunJCE";3     private static final String TRANSFORMATION_PKCS1Paddiing = "RSA/ECB/PKCS1Padding";4     private static final String CHAR_ENCODING = "UTF-8";//固定值,无须修改5     //数据加密方法
6     private static byte[] encryptPkcs1padding(PublicKey publicKey, byte[] data) throwsException {7         Cipher ci =Cipher.getInstance(TRANSFORMATION_PKCS1Paddiing, CIPHER_PROVIDER);8 ci.init(Cipher.ENCRYPT_MODE, publicKey);9         returnci.doFinal(data);10 }11     //加密后的秘文,使用base64编码方法
12     private static String encodeBase64(byte[] bytes) throwsException {13         returnBase64.getEncoder().encodeToString(bytes);14 }15     //对敏感内容(入参Content)加密,其中PUBLIC_KEY_FILENAME为存放平台证书的路径,平台证书文件存放明文平台证书内容,且为pem格式的平台证书(平台证书的获取方式参照平台证书及序列号获取接口,通过此接口得到的参数certificates包含了加密的平台证书内容ciphertext,然后根据接口文档中平台证书解密指引,最终得到明文平台证书内容)
16      public staticString rsaEncrypt(String Content,String cert){17          final byte[] PublicKeyBytes =cert.getBytes();18          X509Certificate certificate = null;19          try{20              certificate =X509Certificate.getInstance(PublicKeyBytes);21          } catch(CertificateException e) {22              return "";23 }24          PublicKey publicKey =certificate.getPublicKey();25          try{26              returnencodeBase64(encryptPkcs1padding(publicKey, Content.getBytes(CHAR_ENCODING)));27          } catch(Exception e) {28              return "";29 }30 }31 }

RSAEncryptUtil

1 public classMD5 {2
3     /**
4 * 签名字符串5 *6 *@paramtext7 *            需要签名的字符串8 *@paramkey9 *            密钥10 *@paraminput_charset11 *            编码格式12 *@return签名结果13      */
14     public static String sign(String text, String key, String charset) throwsException {15         text = text +key;16         returnDigestUtils.md5Hex(getContentBytes(text, charset));17 }18
19     /**
20 * 签名字符串21 *22 *@paramtext23 *            需要签名的字符串24 *@paramsign25 *            签名结果26 *@paramkey27 *            密钥28 *@paraminput_charset29 *            编码格式30 *@return签名结果31      */
32     public static boolean verify(String text, String sign, String key, String charset) throwsException {33         text = text +key;34         String mysign =DigestUtils.md5Hex(getContentBytes(text, charset));35         if(mysign.equals(sign)) {36             return true;37         } else{38             return false;39 }40 }41
42     /**
43 *@paramcontent44 *@paramcharset45 *@return
46 *@throwsSignatureException47 *@throwsUnsupportedEncodingException48      */
49     private static byte[] getContentBytes(String content, String charset) {50         if (charset == null || "".equals(charset)) {51             returncontent.getBytes();52 }53         try{54             returncontent.getBytes(charset);55         } catch(UnsupportedEncodingException e) {56             throw new RuntimeException("签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" +charset);57 }58 }59     /**
60 * 对文件进行MD5获取其Hash值61 *62 *@paramfis63 *@return
64      */
65     public staticString md5HashCode(InputStream fis) {66         try{67             MessageDigest MD5 = MessageDigest.getInstance("MD5");68             byte[] buffer = new byte[8192];69             intlength;70             while ((length = fis.read(buffer)) != -1) {71                 MD5.update(buffer, 0, length);72 }73             return newString(Hex.encodeHex(MD5.digest()));74         } catch(Exception e) {75             return "";76 }77 }78
79     public static String md5HashCode(byte[] fis) {80         try{81             MessageDigest MD5 = MessageDigest.getInstance("MD5");82             MD5.update(fis, 0, fis.length);83             return newString(Hex.encodeHex(MD5.digest()));84         } catch(Exception e) {85             return "";86 }87 }88
89     /**
90 * 生成 MD591 *92 *@paramdata 待处理数据93 *@returnMD5结果94      */
95     public staticString getMD5(String data) {96 MessageDigest md;97         byte[] array = new byte[0];98         try{99             md = MessageDigest.getInstance("MD5");100             array = md.digest(data.getBytes("UTF-8"));101         } catch(NoSuchAlgorithmException e) {102             return "";103         } catch(UnsupportedEncodingException e) {104             return "";105 }106         StringBuilder sb = newStringBuilder();107         for (byteitem : array) {108             sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));109 }110         returnsb.toString().toUpperCase();111 }112 }

MD5

1 public classAnnotationUtil {2     /**
3 * object转map4 *@param
5 *@return
6      */
7     public static SortedMap<String, String>parseObjectToMap(Object obj){8         ArrayList<Field> fileds = new ArrayList<>();9         Class<?> objClass =obj.getClass();10 fileds.addAll(Arrays.asList(objClass.getDeclaredFields()));11         if(objClass.getSuperclass()!=null){12 fileds.addAll(Arrays.asList(objClass.getSuperclass().getDeclaredFields()));13 }14         SortedMap<String,String> map = new TreeMap<>();15         fileds.forEach(filed->{16             filed.setAccessible(true);17             Annotation annotations = filed.getAnnotation(WXPayParam.class);18             String k =((WXPayParam) annotations).value();19             try{20                String v =String.valueOf(filed.get(obj));21                if (null != v && !"".equals(v) && !"null".equals(v)) {22 map.put(k,v);23 }24             } catch(IllegalAccessException e) {25                 return;26 }27 });28         if(WXConstant.SIGNTTYPE.equals(map.get("sign_type"))){29             map.put("sign",WXPayUtil.generateSignature(map,WXConstant.KEY,WXConstant.HMACSHA256TYPE));30         }else{31             map.put("sign",WXPayUtil.generateSignature(map,WXConstant.KEY,WXConstant.MD5TYPE));32 }33         returnmap;34 }35 }

AnnotationUtil

1 public classHMACSHAUtil {2     /**
3 * 生成 HMACSHA2564 *@paramdata 待处理数据5 *@paramkey 密钥6 *@return加密结果7 *@throwsException8      */
9     public staticString getHMACSHA256(String data, String key){10 Mac sha256_HMAC;11         byte[] array = null;12         try{13             sha256_HMAC = Mac.getInstance("HmacSHA256");14             SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");15 sha256_HMAC.init(secret_key);16             array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));17         } catch(Exception e) {18             return "";19 }20         StringBuilder sb = newStringBuilder();21         for (byteitem : array) {22             sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));23 }24         returnsb.toString().toUpperCase();25 }26 }

HMACSHAUtil

六、接口学习总结

    微信接口可以说是相当标准的API文档,说明也比较详细但是对参数的说明不是很准确,导致自己在连接接口的时候看不懂什么意思,一顿询问相关人员参数的含义,希望自己连接微信接口后对于其他的接口也会轻车熟路,一定要细心每一个参数的配置、顺序就没多大问题

转载于:https://www.cnblogs.com/guoxiaoyu/p/10445972.html

微信小微商户直连接口详解相关推荐

  1. java小程序详解_微信小程序登录Java后台接口(详解,附示例代码)

    首先看一下官方文档 地址:微信小程序官方文档API登录接口 我们先对官方给的时序图进行简单的分析 1.当小程序调用wx.login()时,会获得一个code(临时登录凭证),然后我们需要用wx.req ...

  2. 小程序setdata优化_微信小程序 setData的使用方法详解

    微信小程序 setData的使用方法详解 微信小程序 setData的使用方法详解 最近在使用微信小程序的setData时,遇到了以下问题.如下: 官网文档在使用setData()设置数组对象的某个元 ...

  3. 微信小程token_微信小程序url与token设置详解

    微信小程序url与token设置详解 新浪云应用sae的代码里创建一个weixin.php文件,写入以下代码 isValid(); class wechatAPI { public function ...

  4. 微信小程序一键置顶操作详解:

    微信小程序一键置顶操作详解: 第一种方式:采用scroll-view滚动视图实现 第二种方式,直接用view实现 第一种方式:采用scroll-view滚动视图实现 下面是代码简介: wxml文件代码 ...

  5. nodejs实现微信支付小微商户申请入驻接口

    微信支付小微商户可以通过小程序<微信买单服务商助手>来进件,也可以通过API接口来进件(详情可查阅小微商户专属接口文档). 2种方式进件后的商户是有区别的 不同进件方式下的小微商户对比   ...

  6. 微信小程序01【目录结构详解、视图与渲染、事件、input、scroll-view】

    学习地址:https://www.bilibili.com/video/BV1sx411z77P 笔记01:https://blog.csdn.net/weixin_44949135/article/ ...

  7. 微信小程序实战须知2:详解数据API所需网络配置域名、Https、备案、SSL

    网络通信 小程序请求数据API时比较头疼,不能用想当然方式进行学习. 服务器域名.IP.HTTPS 域名1 域名(Domain Name):又称网域,是由一串用点分隔的名字组成的Internet上某一 ...

  8. 【联机对战】微信小程序联机游戏开发流程详解

    现有一个微信小程序叫中国象棋项目,棋盘类的单机游戏看着有缺少了什么,现在给补上了,加个联机对战的功能,增加了可玩性,对新手来说,实现联机游戏还是有难度的,那要怎么实现的呢,接下来给大家讲一下. 考虑到 ...

  9. 微信小程序数组网页调用实例详解:李贺作品集

    额,我觉得这个东西应该叫做数组,有没有更专业的说法,我实在不知道. 惯例,先看效果,只实现数组存储,点击跳转网页,其他的都省略了. 如图可见,这个小程序有两个页面,1是首页index,2是跳转页det ...

最新文章

  1. sqlserver 类似oracle的rownum功能: row_number
  2. Linux下常用 60个命令
  3. 百雀羚、林清轩、逐本走红背后,植物基护肤品的春天来了?
  4. Kubernetes中使用CronJob定时备份etcd集群数据
  5. python中msg函数_Python 知识点考点之闭包
  6. 图像处理基础(五)_图像像素中通道概念解析
  7. 【ZOJ】3380 Patchouli's Spell Cards
  8. 平衡二叉树、B树、B+树、B*树
  9. MapReduce编程模型简介和总结
  10. PCIe协议中的电源管理概述
  11. VMware15 Pro激活密钥
  12. 线性代数 --- 什么是矩阵的逆?(个人笔记扫描版)
  13. numpy中的revel和flatten
  14. 计算机和信息技术革命,人类历史上的四次信息技术革命
  15. c语言Ox5516,采药 (C语言代码)
  16. 【git系列005】git分支学习
  17. 【git之路】拉取远程分支到本地
  18. P2324 [SCOI2005]骑士精神(IDA*)
  19. 【For my liz】宇宙制作全纪录(如果能成功的话TT)
  20. Rust之Sea-orm快速入门指南

热门文章

  1. IntelliJ IDEA中的神仙插件(写代码必备)
  2. 观「招商银行」隐私计算布局的思考(36氪收录)
  3. VMware如此强大,势必成为开源世界的老大
  4. 测试之第四集找bug的专业与素养
  5. 基于红外技术的交通灯设计
  6. 亚马逊视频下载用什么工具:试试专业亚马逊视频下载器-Tuneboto Amazon Video Downloader中文版 | 亚马逊上的视频怎么下载?
  7. win7设置计算机临时用户,为什么Win7用域账号登录以后总显示为临时配置账户? 穿墙书店...
  8. wps怎么免费导出简历_求职简历怎么写 个人简历怎么写 简历怎么制作
  9. 读《轻断食》的一些体会
  10. STMF4编写系统时钟