接上一篇Java微信支付-统一下单API,本篇在上篇文章的基础上讲述调用统一下单API用户支付成功之后微信异步回调通知
下文中所需配置、类都在以请查看以上链接内容。
在调用微信支付-统一下单API时,会传递
notify_url
这个参数给微信,这个参数是用户成功支付之后微信端会向此地址进行通知,我们应该在接受到微信发来的通知时进行验签确保安全性。
注意:notify_url
必须为外网可访问的url,不能携带参数。测试时可以使用内网穿透
进行测试,这个东西在此我就不赘述了,需要的朋友自行Google。
话不多说,直接上码
/**
* 微信支付Controller.
*
* @create: 2019-10-10 15:25
* @author: Sun
*/
@RequestMapping(value = "/wxpay")
@RestController
@Slf4j
public class WxPayController {
/**
* 微信支付异步回调接口
*
* @return
*/
@RequestMapping(value = "/pay/async/notify")
public void payAsyncNotify(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
log.info("[payAsyncNotify]");
String resultXml = wxPayService.payAsyncNotifyVerificationSign(httpServletRequest);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(httpServletResponse.getOutputStream());
bufferedOutputStream.write(resultXml.getBytes());
bufferedOutputStream.flush();
bufferedOutputStream.close();
}
}
/**
* 微信支付接口.
*
* @create: 2019-10-10 15:25
* @author: Sun
*/
public interface WxPayService {
/**
* 微信支付异步通知验证签名
* @param httpServletRequest
* @return
*/
String payAsyncNotifyVerificationSign(HttpServletRequest httpServletRequest);
}
/**
* 微信支付接口实现
*
* @create: 2019-10-10 15:40
* @author: Sun
*/
@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {
@Autowired
private MyWxPayConfig myWxPayConfig;
@Override
public String payAsyncNotifyVerificationSign(HttpServletRequest httpServletRequest) {
WXPay wxPay = new WXPay(myWxPayConfig);
String returnXmlMessage = null;
String notifyXmlData = null;
try {
notifyXmlData = readXmlFromStream(httpServletRequest);
Map<String, String> notifyMapData = WXPayUtil.xmlToMap(notifyXmlData);
log.info("[payAsyncNotifyVerificationSign] [xml转换为map数据成功] [notifyMapData:{}]", notifyMapData);
// 验证签名
boolean signatureValid = wxPay.isPayResultNotifySignatureValid(notifyMapData);
if (signatureValid) {
// TODO:订单支付成功之后相关业务逻辑...
// 一切正常返回的xml数据
returnXmlMessage = setReturnXml(WXPayConstants.SUCCESS, "OK");
log.info("[payAsyncNotifyVerificationSign] [out_trade_no:{}] [支付成功异步消息处理成功:{}]", notifyMapData.get("out_trade_no"), returnXmlMessage);
} else {
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "Verification sign failed!");
log.info("[payAsyncNotifyVerificationSign] [out_trade_no:{}] [验签失败:{}]", notifyMapData.get("out_trade_no"), returnXmlMessage);
}
} catch (IOException e) {
log.error("[payAsyncNotifyVerificationSign] [读取微信服务器返回流中xml数据时发生异常:{}] ", ExceptionUtils.getStackTrace(e));
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "An exception occurred while reading the WeChat server returning xml data in the stream.");
} catch (Exception e) {
log.error("[payAsyncNotifyVerificationSign] [xml数据:{}] [异常:{}] ", notifyXmlData, ExceptionUtils.getStackTrace(e));
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "Payment successful, exception occurred during asynchronous notification processing.");
log.warn("[payAsyncNotifyVerificationSign] [支付成功异步消息处理失败:{}]", returnXmlMessage);
}
return returnXmlMessage;
}
/**
* 从流中读取微信返回的xml数据
*
* @param httpServletRequest
* @return
* @throws IOException
*/
private String readXmlFromStream(HttpServletRequest httpServletRequest) throws IOException {
InputStream inputStream = httpServletRequest.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
final StringBuffer sb = new StringBuffer();
String line = null;
try {
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
} finally {
bufferedReader.close();
inputStream.close();
}
return sb.toString();
}
/**
* 设置返回给微信服务器的xml信息
*
* @param returnCode
* @param returnMsg
* @return
*/
private String setReturnXml(String returnCode, String returnMsg) {
return "<xml><return_code><![CDATA[" + returnCode + "]]></return_code><return_msg><![CDATA[" + returnMsg + "]]></return_msg></xml>";
}
}