需求分析
用戶在提交訂單后,如果是選擇支付方式為微信支付,那應該跳轉到微信支付二維碼頁面,用戶掃描二維碼可以進行支付,金額與訂單金額相同。
實現思路
前端頁面向后端傳遞訂單號,后端根據訂單號查詢訂單,檢查是否為當前用戶的未支付訂單,如果是則根據訂單號和金額生成支付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。添加地址路由標識