- 把sdk复制进项目中,如下图
- 写一个类继承微信SDK中的 WXPayConfig
import org.springframework.stereotype.Service; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * 继承微信sdk的配置类 */ @Service public class MyWxPayConfig extends WXPayConfig { private byte[] certData; private String appId = "";//微信提供的appid private String wxPayKey = "";//微信提供的密钥 private String wxPayMchId = "";//微信提供的商务id //本地证书路径 private String linuxOS = "/mnt/mall-service/pay/wechatKey/apiclient_cert.p12"; private String windowsOS = "D:\\work\\mj_mall\\jeecg-cloud\\key\\apiclient_cert.p12"; @Override public String getAppID() { return appId; } @Override public String getMchID() { return wxPayMchId; } @Override public String getKey() { return wxPayKey; } @Override public InputStream getCertStream() { return new ByteArrayInputStream(this.certData); } @Override public IWXPayDomain getWXPayDomain() { IWXPayDomain iwxPayDomain = new IWXPayDomain() { @Override public void report(String domain, long elapsedTimeMillis, Exception ex) { } @Override public DomainInfo getDomain(WXPayConfig config) { return new IWXPayDomain.DomainInfo(WXPayConstants.DOMAIN_API, true); } }; return iwxPayDomain; } /** * 构造方法读取证书, 通过getCertStream 可以使sdk获取到证书 */ public MyWxPayConfig() throws Exception { //通过服务操作系统判断使用的证书地址,win 和 linux 路径不通 String property = System.getProperty("os.name"); File file = null; if (property.contains("Windows") || property.contains("windows")) { file = new File(windowsOS); } else { file = new File(linuxOS); } InputStream certStream = new FileInputStream(file); this.certData = new byte[(int) file.length()]; certStream.read(this.certData); certStream.close(); } }
- 发起支付前需要统一下单
@Autowired private MyWxPayConfig myWxPayConfig; public Result<Object> wxPayV2SubmitOrder(@RequestParam(name = "orderId") String orderId) { try { Order order = orderApi.getOrderInfoById(orderId); Customer customer = customerApi.getCustomerById(order.getCustomerId()); SysUser sysUser = sysUserRemoteApi.getSysUser(customer.getUserId()); // 统一下单,myWxPayConfig是继承SDK的那个类 WXPay wxpay = new WXPay(myWxPayConfig); Map<String, String> data = new HashMap<String, String>(); data.put("body", "统一下单"); data.put("out_trade_no", order.getOrderCode()); // 订单唯一编号, 不允许重复 //data.put("total_fee", String.valueOf(order.getOrderPrice().intValue())); // 订单金额, 单位分 data.put("total_fee", String.valueOf(1)); // 订单金额, 单位分 data.put("spbill_create_ip", oConvertUtils.getIpAddrByRequest(SpringContextUtils.getHttpServletRequest())); // 下单ip data.put("openid", sysUser.getThirdId()); // 微信公众号统一标示openid data.put("notify_url", payNotifyUrl); // 订单结果通知, 微信主动回调此接口 data.put("trade_type", "JSAPI"); // 固定填写 //下单 Map<String, String> response = wxpay.unifiedOrder(data); logger.info(JSONObject.toJSONString(response)); String returnCode = response.get("return_code"); String resultCode = response.get("result_code"); String returnMsg = response.get("return_msg"); String prepayId = response.get("prepay_id"); if (CollUtil.isEmpty(response) || !returnCode.equals("SUCCESS") || !resultCode.equals("SUCCESS") || !returnMsg.equals("OK") || null == prepayId) { //微信支付下单失败 return Result.error(response.get("err_code_des")); } //下单成功去获取调起微信支付参数 Map<String, String> map = wechatCreatePay(prepayId); logger.info(JSONObject.toJSONString(map)); if (CollUtil.isEmpty(map) || map.size() == 0) { return Result.error("支付调起参数异常"); } return Result.ok(map); } catch (Exception e) { e.printStackTrace(); return null; } }
- 获取微信支付调起参数
public Map<String, String> wechatCreatePay(String prepayId) { try { Map<String, String> wxPayMap = new HashMap<String, String>(); wxPayMap.put("appId", myWxPayConfig.getAppID()); wxPayMap.put("timeStamp", String.valueOf(WXPayUtil.getCurrentTimestamp())); wxPayMap.put("nonceStr", WXPayUtil.generateNonceStr()); wxPayMap.put("package", "prepay_id=" + prepayId); wxPayMap.put("signType", "MD5"); // 加密串中包括 appId timeStamp nonceStr package signType 5个参数, 通过sdk WXPayUtil类加密, 注意, 此处使用 MD5加密 方式 String sign = WXPayUtil.generateSignature(wxPayMap, myWxPayConfig.getKey()); // 返回给前端调起微信支付的必要参数 Map<String, String> map = new HashMap<>(); map.put("prepay_id", prepayId); map.put("paySign", sign); map.putAll(wxPayMap); return map; } catch (Exception e) { e.printStackTrace(); return null; } }
- 参数获取成功后返回给前端调用就OK了
华丽的分割线---------------------------------------------------------------
- 支付成功之后支付回调,提供给微信调用的
public String wechatPayCallback(HttpServletRequest request, HttpServletResponse response) { try { InputStream is = request.getInputStream(); //将InputStream转换成String BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } String resXml = sb.toString(); logger.info("微信支付异步通知请求包------"); logger.info(resXml); return wechatPayBack(resXml); } catch (Exception e) { logger.error("微信支付回调通知失败", e); String result = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> "; return result; } }
public String wechatPayBack(String xmlStr) { String xmlBack = ""; Map<String, String> notifyMap = null; try { WXPay wxpay = new WXPay(myWxPayConfig); notifyMap = WXPayUtil.xmlToMap(xmlStr); // 转换成map if (wxpay.isPayResultNotifySignatureValid(notifyMap)) { logger.info("签名成功 \r\n" + JSONObject.toJSONString(notifyMap)); // 签名正确 // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功 String returnCode = notifyMap.get("return_code").trim();//状态 //系统支付订单编号 String outTradeNo = notifyMap.get("out_trade_no").trim();//订单号 if (null == outTradeNo) { logger.info("微信支付回调失败订单号: {}", notifyMap); xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg></xml> "; return xmlBack; } //交易类型 String tradeType = notifyMap.get("trade_type").trim(); //付款银行 String bankType = notifyMap.get("bank_type").trim(); //微信支付订单号 String transactionId = notifyMap.get("transaction_id").trim(); //支付金额 String cashFee = notifyMap.get("cash_fee").trim(); //订单金额 String totalFee = notifyMap.get("total_fee").trim(); //支付时间 String timeEnd = notifyMap.get("time_end").trim(); //是否关注公众账号 String isSubscribe = notifyMap.get("is_subscribe").trim(); SimpleDateFormat format = new SimpleDateFormat("yyyy-HH-dd HH:mm:ss"); Date date = new SimpleDateFormat("yyyy-HH-dd HH:mm:ss").parse(format.format(new SimpleDateFormat("yyyyHHddHHmmss").parse(timeEnd))); logger.info("微信支付回调成功订单号: {}", notifyMap); xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"; return xmlBack; } else { logger.error("微信支付回调通知签名错误"); xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> "; return xmlBack; } } catch (Exception e) { logger.error("微信支付回调通知失败", e); xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> "; } return xmlBack; }
- 支付流程基本跑完了