支付页面
步骤一:创建 flow3.vue组件
步骤二:引入第三方资源(js、css)
<script> import TopNav from '../components/TopNav' import Footer from '../components/Footer' export default { head: { title: '首页', link: [ {rel:'stylesheet',href: '/style/success.css'}, ], script: [ ] }, components: { TopNav, Footer, }, } </script>
接口
POST http://localhost:10010/order-service/pay { "sn" : "1255513323915579400" }
后端实现
步骤一:编写 PayRequest,用于封装数据
package com.czxy.changgou4.vo; import lombok.Data; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Data public class PayRequest { private Long sn; }
步骤二:检查order服务,yml文件中是否有微信配置
sc: pay: appID: wx8397f8696b538317 mchID: 1473426802 key: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb httpConnectTimeoutMs: 5000 httpReadTimeoutMs: 10000
步骤三:编写PayProperties,用于加载微信配置
package com.czxy.changgou4.config; import com.github.wxpay.sdk.WXPayConfig; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import java.io.InputStream; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Data @ConfigurationProperties(prefix = "sc.pay") public class PayProperties implements WXPayConfig { private String appID; // 公众账号ID private String mchID; // 商户号 private String key; // 生成签名的密钥 private int httpConnectTimeoutMs; // 连接超时时间 private int httpReadTimeoutMs; // 读取超时时间 @Override public InputStream getCertStream() { //加载证书,需要通过账号中心生成 return null; } }
步骤四:编写PayState,自定义支付状态
package com.czxy.changgou4.utils; import lombok.Getter; /** * 自定义支付状态,微信支持多种状态,此处统一四种: * SUCCESS—支付成功、NOTPAY—未支付、CLOSED—已关闭、PAYERROR--支付失败 * @author 桐叔 * @email liangtong@itcast.cn */ @Getter public enum PayState { NOT_PAY(0,"未支付"),SUCCESS(1,"支付成功"),CLOSED(2,"已关闭"),PAY_ERROR(3,"支付失败"); PayState(int code,String desc) { this.code = code; this.desc = desc; } private int code; //自定义编码 private String desc; //描述信息 }
步骤五:编写PayHelper,用于微信操作的工具类
package com.czxy.changgou4.utils; import com.czxy.changgou4.config.PayProperties; import com.github.wxpay.sdk.WXPay; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Component @EnableConfigurationProperties(PayProperties.class) public class PayHelper { private WXPay wxPay; @Bean public WXPay wxPay(PayProperties payProperties){ if(wxPay == null){ wxPay = new WXPay(payProperties); } return wxPay; } private static final Logger logger = LoggerFactory.getLogger(PayHelper.class); public PayHelper() { } public PayHelper(PayProperties payProperties) { wxPay = new WXPay(payProperties); } public String createPayUrl(Long sn) { String key = "pay.url." + sn; try { Map<String, String> data = new HashMap<>(); // 商品描述 data.put("body", "商城测试"); // 订单号 data.put("out_trade_no", sn.toString()); //货币 data.put("fee_type", "CNY"); //金额,单位是分 data.put("total_fee", "1"); //调用微信支付的终端IP(商城的IP) data.put("spbill_create_ip", "127.0.0.1"); //回调地址 data.put("notify_url", "http://test.jingxi.com/wxpay/notify"); // 交易类型为扫码支付 data.put("trade_type", "NATIVE"); //商品id,使用假数据 data.put("product_id", "1234567"); Map<String, String> result = this.wxPay.unifiedOrder(data); if ("SUCCESS".equals(result.get("return_code"))) { if("SUCCESS".equals(result.get("result_code"))){ String url = result.get("code_url"); return url; } else { logger.error("创建预交易订单失败,错误信息:{}", result.get("err_code_des")); return null; } } else { logger.error("创建预交易订单失败,错误信息:{}", result.get("return_msg")); return null; } } catch (Exception e) { logger.error("创建预交易订单异常", e); return null; } } /** * 查询订单状态 * 交易状态参考:(trade_state) SUCCESS—支付成功 REFUND—转入退款 NOTPAY—未支付 CLOSED—已关闭 REVOKED—已撤销(付款码支付) USERPAYING--用户支付中(付款码支付) PAYERROR--支付失败(其他原因,如银行返回失败) * @param sn * @return */ public PayState queryOrder(Long sn) { Map<String, String> data = new HashMap<>(); // 订单号 data.put("out_trade_no", sn.toString()); try { Map<String, String> result = this.wxPay.orderQuery(data); if("SUCCESS".equals(result.get("return_code"))){ if("SUCCESS".equals(result.get("result_code"))) { String tradeState = result.get("trade_state"); if ("SUCCESS".equals(tradeState)) { return PayState.SUCCESS; } if ("NOTPAY".equals(tradeState)) { return PayState.NOT_PAY; } if ("CLOSED".equals(tradeState)) { return PayState.CLOSED; } } } return PayState.PAY_ERROR; } catch (Exception e) { logger.error("查询订单状态异常", e); return PayState.PAY_ERROR; } } }
步骤五:编写PayService,调用工具类,用于生成支付接口
package com.czxy.changgou4.service; import com.czxy.changgou4.vo.PayRequest; /** * @author 桐叔 * @email liangtong@itcast.cn */ public interface PayService { public String pay(PayRequest payRequest); }
package com.czxy.changgou4.service.impl; import com.czxy.changgou4.service.PayService; import com.czxy.changgou4.utils.PayHelper; import com.czxy.changgou4.vo.PayRequest; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Service public class PayServiceImpl implements PayService { @Resource private PayHelper payHelper; @Override public String pay(PayRequest payRequest) { //根据sn查询订单 //获得微信支付路径 String payUrl = payHelper.createPayUrl(payRequest.getSn()); //返回支付路径 return payUrl; } }
步骤六:编写PayController,根据sn生产微信支付路径
package com.czxy.changgou4.controller; import com.czxy.changgou4.service.PayService; import com.czxy.changgou4.vo.BaseResult; import com.czxy.changgou4.vo.PayRequest; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author 桐叔 * @email liangtong@itcast.cn */ @RestController @RequestMapping("/pay") public class PayController { @Resource private PayService payService; @PostMapping public BaseResult pay(@RequestBody PayRequest payRequest){ //获得支付路径 String payUrl = payService.pay(payRequest); //返回 return BaseResult.ok("二维码生产成功").append("wxurl",payUrl); } }
前端实现
步骤一:修改apiclient.js文件,生成位置支付路径
pay : ( params ) => { return axios.post("/order-service/pay" ,params ) }
步骤二:拷贝qrcode.min.js 用于生成二维码
步骤三:导入qrcode.min.js
script: [ { type: 'text/javascript', src: '/js/qrcode.min.js' } ]
步骤四:页面加载成功,把微信支付路径生产二维码
data() { return { sn: this.$route.query.sn, } }, async mounted() { let {data} = await this.$request.pay({"sn":this.sn}) new QRCode( document.getElementById("qrcode") , data.other.wxurl ) },
步骤五:确定二维码生成的位置
<p> <div id="qrcode" style="width:256px;margin: 0 auto;"></div> </p>
步骤六:优化,添加样式,
<style> #qrcode img { background-color: #fff; padding: 6px; } </style>