最近做的项目涉及到微信公众号的支付,翻遍文档和查阅众多资料后,记一下自己整的过程:
1.先看的官方文档,把DEMO下载下来,发现都是要证书的,继续看文档,API列表
2.还是看文档,参数,坑最多的地方,这里需要在工具类里边先配置几个东西,需要在公众号的账号和商户号里面预先设置好
公众号AppId 微信支付商户号 微信支付API秘钥
微信支付通知URL 我用的是内网穿透工具 nat300 映射的已备案域名
3.调用微信统一下单的接口,微信只接收XML格式的字符串,返回的也是XML格式的字符串,主要代码如下:
/**
* 微信公众号支付统一下单
* @param req
* @param request
* @return
* @throws Exception
*/
@Override
public ServiceResult<Object> unifiedorder(WxOrderReq req, HttpServletRequest request, String openId) {
Map<String, String> paraMap = new HashMap<String, String>();
paraMap.put("appid", WXPayConfig.APP_ID);
paraMap.put("mch_id", WXPayConfig.MCH_ID);
paraMap.put("nonce_str", WXPayUtil.generateNonceStr()); //随机字符串,长度要求在32位以内。
paraMap.put("body", req.getIntroduce());
paraMap.put("out_trade_no", orderNumber);
paraMap.put("total_fee", req.getSum().multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString()); //订单总金额,单位为分
paraMap.put("spbill_create_ip", IpUtil.getIpAddr(request));
paraMap.put("notify_url", WXPayConfig.NOTIFY_URL);
paraMap.put("trade_type", WXPayConfig.TRADE_TYPE_JSAPI);
paraMap.put("openid", openId);
Map<String, String> payMap = new HashMap<String, String>();
try {
String sign = WXPayUtil.generateSignature(paraMap, WXPayConfig.KEY);//签名,将所有的请求参数按照ASCII字典排序后,按照规定格式拼接成字符串,再使用MD5加密后生成
paraMap.put("sign", sign);
// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
String url = WXPayConfig.UNIFIED_ORDER_URL;
String xml = WXPayUtil.mapToXml(paraMap);//将map转成xml格式的 字符串(微信只接受xml格式的字符串)
String xmlStr = HttpKit.post(url, xml); //请求微信统一下单接口(微信只返回xml格式的字符串)
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr); //将xml格式的字符串转成 map
//xmlStr.indexOf("SUCCESS") != -1
if (!map.get("return_code").equals("SUCCESS")) {
return ServiceResult.newFailure(new CodeMsg(-1,"调用接口失败!!!!!!"));
}
// 微信生成的预支付会话标识,该值有效期为2小时
String prepay_id = map.get("prepay_id");
payMap.put("appId", WXPayConfig.APP_ID);
payMap.put("timeStamp", String.valueOf(WXPayUtil.getCurrentTimestamp()));
payMap.put("nonceStr", WXPayUtil.generateNonceStr());
payMap.put("signType", WXPayConfig.SIGNTYPE);
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WXPayUtil.generateSignature(payMap, WXPayConfig.KEY);
payMap.put("paySign", paySign);
payMap.put("outTradeNo",orderNumber);
} catch (Exception e) {
e.printStackTrace();
}
//新增订单业务
return ServiceResult.newSuccess(payMap);
}
4.支付结果通知,这个接口是在工具类中配置好的 微信支付通知url
/**
* 支付结果通知
* @param request
* @param response
*/
public ServiceResult<Object> getWeChatPayReturn(HttpServletRequest request, HttpServletResponse response){
String resSuccessXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
String resFailXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
String resXml = "";
try {
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
WXPayUtil.getLogger().info("wxnotify:微信支付----start----");
// 获取微信调用我们notify_url的返回信息
String result = new String(outSteam.toByteArray(), "utf-8");
WXPayUtil.getLogger().info("wxnotify:微信支付----result----=" + result);
// 关闭流
outSteam.close();
inStream.close();
// xml转换为map
Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
boolean isSuccess = false;
if (WXPayConstants.SUCCESS.equalsIgnoreCase(resultMap.get("return_code"))){
WXPayUtil.getLogger().info("wxnotify:微信支付----返回成功");
if (WXPayUtil.isSignatureValid(resultMap,WXPayConfig.KEY)){
// 订单处理 操作 orderconroller 的回写操作?
WXPayUtil.getLogger().info("wxnotify:微信支付----验证签名成功");
// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = resSuccessXml;
isSuccess = true;
} else {
WXPayUtil.getLogger().error("wxnotify:微信支付----判断签名错误");
}
} else {
WXPayUtil.getLogger().error("wxnotify:支付失败,错误信息:" + resultMap.get("return_msg"));
resXml = resFailXml;
}
// 回调方法,处理业务 - 修改订单支付状态
WXPayUtil.getLogger().info("wxnotify:微信支付回调:修改的订单===>" + resultMap.get("out_trade_no"));
// logger.info("resultMap::::::",resultMap);
ServiceResult<Object> updateResult = orderService.updateOrderState(resultMap.get("out_trade_no"));
if (updateResult.success()){
WXPayUtil.getLogger().info("wxnotify:微信支付回调:修改订单支付状态成功");
} else {
WXPayUtil.getLogger().error("wxnotify:微信支付回调:修改订单支付状态失败");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
// 处理业务完毕
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
} catch (IOException e) {
WXPayUtil.getLogger().error("wxnotify:支付回调发布异常:out:", e);
}
}
return ServiceResult.newSuccess(resXml);
}
5.查询订单 根据订单号向微信发起请求 得知该订单的状态
/**
* 查询订单
* @param req
* @return
* @throws Exception
*/
@Override
public ServiceResult<Object> orderQuery(OrderQueryReq req) {
String trade_state = null;
String accessToken = req.getAccessToken();
ObjectResult<User> userByToken = authFeignService.getUserByToken(accessToken);
User data = userByToken.getData();
if (data == null) {
return ServiceResult.newFailure(CodeMsg.ERROR_ACCESS_TOKEN);
}
Map<String, String> paraMap = new HashMap<String, String>();
paraMap.put("appid",WXPayConfig.APP_ID);
paraMap.put("mch_id",WXPayConfig.MCH_ID);
paraMap.put("nonce_str",WXPayUtil.generateNonceStr()); //随机字符串,长度要求在32位以内。
paraMap.put("out_trade_no",req.getOutTradeNo());
try {
String sign = WXPayUtil.generateSignature(paraMap, WXPayConfig.KEY);//签名,将所有的请求参数按照ASCII字典排序后,按照规定格式拼接成字符串,再使用MD5加密后生成
paraMap.put("sign", sign);
// 查询订单 https://api.mch.weixin.qq.com/pay/orderquery
String url = WXPayConfig.ORDER_QUERY;
String xml = WXPayUtil.mapToXml(paraMap);//将map转成xml格式的 字符串(微信只接受xml格式的字符串)
String xmlStr = HttpKit.post(url, xml); //请求微信查询订单接口(微信只返回xml格式的字符串)
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr); //将xml格式的字符串转成 map
System.err.println(map);
trade_state = map.get("trade_state");
}catch (Exception e){
e.printStackTrace();
}
//SUCCESS—支付成功 REFUND—转入退款 NOTPAY—未支付 CLOSED—已关闭 REVOKED—已撤销(付款码支付)
// USERPAYING--用户支付中(付款码支付) PAYERROR--支付失败(其他原因,如银行返回失败)
if ("SUCCESS".equals(trade_state)){
return ServiceResult.newSuccess(0);
}
if ("REFUND".equals(trade_state)){
return ServiceResult.newSuccess("转入退款");
}
if ("NOTPAY".equals(trade_state)){
return ServiceResult.newSuccess("未支付");
}
if ("CLOSED".equals(trade_state)){
return ServiceResult.newSuccess("已关闭");
}
if ("REVOKED".equals(trade_state)){
return ServiceResult.newSuccess("已撤销(付款码支付)");
}
if ("USERPAYING".equals(trade_state)){
return ServiceResult.newSuccess("用户支付中(付款码支付)");
}
if ("PAYERROR".equals(trade_state)){
return ServiceResult.newSuccess("支付失败");
}
return ServiceResult.newSuccess(trade_state);
}
比较懒,所以就直接放的代码了,欢迎大家交流指正 tansky1995@gmail.com