1. 下载微信官网demo
工欲善其事必先利其器(下载微信官网支付demo) https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
知其然知其所以然(熟悉接口API参数方便结合业务场景获取): https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
如不知该用哪个版本可以参考: https://download.csdn.net/download/qq_16771097/16669146
*简单的配置我这里就不复述了,看过官网下过demo,修改MyConfig配置文件就好。*
特别注意:
WXPay.java 默认是SignType.HMACSHA256需要修改为SignType.MD5;
异步回调通知(支付/退款)必须配置外网可以访问https,并且无参数!!!
public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox)
throws Exception {
this.config = config;
this.notifyUrl = notifyUrl;
this.autoReport = autoReport;
this.useSandbox = useSandbox;
if (useSandbox) {
this.signType = SignType.HMACSHA256; // 沙箱环境
}else {
this.signType = SignType.MD5;
}
this.wxPayRequest = new WXPayRequest(config);
}
2.微信支付-订单回调接口
特别注意: // 交易成功判断条件: return_code、result_code和trade_state都为SUCCESS
/**
* 微信支付-订单回调接口
* @param request
* @param response
* @throws Exception
*/
@ApiOperation(value = "微信支付-订单回调接口")
@RequestMapping(value="/wxPay/async", produces="text/html;charset=utf-8")
public void wxPayAsyncNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
String resultXml = stuPlatNotifyService.wxPayAsyncNotify(request);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(response.getOutputStream());
bufferedOutputStream.write(resultXml.getBytes());
bufferedOutputStream.flush();
bufferedOutputStream.close();
}
//微信支付回调 先判断返回结果是否正常 再验证签名 再根据 商品订单号 查询支付订单是否支付完成 最后更新订单状态与数据
@Override
public String wxPayAsyncNotify(HttpServletRequest request) {
String returnXmlMessage = null;
String notifyXmlData = null;
try {
notifyXmlData = readXmlFromStream(request);
Map<String, String> notifyMapData = WXPayUtil.xmlToMap(notifyXmlData);
if (WXPayConstants.SUCCESS.equals(notifyMapData.get("return_code"))) {
//log.info(">>>----------------wxPayAsyncNotify---------------:{}", notifyMapData);
String outTradeNo = notifyMapData.get("out_trade_no"); //获取 商品订单号
WXPay wxpay = new WXPay(new MyConfig(certUrl));
boolean signatureValid = wxpay.isPayResultNotifySignatureValid(notifyMapData); // 验证签名
if (signatureValid) {
//先查询核实订单再确认更新订单
Map<String, String> map = WxPayUtils.orderQueryDetail(outTradeNo, certUrl);
String wxPayStatus = map.get(WXPayConstants.WX_PAY_STATUS);
if(StringUtils.isNotEmpty(wxPayStatus) && wxPayStatus.equals(WXPayConstants.SUCCESS)){
//log.info(">>>----------------wxPayAsyncNotify---------------:{}", map);
//String transactionId = map.get("transaction_id");
//String timeEnd = DateFormatUtils.getDateStr(map.get("time_end"));
// update status success
// 一切正常返回的xml数据
returnXmlMessage = setReturnXml(WXPayConstants.SUCCESS, "OK");
}else{
// update status fail
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "-wxPayAsyncNotify-orderQuery-failed!");
log.error("-wxPayAsyncNotify-orderQuery-failed!--"+map.get("return_msg"));
}
} else {
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "-wxPayAsyncNotify-Verification sign failed!");
log.error("-wxPayAsyncNotify-Verification sign failed!");
}
}else{
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "--wxPayAsyncNotify--");
log.error("-wxPayAsyncNotify--"+notifyMapData.get("return_msg"));
}
} catch (IOException e) {
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "An exception occurred while reading the WeChat server returning xml data in the stream.");
log.error("-[wxPayAsyncNotify] [读取微信服务器返回流中xml数据时发生异常:{}] ", ExceptionUtils.getStackTrace(e));
} catch (Exception e) {
log.error("-[wxPayAsyncNotify] [xml数据:{}] [异常:{}] ", notifyXmlData, ExceptionUtils.getStackTrace(e));
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "Payment successful, exception occurred during asynchronous notification processing.");
log.error("-[wxPayAsyncNotify] [支付成功异步消息处理失败:{}]", returnXmlMessage);
}
return returnXmlMessage;
}
3.微信退款-订单回调接口
/**
* 微信退款-订单回调接口
* @param request
* @param response
* @throws Exception
*/
@ApiOperation(value = "微信退款-订单回调接口")
@RequestMapping(value="/wxRefund/async", produces="text/html;charset=utf-8")
public void wxRefundAsyncNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
String resultXml = stuPlatNotifyService.wxRefundAsyncNotify(request);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(response.getOutputStream());
bufferedOutputStream.write(resultXml.getBytes());
bufferedOutputStream.flush();
bufferedOutputStream.close();
}
//微信退款回调 先判断返回结果是否正常 再解析加密信息 再根据 商品订单号 查询支付订单是否退款完成 最后更新订单状态与数据
@Override
public String wxRefundAsyncNotify(HttpServletRequest request) {
String returnXmlMessage = null;
String notifyXmlData = null;
try {
notifyXmlData = readXmlFromStream(request);
Map<String, String> notifyMapData = WXPayUtil.xmlToMap(notifyXmlData);
if (WXPayConstants.SUCCESS.equals(notifyMapData.get("return_code"))) {
String reqInfo = notifyMapData.get("req_info"); // 获得加密信息
// 进行AES解密 获取req_info中包含的相关信息(解密失败会抛出异常)
String refundData = wxDecodeUtil.decryptData(reqInfo);
Map<String, String> reqInfoMap = WXPayUtil.xmlToMap(refundData);
//log.info(">>>----------------wxRefundAsyncNotify---------------reqInfoMap:{}", reqInfoMap);
String outTradeNo = reqInfoMap.get("out_trade_no"); //获取 商品订单号
String outRefundNo = reqInfoMap.get("out_refund_no"); //获取 退款订单号
//先查询核实订单再确认更新订单
Map<String, String> refundMap = WxPayUtils.refundQuery(outTradeNo, certUrl);
if(WXPayConstants.SUCCESS.equals(refundMap.get("return_code"))){
//log.info(">>>----------------wxRefundAsyncNotify---------------refundMap:{}", refundMap);
String transactionId = refundMap.get("transaction_id");
String refundCount = refundMap.get("refund_count");
if(StringUtils.isNotEmpty(refundCount) && Integer.parseInt(refundCount)>0){
String refundTime = null;
Integer refundInt = Integer.parseInt(refundCount);
boolean refundBool = false;
for(int i=0;i<refundInt;i++){
if(WXPayConstants.SUCCESS.equals(refundMap.get("refund_status_"+i)) && outRefundNo.equals(refundMap.get("out_refund_no_"+i))){
refundBool = true;
refundTime = refundMap.get("refund_success_time_"+i);
break;
}
}
if(refundBool){
//update status success
// 一切正常返回的xml数据
returnXmlMessage = setReturnXml(WXPayConstants.SUCCESS, "OK");
}else{
//update status fail
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "-wxRefundAsyncNotify-refundQuery-out_refund_no--");
log.error("-wxRefundAsyncNotify-refundQuery-out_refund_no--"+refundMap.get("return_msg"));
}
}
}else{
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "-wxRefundAsyncNotify-refundQuery-fail!");
log.error("-wxRefundAsyncNotify-refundQuery-fail!"+refundMap.get("return_msg"));
}
}else{
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "-wxRefundAsyncNotify-refund-fail!");
log.error("-wxRefundAsyncNotify-refund-fail!"+notifyMapData.get("return_msg"));
}
} catch (IOException e) {
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "An exception occurred while reading the WeChat server returning xml data in the stream.");
log.error("[wxRefundAsyncNotify] [读取微信服务器返回流中xml数据时发生异常:{}] ", ExceptionUtils.getStackTrace(e));
} catch (Exception e) {
log.error("[wxRefundAsyncNotify] [xml数据:{}] [异常:{}] ", notifyXmlData, ExceptionUtils.getStackTrace(e));
returnXmlMessage = setReturnXml(WXPayConstants.FAIL, "Payment successful, exception occurred during asynchronous notification processing.");
log.warn("[wxRefundAsyncNotify] [退款异步消息处理失败:{}]", returnXmlMessage);
}
return returnXmlMessage;
}
4.支付回调,退款回调(公共方法)
//从流中读取微信返回的xml数据
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信息
private String setReturnXml(String returnCode, String returnMsg) {
return "<xml><return_code><![CDATA[" + returnCode + "]]></return_code><return_msg><![CDATA[" + returnMsg + "]]></return_msg></xml>";
}
// 下面这段代码至验签的地方,代码是通用的,可以直接用(支付宝获取 支付、退款)
private Map<String, String> getMapParams(HttpServletRequest request){
Map<String, String> params = new HashMap<>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用。
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
return params;
}
5.回调通知注意事项
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=23_8&index=6