微信支付二维码
需求分析
用户在提交订单后,如果是选择支付方式为微信支付,那应该跳转到微信支付二维码页面,用户扫描二维码可以进行支付,金额与订单金额相同。
实现思路
前端页面向后端传递订单号,后端根据订单号查询订单,检查是否为当前用户的未支付订单,如果是则根据订单号和金额生成支付url返给前端,前端得到支付url生成支付二维码。
代码实现
提交订单跳转支付页
1)更新changgou_web_order的application.yml,添加读取超时设置
#请求处理的超时时间 ribbon: ReadTimeout: 4000 #请求连接的超时时间 ConnectTimeout: 3000
2)在changgou_order_web工程resources/templates下添加 '资源/pay.html,fail.html,wxpay.html'。
3)更新changgou_service_order中add() ,设置返回值为订单Id
#orderServiceImpl /** * 增加 * @param order */ @Override public String add(Order order){ List<OrderItem> cartList = cartService.findCartList(order.getUsername()); int totalMoney=0; int totalNum=0; int totalPayMoney=0; for (OrderItem orderItem : cartList) { totalMoney+=orderItem.getMoney(); totalNum+=orderItem.getNum(); totalPayMoney+=orderItem.getPayMoney(); } order.setTotalNum(totalNum); order.setTotalMoney(totalMoney); order.setPayMoney(totalPayMoney); order.setPreMoney(totalMoney-totalPayMoney); //其他数据完善 order.setCreateTime(new Date()); order.setUpdateTime(order.getCreateTime()); order.setBuyerRate("0"); //0:未评价,1:已评价 order.setSourceType("1"); //来源,1:WEB order.setOrderStatus("0"); //0:未完成,1:已完成,2:已退货 order.setPayStatus("0"); //0:未支付,1:已支付,2:支付失败 order.setConsignStatus("0"); //0:未发货,1:已发货,2:已收货 String orderId = idWorker.nextId() + ""; order.setId(orderId); int result = orderMapper.insertSelective(order); for (OrderItem orderItem : cartList) { orderItem.setId(idWorker.nextId()+""); orderItem.setIsReturn("0"); orderItem.setOrderId(order.getId()); orderItemMapper.insertSelective(orderItem); } //扣减库存 skuFeign.decrCount(order.getUsername()); //清除缓存中的数据 redisTemplate.delete("Cart_"+order.getUsername()); return orderId; } #orderController @PostMapping public Result<String> add(@RequestBody Order order){ String username = tokenDecode.getUserInfo().get("username"); order.setUsername(username); String orderId = orderService.add(order); return new Result(true,StatusCode.OK,"添加成功",orderId); }
4) 更新order.html中添加订单js
add:function () { axios.post('/api/worder/add',this.order).then(function (response) { if (response.data.flag){ alert("添加订单成功"); var orderId = response.data.data; location.href="/api/worder/toPayPage?orderId="+orderId; }else{ alert("添加失败"); } }) }
5)在orderController中新增方法,用于跳转支付页
5.1)changgou_service_order_api的OrderFeign新增接口定义
/*** * 根据ID查询数据 * @param id * @return */ @GetMapping("/order/{id}") public Result findById(@PathVariable("id") String id);
5.2) changgou_order_web中的orderController新增方法,跳转支付页
@GetMapping("/toPayPage") public String toPayPage(String orderId, Model model){ Order order= orderFeign.findById(orderId).getData(); model.addAttribute("orderId",orderId); model.addAttribute("payMoney",order.getPayMoney()); return "pay"; }
支付微服务-下单
(1)创建changgou_service_pay (支付微服务), pom.xml添加依赖
<dependency> <groupId>com.changgou</groupId> <artifactId>changgou_common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>3.0.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
排除log包,否则会因为包冲突无法正常启动
(2)创建配置文件application.yml
server: port: 9010 spring: application: name: pay rabbitmq: host: 192.168.200.128 main: allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册 eureka: client: service-url: defaultZone: http://127.0.0.1:6868/eureka instance: prefer-ip-address: true
(3)创建com.github.wxpay.sdk包,包下创建Config类
public class MyConfig extends WXPayConfig { String getAppID() { return "wx8397f8696b538317"; } String getMchID() { return "1473426802"; } String getKey() { return "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"; } InputStream getCertStream() { return null; } IWXPayDomain getWXPayDomain() { return new IWXPayDomain() { public void report(String domain, long elapsedTimeMillis, Exception ex) { } public DomainInfo getDomain(WXPayConfig config) { return new DomainInfo("api.mch.weixin.qq.com",true); } }; } }
(4)创建com.changgou包,包下创建类PayApplication
@SpringBootApplication @EnableEurekaClient public class PayApplication { public static void main(String[] args) { SpringApplication.run(PayApplication.class); } @Bean public WXPay wxPay(){ try { return new WXPay( new MyConfig() ); } catch (Exception e) { e.printStackTrace(); return null; } } }
(3)创建com.changgou.pay.controller包 ,新增WxPayController
@RestController @RequestMapping("/wxpay") public class WxPayController { @Autowired private WxPayService wxPayService; /** * 下单 * @param orderId * @param money * @return */ @GetMapping("/nativePay") public Result nativePay(@RequestParam("orderId")String orderId,@RequestParam("money") Integer money){ Map map = wxPayService.nativePay( orderId, money ); return new Result( true, StatusCode.OK,"",map ); } }
(4)创建com.changgou.pay.service包,包下创建接口WxPayService
public interface WxPayService { /** * 生成微信支付二维码 * @param orderId * @param money * @return */ Map nativePay(String orderId, Integer money); }
(5)创建com.changgou.pay.service.impl 包 ,新增服务类WxPayServiceImpl
@Service public class WxPayServiceImpl implements WxPayService { @Autowired private WXPay wxPay; @Override public Map nativePay(String orderId, Integer money) { try { //1.封装请求参数 Map<String,String> map=new HashMap(); map.put("body","畅购商城");//商品描述 map.put("out_trade_no",orderId);//订单号 //map.put("total_fee",String.valueOf(money*100));//金额,以分为单位 BigDecimal payMoney = new BigDecimal("0.01"); BigDecimal fen = payMoney.multiply(new BigDecimal("100")); //1.00 fen = fen.setScale(0,BigDecimal.ROUND_UP); // 1 map.put("total_fee",String.valueOf(fen)); map.put("spbill_create_ip","127.0.0.1");//终端IP map.put("notify_url","http://www.itcast.cn");//回调地址,先随便填一个 map.put("trade_type","NATIVE");//交易类型 Map<String, String> mapResult = wxPay.unifiedOrder( map ); //调用统一下单 return mapResult; } catch (Exception e) { e.printStackTrace(); return null; } } }
测试:地址栏输入http://localhost:9010/wxpay/nativePay?orderId=990099&money=1
页面对接支付微服务
(1)新增changgou_service_pay_api模块 ,并添加common工程依赖,新增com.changgou.pay.feign包,包下创建接口
@FeignClient("pay") public interface WxPayFeign { /** * 下单 * @param orderId * @param money * @return */ @GetMapping("/wxpay/nativePay") public Result nativePay(@RequestParam("orderId") String orderId, @RequestParam("money") Integer money ); }
(2)changgou_web_order新增PayController
@Controller @RequestMapping("/wxpay") public class PayController { @Autowired private OrderFeign orderFeign; @Autowired private WxPayFeign wxPayFeign; /** * 微信支付二维码 * @param orderId * @return */ @GetMapping public String wxPay(String orderId, Model model){ //根据orderId查询订单 Result orderResult = orderFeign.findById( orderId ); if(orderResult.getData()==null){ //如果订单不存在 return "fail";//出错页 } Order order = orderResult.getData(); //判断支付状态 if( !"0".equals( order.getPayStatus() )){// 如果不是未支付订单 return "fail";//出错页 } Result payResult = wxPayFeign.nativePay( orderId, order.getPayMoney() ); if(payResult.getData()==null){ return "fail";//出错页 } Map payMap= (Map)payResult.getData(); payMap.put( "payMoney", order.getPayMoney() ); payMap.put( "orderId" ,orderId ); model.addAllAttributes( payMap ); return "wxpay"; } }
(3)将静态原型中wxpay.html拷贝到templates文件夹下作为模板,修改模板,部分代码如下:
二维码地址渲染
<script type="text/javascript" th:inline="javascript"> let qrcode = new QRCode(document.getElementById("qrcode"), { width : 200, height : 200 }); qrcode.makeCode([[${code_url}]]); </script>
显示订单号与金额
<h4 class="fl tit-txt"><span class="success-icon"></span><span class="success-info" th:text="|订单提交成功,请您及时付款!订单号:${orderId}|"></span></h4> <span class="fr"><em class="sui-lead">应付金额:</em><em class="orange money" th:text="${payMoney}"></em>元</span>
设置支付跳转
<li><a th:href="|/api/wxpay?orderId=${orderId}|"><img src="/img/_/pay3.jpg"></a></li>
(4) 更新网关地址过滤器。添加wxpay路径的拦截
同时更新网关服务的application.yml。添加地址路由标识