第一步:注册微信支付账户,开通扫码支付
具体流程请参照官方说明
第二步:创建Maven项目
1. 添加微信支付SDK依赖、二维码工具依赖(微信支付需要自己通过二维码工具生成支付二维码)
<!-- 微信支付 --> <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency> <!-- google二维码工具 --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.1.0</version> </dependency>
2. 实现SDK微信配置类,创建商户自己的配置类
public class WxPayConfig implements WXPayConfig{ private byte[] certData; //初始化退款、撤销时的商户证书 public WxPayConfig() throws Exception { String certPath = "D://第三方开放平台/wx_apiclient_cert.p12"; File file = new File(certPath); InputStream certStream = new FileInputStream(file); this.certData = new byte[(int) file.length()]; certStream.read(this.certData); certStream.close(); } public String getAppID() { return ""; } /** 微信支付商户号 */ public String getMchID() { return ""; } public String getKey() { return ""; } public int getHttpConnectTimeoutMs() { return 8000; } public int getHttpReadTimeoutMs() { return 10000; } @Override public InputStream getCertStream() { ByteArrayInputStream certBis; certBis = new ByteArrayInputStream(this.certData); return certBis; } }
3. 创建微信支付的控制器类
3.1 初始化微信支付的SDK客户端
private WxPayConfig config; private WXPay wxpay; public WxPayController() { try { //初始化微信支付客户端 config = new WxPayConfig(); wxpay = new WXPay(config); } catch (Exception e) { e.printStackTrace(); } }
3.2 创建预支付接口,生成支付二维码(可以在页面添加img标签,让它的url指向这里就能直接在页面特定区域显示二维码了)
/** * 预支付接口,生成支付二维码 * @param order * @return * @throws Exception */ @RequestMapping("/wxpay/pay") public void pay(HttpServletResponse response) throws Exception { //TODO:这里执行商户系统创建新的订单操作 WxPayOrder order = new WxPayOrder(); order.setOut_trade_no(System.currentTimeMillis() + ""); wxPayService.createOrder(order); //设置请求参数 Map<String, String> data = new HashMap<String, String>(); data.put("body", "微信支付测试"); data.put("out_trade_no", order.getOut_trade_no()); data.put("device_info", ""); data.put("fee_type", "CNY"); data.put("total_fee", "1"); data.put("spbill_create_ip", "192.168.0.119"); data.put("notify_url", notify_url); data.put("trade_type", "NATIVE"); // 此处指定为扫码支付 data.put("product_id", "12"); try { //发起支付 Map<String, String> resp = wxpay.unifiedOrder(data); //获取二维码URL String code_url = resp.get("code_url"); //根据url生成二维码 MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); // 设置二维码参数 Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); BitMatrix bitMatrix = multiFormatWriter.encode(code_url, BarcodeFormat.QR_CODE, 300, 300, hints); //返回二维码 MatrixToImageWriter.writeToStream(bitMatrix, "jpg", response.getOutputStream()); } catch (Exception e) { e.printStackTrace(); } }
3.3 创建支付结果回调接口(回调的URL必须公网可以访问,测试时可以使用花生壳等工具映射一个公网地址
/** * 支付结果回调 * @return * @throws Exception */ @PostMapping("/wxpay/notify_url") public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception { // 读取回调内容 InputStream inputStream; StringBuffer sb = new StringBuffer(); inputStream = request.getInputStream(); String s; BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); while ((s = in.readLine()) != null) { sb.append(s); } in.close(); inputStream.close(); // 支付结果通知的xml格式数据 String notifyData = sb.toString(); // 转换成map Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData); //支付确认内容 String resXml = ""; //验证签名 if (wxpay.isPayResultNotifySignatureValid(notifyMap)) { // 签名正确 WxPayOrder order = wxPayService.getOrder(notifyMap.get("out_trade_no")); if(order != null) { if("SUCCESS".equals(notifyMap.get("result_code"))) { //交易成功 // TODO:更新订单 System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付成功"); } else { //交易失败 System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败"); } } // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功 //设置成功确认内容 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { // 签名错误,如果数据里没有sign字段,也认为是签名错误 //设置失败确认内容 resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg></return_msg>" + "</xml> "; System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败"); } //发送通知 response.getWriter().println(resXml); }
3.4 创建申请退款接口(这里一定要注意先要下载并配置证书,否则会报错;证书下载请参考官方文档,证书配置见商户微信配置类)
/** * 微信申请退款接口 * @param out_trade_no 订单号 * @throws Exception */ @RequestMapping("/wxpay/refund") public void refund(String out_trade_no) throws Exception { //设置请求参数 HashMap<String, String> data = new HashMap<String, String>(); data.put("out_trade_no", out_trade_no); data.put("out_refund_no", out_trade_no); data.put("total_fee", "1"); data.put("refund_fee", "1"); data.put("refund_fee_type", "CNY"); data.put("op_user_id", config.getMchID()); try { //调用sdk发起退款 Map<String, String> result = wxpay.refund(data); if("SUCCESS".equals(result.get("result_code"))) { //TODO:更新订单 System.out.println("订单" + out_trade_no + "微信退款成功"); } } catch (Exception e) { e.printStackTrace(); } }
第三步:测试支付、退款
1. 运行项目 mvn jetty:run
2. 测试支付接口:http://localhost:8080/wxpay/pay
3. 测试退款接口:http://localhost:8080/wxpay/refund
说明:当前项目仅实现了简单的支付和退款功能,代码大部分搬自官方示例,并不包括完整的支付流程,有什么不明白的地方,欢迎留言