接続したテキストは、この部分は注意を払うに処理が必要としている有料ポイント、コールバック給与、払い戻しや他のプロセスへの支払い、およびピットを説明しています。
ステップ4:ポイントを支払うための終わり
「実際に応じてエンドユーザサービス、ビジネスコール、受注支払ったエンドポイントインタフェース、」によるマイクロチャンネル「有料ポイントへのオーダーの終わり」引き落とさ充電量渡さインターフェース。
このステップでは、POSTインターフェースは、マイクロ手紙を呼び出し、何よりも困難であり、私はノートにいくつかのポイントを言うためにここにいます。
加盟店側の注文番号に渡される1.urlは、注文番号は、注文時に作成されます。(伏線が最初にここに埋葬)
2.サービスの時間の期間は、時間のサービス終了が必要、と必須要件があり、ビジネスニーズに応じて合格することをお勧めします。
コール:
//生成签名
String completeUrl = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder/"+ oi.getRefrenceId() +"/complete";
HttpUrl completeHttpUrl = HttpUrl.parse(completeUrl);
String completeToken = WxAPIV3SignUtils.getToken("POST",completeHttpUrl,JSON.toJSONString(completePayScoreIn),payScoreConfig.getMchId(),payScoreConfig.getPrivateKey(),payScoreConfig.getSerialNo());
RequestBody completeRequestBody = RequestBody.create(MediaType_JSON,JSON.toJSONString(completePayScoreIn));
Request completeRequest = new Request.Builder()
.url(completeUrl)
.addHeader("Content-Type","application/json")
.addHeader("Accept","application/json")
.addHeader("Authorization",completeToken)
.post(completeRequestBody)
.build();
Response completeResponse = okHttpClient.newCall(completeRequest).execute();
logger.debug("【完结支付分订单API】接口返回:{},code={},message={},body={}",JSON.toJSONString(completeResponse),completeResponse.code(),completeResponse.message(),completeResponse.body().string());
if (completeResponse.isSuccessful()){//调用成功
}else {//调用失败
}
マイクロチャネルの有料成功コールバック通知を受け取ります
コールバック通知インターフェースを受けて、ノートには、いくつかのポイントがあります。
1.マイクロチャネルの通知メカニズムであれば抗繰り返しプロセスに、そのロジックの実現に、有料の注意を[零細企業は、応答の手紙を受け取ったが、仕様や残業を満たしていない、マイクロチャネルの通知が失敗した、マイクロチャネルは、特定の戦略を定期的に再起動通知を渡すと考えています]。
2.通知は、URL、URLに直接アクセス可能でなければならないとパラメータを運ぶことができません。
実際の処理ロジックを見てみましょう:
public ResponseEntity payScoreCallBack(HttpServletRequest request) throws Exception
{
boolean isOk = true;
String message = null;
String callBackIn = "";//json字符串
String callBackOut = "";
PayOrderIn orderIn = null;
String shopId = (String) request.getAttribute("shopId");
String mchKey = "";//商户APIv3密钥
try {
Date now = DateTime.Now();
ServletInputStream servletInputStream = request.getInputStream();
int contentLength = request.getContentLength();
byte[] callBackInBytes = new byte[contentLength];
servletInputStream.read(callBackInBytes, 0, contentLength);
callBackIn = new String(callBackInBytes, "UTF-8");
logger.debug("【微信支付分免密支付回调】:" + callBackIn);
WxPayScoreNotifyIn notifyIn = JSON.parseObject(callBackIn,WxPayScoreNotifyIn.class);
if(notifyIn == null){
throw new Exception("参数不正确,反序列化失败");
}
if(!"PAYSCORE.USER_PAID".equals(notifyIn.getEvent_type())) {
logger.debug("通知类型非支付成功");
throw new Exception(message);
}
//解密回调信息
byte[] key = mchKey.getBytes();
WxAPIV3AesUtil aesUtil = new WxAPIV3AesUtil(key);
String decryptToString = aesUtil.decryptToString(notifyIn.getResource().getAssociated_data().getBytes(),notifyIn.getResource().getNonce().getBytes(),notifyIn.getResource().getCiphertext());
logger.debug("【支付分支付回调解密结果:】" + decryptToString);
WxPayScoreNotify_Detail wxPayScoreNotify_detail = JSON.parseObject(decryptToString,WxPayScoreNotify_Detail.class);
//todo:处理业务逻辑
}catch (Exception e){
isOk = false;
message = e.getMessage();
LoggerUtils.logDebug(logger, "微信支付回调处理异常,"+e.toString());
}finally {
if(isOk){
}
try{
return new ResponseEntity(HttpStatus.OK);
} catch (Exception e){
//记录日志
LoggerUtils.logDebug(logger, "微信支付回调响应异常,"+e.toString());
return new ResponseEntity(HttpStatus.EXPECTATION_FAILED);
}
}
}
3.マイクロチャネルの暗号文と復号化アルゴリズム解読返され、スペース上の理由から、私の他の記事を参照してください。
https://blog.csdn.net/w1170384758/article/details/105414860
ここでは、私たちに4マイクロ手紙は、復号鍵のビジネスを使用し、返されたコンテンツは暗号化されて、ピットを残しました。単一事業であれば、問題はない、それが鍵ですので。SAASプラットフォームは、マルチ商人はそれに定住した場合、どのように解読するには?これまでの成功を知って、テストを取るために一つの世論調査復号鍵1:私は答えは、対応するテンセント技術について尋ねました。
結果を参照してください、私はハァッでしょう。
!!!私は伏線の前に埋もれポイントは何で、ここでの考え方提供します:
私たちは、私がここにいるの通知、傍受URLを受け取った後、私たちの商人IDを入れて、思考のこのライン、支払いコールバックURL、我々は必要な情報にステッチを採用することができ、この再ルーティング引数として前進。
ワンタイム通知設定は、アドレスの下を見て:
String notifyUrl = "https://url/{shopId}/payScoreCallBack";
notifyUrl = notifyUrl.replaceAll("\\{shopId}",oi.getShopId());
wxApplyPayScoreIn.setNotify_url(notifyUrl);
ルーティング転送ロジック(春フレーム、カスタムインターセプタ):
/**
* 动态拦截请求的所有参数
* <p>
* 通过"op"参数自动路由到具体的控制方法
* </p>
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
String uri = request.getRequestURI();
if (uri.contains("/payScoreCallBack")){//微信支付分回调通知
String process = (String) request.getAttribute("process");
if (!org.springframework.util.StringUtils.isEmpty(process)) return true;//已转发的消息透传
String[] params = uri.split("/");
String shopId = params[params.length - 2];//shopId存储在倒数第二节
//重新拼接url,并将mchId放在参数里
request.setAttribute("shopId",shopId);
request.setAttribute("process", "true");
uri = uri.replaceFirst("/" + shopId,"");
String vPath = request.getContextPath();
if(!org.springframework.util.StringUtils.isEmpty(vPath))
uri = uri.replaceFirst(vPath, "");
request.getRequestDispatcher(uri).forward(request, response);
return false;
}
return true;
}
したがって、いないマイクロチャネルインタフェース仕様に対するおよびパラメータを渡すために私たちのニーズを満たします。
返金要求有料ポイント
公式文書を読んだ後、返金の支払いと払い戻し、見つけ分コールバックや他の支払方法(H5支払い、支払いアプレット)同じAPIインタフェースを使用して、私はそれが非常に簡単だろうと思ったが、ああを見つけるために下に測定!
コードの最初に:
//微信申请退款
private boolean wxApplyRefund(ApplyRefundIn refundIn){
Date wxReqDate = new Date();
boolean result = false;
String wxApplyRefundInXml="",wxApplyRefundOutXml="";
try{
//获取商家支付信息
GetPayInfoOut payInfoOut = customerFacade.getPayInfo(new GetPayInfoIn(refundIn.getShopMchId(), refundIn.getPayType()));
//创建请求对象
BigDecimal handred = new BigDecimal(100);
WxApplyRefundIn wxApplyRefundIn = new WxApplyRefundIn(payInfoOut.getAppId(),payInfoOut.getMchId()
, SerialnoUtils.buildUUID(), "MD5", refundIn.getPayOrderId()/*, refundIn.getOrderId()*/, refundIn.getRefundId()
, refundIn.getOrderAmount().multiply(handred).setScale(2, RoundingMode.HALF_EVEN).intValue()
, refundIn.getRefundAmount().multiply(handred).setScale(2, RoundingMode.HALF_EVEN).intValue()
, "CNY", "order error", SystemConst.WEIXIN_NOTIFY_URL + "/refund");//refundIn.getRefundDesc()
wxApplyRefundIn.setSign(MapUtils.getObjectMD5Sign(wxApplyRefundIn, payInfoOut.getMchKey()));
//调用接口
wxApplyRefundInXml = XmlUtils.beanToXml(wxApplyRefundIn);
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File(SystemConst.WX_Cert_URL+payInfoOut.getCertFile()));
try {
keyStore.load(instream,payInfoOut.getMchId().toCharArray());
}finally {
instream.close();
}
CloseableHttpClient httpclient = null;
CloseableHttpResponse response = null;
try{
// Trust own CA and all self-signed certs
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore
, payInfoOut.getMchId().toCharArray()).build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(
sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
httpclient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
HttpPost httpPost = new HttpPost(SystemConst.WX_Refund_URL);
httpPost.setEntity(new StringEntity(wxApplyRefundInXml));
response = httpclient.execute(httpPost);
int contentLength = (int) response.getEntity().getContentLength();
byte[] wxApplyPayOutBytes = new byte[contentLength];
InputStream outStream = response.getEntity().getContent();
outStream.read(wxApplyPayOutBytes, 0, contentLength);
wxApplyRefundOutXml = new String(wxApplyPayOutBytes, "UTF-8");
}finally {
response.close();
httpclient.close();
}
WxApplyRefundOut wxApplyRefundOut = XmlUtils.xmlContentToBean(wxApplyRefundOutXml, WxApplyRefundOut.class);
if (wxApplyRefundOut == null) {
throw new Exception("微信支付响应异常");
}
if ("FAIL".equals(wxApplyRefundOut.getReturn_code())) {
throw new Exception(wxApplyRefundOut.getReturn_msg());
}
//验证签名
/*String sign = MapUtils.getObjectMD5Sign(wxApplyRefundOut, payInfoOut.getMchKey());
if (!sign.equals(wxApplyRefundOut.getSign())) {
throw new BusinessException("验证签名失败");
}*/
if ("FAIL".equals(wxApplyRefundOut.getResult_code())) {
throw new Exception("err_code:" + wxApplyRefundOut.getErr_code() + ",err_code_des:" + wxApplyRefundOut.getErr_code_des());
}
result = true;
}catch (Exception e){
refundIn.setErrorMsg(e.getMessage());
logger.error("微信退款申请异常", e);
}finally {
//记录退款请求日志
logger.debug("微信退款申请,请求("+DateUtils.formatDateTime(wxReqDate)+"):"+wxApplyRefundInXml
+"响应("+DateUtils.formatDateTime(new Date())+"):"+wxApplyRefundOutXml);
}
return result;
}
これは、以下のピット言いました:
1.マイクロチャネルの有料、普通のユーザーとマイクロチャネルビジネスの背景ショーの成功を見ては、どのようにこの順番で取ります。
はい、あなたはその権利、マイクロチャネルの有料ポイントを読んで、加盟店側の注文番号が、彼はすべての文字に変更、ハハ、マイクロチャンネル公式の回答を見て与えられました。
それは、サポートされていないハハ、私を殺して、マイクロチャネルビジネスの背景は、マイクロチャネルの製品をサポートしていない、とにかく、私は本当に気分が悪く。
!!!我々はポイントの開発に注意を払うときに出てきました
ポイントは、払い戻しを支払うとき、あなたはTRANSACTION_IDを使用しなければならない、と秩序が存在しないと文句を言うだろうとして、out_trade_no通過しない、out_trade_no使用することはできません。払い戻しのコールバック通知は、同じ理由で、注意互換性の処理です。(マイクロチャネル推定値の更新が続きます)
そして、処理ロジック返金コールバック通知の結果を見てみましょう。
/**
* 微信退款回调
*
* @param request
* @param response
* @return
* @throws Exception
*/
public void refund(HttpServletRequest request, HttpServletResponse response) throws Exception {
boolean isOk = false;
String message = null;
String reqXml = "";String resXml = "";
PayOrderIn orderIn = null;
WxRefundNotifyIn reqParam = null;
WxRefundNotifyReqInfo reqInfo = null;
try {
//解析报文
ServletInputStream servletInputStream = request.getInputStream();
int contentLength = request.getContentLength();
byte[] callBackInBytes = new byte[contentLength];
servletInputStream.read(callBackInBytes, 0, contentLength);
reqXml = new String(callBackInBytes, "UTF-8");
logger.info("【微信退款回调开始】请求报文:" + reqXml);
//记录回调日志
//xml转object
reqParam = XmlUtils.xmlContentToBean(reqXml, WxRefundNotifyIn.class);
if (reqParam == null) {
logger.error("回调参数反序列化失败");
return;
}
if (WXPayConstants.FAIL.equals(reqParam.getReturn_code())) {
message = reqParam.getReturn_msg();
logger.error(message);
return;
}
PayConfig payConfig = null;
if (StringUtils.isNotBlank(reqParam.getMch_id())) { //订单有收款信息,获取商户收款账户信息
GetPayInfoIn payInfoIn = new GetPayInfoIn(reqParam.getMch_id(),PayTypeEnum.wx_payscore.getVal());
GetPayInfoOut payInfoOut = customerFacade.getPayInfo(payInfoIn);
}
if (payConfig == null) {
WxConfig config = SpringUtils.getBean(WxConfig.class);
payConfig = new PayConfig(config.getAppID(), config.getMchID(),config.getKey());
}
//aes解密
String reqInfoXml = AESUtils.decryptData(reqParam.getReq_info(), payConfig.getApiSecret());
reqInfo = XmlUtils.xmlContentToBean(reqInfoXml, WxRefundNotifyReqInfo.class);
if (reqInfo == null) {
logger.error("回调参数“reqInfo”反序列化失败");
return;
}
logger.debug("【微信退款回调,解密后参数:】{}",JSON.toJSONString(reqInfo));
//boolean isValid = WXPayUtil.isSignatureValid(reqXml, payConfig.getApiSecret());//验证签名
//if (!isValid) {
// logger.error("签名验证失败");
// return;
//}
if (!WXPayConstants.SUCCESS.equals(reqInfo.getRefund_status())) {
logger.error("退款失败");
return;
}
isOk = true;
logger.debug("微信退款回调成功");
} catch (Exception e) {
isOk = false;
message = e.getMessage();
logger.info("微信退款回调处理异常:", e);
} finally {
try{
//处理业务逻辑
}catch (Exception e){
logger.error("微信退款回调逻辑处理异常", e);
}
try {
WxRefundNotifyOut resParam = new WxRefundNotifyOut();
if (isOk) {
resParam.setReturn_code(WXPayConstants.SUCCESS);
} else {
resParam.setReturn_code(WXPayConstants.FAIL);
resParam.setReturn_msg(message);
}
resXml = XmlUtils.beanToXml(resParam);
byte[] resBytes = resXml.getBytes(Charset.forName("UTF-8"));
ServletOutputStream servletOutputStream = response.getOutputStream();
servletOutputStream.write(resBytes);
} catch (Exception e) {
logger.error("微信退款回调应答异常,", e);
}
logger.info("【微信退款回调结束】应答报文:" + resXml);
}
}
私は、これは小さなマイクロチャネルパートナーのために引き継ぐために信じて、何も難しくありません、2つのツールがあります:XMLのターンJavaBeanと対称AES暗号解読は、小さなプライベートのパートナーが私を信じることができるが必要です。
ハハ、これまでのところ、私たちのマイクロチャネルの有料ポイントドッキングは完了です。我々がサポートできることを願って、問題領域はまた、補正の神を歓迎します。