posts - 206,  comments - 26,  views - 17万
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

一、 需求分析


  用户在提交订单后,如果是选择支付方式为微信支付,那应该跳转到微信支付二维码页面(通过微信支付的统一下单接口,去生成商品订单的支付二维码)。用户扫描二维码可以进行支付,金额与订单金额相同。

  支付流程用户购物流程):

  商品详情页(用户点击加入购物车)=> 购物车结算页面(用户点击结算按钮)=>订单提交页(用户点击提交订单)=>选择支付方式页面(显示订单ID和订单总金额,用户点击微信支付按钮)=>微信支付二维码页面(显示订单ID和订单总金额,用户进行扫码支付,并且支付成功后)=>支付成功页面(用户可以查看订单和继续购物)

二、 代码实现思路


  应用技术:分布式架构,Feign远程调用,Oauth,Wxpay ,Vue, Axios,Eureka , Rabbitmq

  前端页面向后端传递订单号,后端根据订单号查询订单,检查是否为当前用户的未支付订单,如果是则根据订单号和金额生成支付url返给前端,前端得到支付url生成支付二维码。

  步骤一: 订单结算页面用户点击提交订单,跳转到选择支付方式页面
  选择支付方式页面需要显示订单ID和支付金额。 基于feign调用订单服务

  步骤二: 支付微服务-下单
  创建支付微服务
  步骤三: 页面对接支付微服务

  三、 代码实现


3.1 提交订单跳转支付页


步骤1)更新shangcheng_web_order的application.yml,添加读取超时设置

 

#请求处理的超时时间
ribbon:
  ReadTimeout: 4000
  #请求连接的超时时间
  ConnectTimeout: 3000

 

 


步骤2)在shangcheng_order_web工程resources/templates下添加 ‘资源/pay.html,fail.html,wxpay.html’。

步骤3)更新shangcheng_service_order中add() ,设置返回值为订单ID

#orderServiceImpl

复制代码
#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)shangcheng_service_order_api的OrderFeign新增接口定义

/***
 * 根据ID查询数据
 * @param id
 * @return
 */
@GetMapping("/order/{id}")
public Result findById(@PathVariable("id") String id);

 


5.2) shangcheng_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";
    }

 


3.2 支付微服务-下单


步骤(1):创建shangcheng_service_pay (支付微服务), pom.xml添加依赖

 

复制代码
 1 <dependency>
 2     <groupId>com.shangcheng</groupId>
 3     <artifactId>shangcheng_common</artifactId>
 4     <version>1.0-SNAPSHOT</version>
 5 </dependency>
 6 <dependency>
 7     <groupId>com.github.wxpay</groupId>
 8     <artifactId>wxpay-sdk</artifactId>
 9     <version>3.0.9</version>
10 </dependency>
11 <dependency>
12     <groupId>org.springframework.boot</groupId>
13     <artifactId>spring-boot-starter</artifactId>
14     <exclusions>
15         <exclusion>
16             <groupId>org.springframework.boot</groupId>
17             <artifactId>spring-boot-starter-logging</artifactId>
18         </exclusion>
19     </exclusions>
20 </dependency>
21 <dependency>
22     <groupId>org.springframework.boot</groupId>
23     <artifactId>spring-boot-starter-amqp</artifactId>
24 </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.shangcheng包,包下创建类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;
        }
    }
​
}
复制代码

 

步骤(5)创建com.shangcheng.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 );
    }
}
复制代码

 

步骤(6)创建com.shangcheng.pay.service包,包下创建接口WxPayService

复制代码
public interface WxPayService {
​
    /**
     * 生成微信支付二维码
     * @param orderId
     * @param money
     * @return
     */
    Map nativePay(String orderId, Integer money);
}
复制代码

 


步骤(7)创建com.shangcheng.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

3.3 页面对接支付微服务


步骤(1)新增shangcheng_service_pay_api模块 ,并添加common工程依赖,新增com.shangcheng.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)shangcheng_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>

 


更新网关地址过滤器。添加wxpay路径的拦截

同时更新网关服务的application.yml。添加地址路由标识

posted on   努力--坚持  阅读(11)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示