2.微信支付二维码
2.1 需求分析
用户在提交订单后,如果是选择支付方式为微信支付,那应该跳转到微信支付二维码页面,用户扫描二维码可以进行支付,金额与订单金额相同。
2.2 实现思路
前端页面向后端传递订单号,后端根据订单号查询订单,检查是否为当前用户的未支付订单,如果是则根据订单号和金额生成支付url返给前端,前端得到支付url生成支付二维码。
2.3 代码实现
2.3.1 提交订单跳转支付页
1)更新changgou_web_order的application.yml,添加读取超时设置
#请求处理的超时时间
ribbon:
ReadTimeout: 4000
#请求连接的超时时间
ConnectTimeout: 3000
3)更新changgou_service_order中add() ,设置返回值为订单Id
//orderServiceImpl
/**
* 增加
* @param order
*/
@Override
@GlobalTransactional(name = "order_add")
public String add(Order order){
//1.获取购物车的相关数据(redis)
Map cartMap = cartService.list(order.getUsername());
List<OrderItem> orderItemList = (List<OrderItem>) cartMap.get("orderItemList");
//2.统计计算:总金额,总数量
//3.填充订单数据并保存到tb_order
order.setTotalNum((Integer) cartMap.get("totalNum"));
order.setTotalMoney((Integer) cartMap.get("totalMoney"));
order.setPayMoney((Integer) cartMap.get("totalMoney"));
order.setCreateTime(new Date());
order.setUpdateTime(new Date());
order.setBuyerRate("0"); // 0:未评价 1:已评价
order.setSourceType("1"); //1:WEB
order.setOrderStatus("0"); //0:未完成 1:已完成 2:已退货
order.setPayStatus("0"); //0:未支付 1:已支付
order.setConsignStatus("0"); //0:未发货 1:已发货
String orderId = idWorker.nextId()+"";
order.setId(orderId);
orderMapper.insertSelective(order);
//4.填充订单项数据并保存到tb_order_item
for (OrderItem orderItem : orderItemList) {
orderItem.setId(idWorker.nextId()+"");
orderItem.setIsReturn("0"); //0:未退货 1:已退货
orderItem.setOrderId(orderId);
orderItemMapper.insertSelective(orderItem);
}
//扣减库存并增加销量
skuFeign.decrCount(order.getUsername());
//int i =1/0;
//添加任务数据
System.out.println("向订单数据库中的任务表去添加任务数据");
Task task = new Task();
task.setCreateTime(new Date());
task.setUpdateTime(new Date());
task.setMqExchange(RabbitMQConfig.EX_BUYING_ADDPOINTUSER);
task.setMqRoutingkey(RabbitMQConfig.CG_BUYING_ADDPOINT_KEY);
Map map = new HashMap();
map.put("username",order.getUsername());
map.put("orderId",orderId);
map.put("point",order.getPayMoney());
task.setRequestBody(JSON.toJSONString(map));
taskMapper.insertSelective(task);
//5.删除购物车数据(redis)
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);
}
- 更新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新增接口定义
package com.changgou.order.feign;
import com.changgou.entity.Result;
import com.changgou.order.pojo.Order;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = "order")
public interface OrderFeign {
@PostMapping("/order")
public Result add(@RequestBody Order order);
@GetMapping("/order/{id}")
public Result<Order> 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";
}
2.3.2 支付微服务-下单
(1)创建changgou_service_pay (支付微服务), pom.xml添加依赖
<dependencies>
<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>
</dependencies>
排除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
wxpay:
notify_url: http://weizhaohui.cross.echosite.cn/wxpay/notify #回调地址
(3)创建com.github.wxpay.sdk包,包下创建Config类
package com.github.wxpay.sdk;
import java.io.InputStream;
public class MyConfig extends WXPayConfig {
@Override
String getAppID() {
return "wx8397f8696b538317";
}
@Override
String getMchID() {
return "1473426802";
}
@Override
String getKey() {
return "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb";
}
@Override
InputStream getCertStream() {
return null;
}
@Override
IWXPayDomain getWXPayDomain() {
return new IWXPayDomain() {
@Override
public void report(String s, long l, Exception e) {
}
@Override
public DomainInfo getDomain(WXPayConfig wxPayConfig) {
return new DomainInfo("api.mch.weixin.qq.com",true);
}
};
}
}
(4)创建com.changgou包,包下创建类PayApplication
package com.changgou.pay;
import com.github.wxpay.sdk.MyConfig;
import com.github.wxpay.sdk.WXPay;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableEurekaClient
public class PayApplication {
public static void main(String[] args) {
SpringApplication.run(PayApplication.class,args);
}
@Bean
public WXPay wxPay(){
try {
return new WXPay(new MyConfig());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
@RequestMapping("/wxpay")
@RestController
public class WXPayController {
@Autowired
private WXPayService wxPayService;
//下单
@GetMapping("/nativePay")
public Result nativePay(@RequestParam("orderId") String orderId, @RequestParam("money")Integer money){
Map resultMap = wxPayService.nativePay(orderId, money);
return new Result(true, StatusCode.OK,"",resultMap);
}
}
(5)创建com.changgou.pay.service包,包下创建接口WxPayService
public interface WxPayService {
/**
* 生成微信支付二维码
* @param orderId
* @param money
* @return
*/
Map nativePay(String orderId, Integer money);
}
(6)创建com.changgou.pay.service.impl 包 ,新增服务类WxPayServiceImpl
package com.changgou.pay.service.impl;
import com.changgou.pay.service.WXPayService;
import com.github.wxpay.sdk.WXPay;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.awt.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
@Service
public class WXPayServiceImpl implements WXPayService {
@Autowired
private WXPay wxPay;
@Value("${wxpay.notify_url}")
private String notify_url;
//统一下单接口调用
@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);
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");
map.put("notify_url",notify_url);
map.put("trade_type","NATIVE");
//2.基于wxpay完成统一下单接口的调用,并获取返回结果
Map<String, String> result = wxPay.unifiedOrder(map);
return result;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
}
测试:地址栏输入http://localhost:9010/wxpay/nativePay?orderId=990099&money=1
2.3.3 页面对接支付微服务
(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
package com.changgou.web.order.controller;
import com.changgou.entity.Result;
import com.changgou.order.feign.OrderFeign;
import com.changgou.order.pojo.Order;
import com.changgou.pay.feign.PayFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.jws.WebParam;
import java.util.Map;
@Controller
@RequestMapping("/wxpay")
public class PayController {
@Autowired
private OrderFeign orderFeign;
@Autowired
private PayFeign payFeign;
//跳转到微信支付二维码页面
@GetMapping
public String wxPay(String orderId , Model model){
//1.根据orderid查询订单,如果订单不存在,跳转到错误页面
Result<Order> orderResult = orderFeign.findById(orderId);
if (orderResult.getData() == null){
return "fail";
}
//2.根据订单的支付状态进行判断,如果不是未支付的订单,跳转到错误页面
Order order = orderResult.getData();
if (!"0".equals(order.getPayStatus())){
return "fail";
}
//3.基于payFeign调用统计下单接口,并获取返回结果
Result payResult = payFeign.nativePay(orderId, order.getPayMoney());
if (payResult.getData() == null){
return "fail";
}
//4.封装结果数据
Map payMap = (Map) payResult.getData();
payMap.put("orderId",orderId);
payMap.put("payMoney",order.getPayMoney());
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="successinfo" th:text="|订单提交成功,请您及时付款!订单号:${orderId}|"></span></h4>
<span class="fr"><em class="sui-lead">应付金额:</em><em class="orange money"
th:text="${payMoney}/100"></em>元</span>
设置支付跳转
<li><a th:href="|/api/wxpay?orderId=${orderId}|"><img src="/img/_/pay3.jpg"></a></li>
(4) 更新网关地址过滤器。添加wxpay路径的拦
同时更新网关服务的application.yml。添加地址路由标识