当前位置: 首页 > news >正文

【畅购商城】微信支付之支付回调和支付状态

目录

Nuxt.js IP 启动

支付回调

回调接口

后端实现

查看支付状态

后端实现

前端实现

​​​​​​​前置技术:RabbitMQ

​​​​​​​更新订单状态

​​​​​​​Nuxt.js IP 启动

  "config": {"nuxt": {"host": "0.0.0.0","port": "3000"}},

​​​​​​​支付回调

​​​​​​​回调接口

步骤一:修改yml文件,添加notifyUrl配置

步骤二:修改配置文件

步骤三:修改工具类

步骤一:修改yml文件,添加notifyUrl配置

sc:pay:notifyUrl: http://40m459492i.wicp.vip/order-service/pay/callback

步骤二:修改配置文件

private String notifyUrl;           //回调路径

步骤三:修改工具类

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;private PayProperties payProperties;@Beanpublic WXPay wxPay(PayProperties payProperties){if(wxPay == null){this.payProperties = payProperties;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", this.payProperties.getNotifyUrl());// 交易类型为扫码支付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;}}
}

​​​​​​​后端实现

  1. 步骤一:修改PayController,添加callback方法
  2. 步骤二:检查网关,放行callback方法
  3. 步骤三:修改花生壳,访问10010端口

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_7&index=8

步骤一:修改PayController,添加callback方法

@PostMapping("/callback")
public void callback(HttpServletRequest request, HttpServletResponse response) throws IOException {try {//1 获得响应内容String xml = IOUtils.toString(request.getInputStream(), "UTF-8");System.out.println(xml);//解析Map<String, String> map = WXPayUtil.xmlToMap( xml );// 查询成功if("SUCCESS".equals(map.get( "result_code" )  )){// 获得订单号String sn = map.get("out_trade_no");//TODO  更新订单状态System.out.println(sn);//如果成功,给微信支付一个成功的响应response.setContentType("text/xml");String data = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";response.getWriter().write(data);}} catch (Exception e) {e.printStackTrace();response.setContentType("text/xml");String data = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA["+e.getMessage()+"]]></return_msg></xml>";response.getWriter().write(data);}
}

步骤二:检查网关,放行callback方法

步骤三:修改花生壳,访问10010端口

 

查看控制台结果

<xml><appid><![CDATA[wx8397f8696b538317]]></appid>
<bank_type><![CDATA[COMM_CREDIT]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[N]]></is_subscribe>
<mch_id><![CDATA[1473426802]]></mch_id>
<nonce_str><![CDATA[47e529ea929e4c9e847ee9699751a648]]></nonce_str>
<openid><![CDATA[oNpSGwZaaw_0uBEMwFpkwIwFsttw]]></openid>
<out_trade_no><![CDATA[1259484402174529500]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[2D4BC610795C1DC303B0B26092D6C6E3]]></sign>
<time_end><![CDATA[20200510220429]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[NATIVE]]></trade_type>
<transaction_id><![CDATA[4200000568202005108477965385]]></transaction_id>
</xml>
1259484402174529500

​​​​​​​查看支付状态

​​​​​​​后端实现

  1. 步骤一:修改PayService,查询订单支付状态
  2. 步骤二:编写PayService实现类
  3. 步骤三:修改PayController

步骤一:修改PayService,查询订单支付状态

package com.czxy.changgou4.service;import com.czxy.changgou4.utils.PayState;
import com.czxy.changgou4.vo.PayRequest;/*** @author 桐叔* @email liangtong@itcast.cn*/
public interface PayService {/*** 查看支付状态* @param sn* @return*/public PayState query(Long sn);
}

步骤二:编写PayService实现类

@Override
public PayState query(Long sn) {//查询微信支付状态PayState payState = payHelper.queryOrder(sn);return payState;}

步骤三:修改PayController

@GetMapping("/{sn}")
public BaseResult query(@PathVariable("sn") Long sn){//查询PayState payState = payService.query(sn);//返回if(payState.getCode() == 1) {return BaseResult.ok(payState.getDesc());}return BaseResult.error(payState.getDesc());
}

​​​​​​​前端实现

如果订单已经支付,跳转到支付成功页面。

  1. 步骤一:修改api.js,查询订单支付状态
  2. 步骤二:修改flow3,“查询订单状态”绑定事件
  3. 步骤三:修改flow3,编写事件,如果是成功,调到到flow4
  4. 步骤四:编写flow4,与flow3基本内容一致,提示信息为“支付成功,货物即将送出!”

步骤一:修改api.js,查询订单支付状态

  findPayStatus : ( sn ) => {return axios.get("/order-service/pay/"+sn )}

步骤二:修改flow3,“查询订单状态”绑定事件

步骤三:修改flow3,编写事件,如果是成功,调到到flow4

  methods: {async findPayStatusFn() {let { data } = await this.$request.findPayStatus( this.sn );if( data.code == 20000) {location.href = 'flow4'} else {alert( data.message );}}},

步骤四:编写flow4,与flow3基本内容一致,提示信息为“支付成功,货物即将送出!”

<template><div><!-- 顶部导航 start --><div class="topnav"><div class="topnav_bd w990 bc"><div class="topnav_left"></div><div class="topnav_right fr"><ul><li>您好,欢迎来到畅购![<a href="login.html">登录</a>] [<a href="register.html">免费注册</a>] </li><li class="line">|</li><li>我的订单</li><li class="line">|</li><li>客户服务</li></ul></div></div></div><!-- 顶部导航 end --><div style="clear:both;"></div><!-- 页面头部 start --><div class="header w990 bc mt15"><div class="logo w990"><h2 class="fl"><a href="index.html"><img src="images/logo.png" alt="畅购商城"></a></h2><div class="flow fr flow3"><ul><li>1.我的购物车</li><li>2.填写核对订单信息</li><li class="cur">3.成功提交订单</li></ul></div></div></div><!-- 页面头部 end --><div style="clear:both;"></div><!-- 主体部分 start --><div class="success w990 bc mt15"><div class="success_hd"><h2>订单支付成功</h2></div><div class="success_bd"><p><span></span>支付成功,货物即将送出!</p></div></div><!-- 主体部分 end --><div style="clear:both;"></div><!-- 底部版权 start --><Footer></Footer><!-- 底部版权 end --></div>
</template><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><style></style>

​​​​​​​前置技术:RabbitMQ

​​​​​​​更新订单状态

步骤一:配置环境,

rabbitmq中添加order_pay队列

添加依赖

添加yml配置

步骤二:修改回调函数,将sn存放到rabbit中

步骤三:编写监听器(消费者),更新订单状态

步骤四:修改OrderService,完成修改功能

步骤五:修改OrderMapper,完成修改功能

步骤一:配置环境,

rabbitmq中添加order_pay队列,添加rabbit配置类

ackage com.czxy.changgou4.config;import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;/*** @author 桐叔* @email liangtong@itcast.cn*/
@Component
public class OrderPayQueue {private static final String ORDER_PAY_QUEUE = "order_pay";@Beanpublic Queue queue() {return new Queue(ORDER_PAY_QUEUE);}
}

添加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

 ​​​​​​​

添加yml配置

spring:rabbitmq:host: 127.0.0.1username: guestpassword: guest

步骤二:修改回调函数,将sn存放到rabbit中

rabbitTemplate.convertAndSend("", "order_pay", sn); 

步骤三:编写监听器(消费者),更新订单状态

package com.czxy.changgou4.listener;import com.czxy.changgou4.service.OrderService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** @author 桐叔* @email liangtong@itcast.cn*/
@Component
@RabbitListener(queues = "order_pay")
public class OrderPayListener {@Autowiredprivate OrderService orderService;/*** 更新支付状态* @param message*/@RabbitHandlerpublic void updatePayStatus(String message){orderService.updatePayStatus( message , "1" );}
}

步骤四:修改OrderService,完成修改功能

package com.czxy.changgou4.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.czxy.changgou4.pojo.Order;
import com.czxy.changgou4.pojo.User;
import com.czxy.changgou4.vo.CartVo;
import com.czxy.changgou4.vo.OrderVo;import java.util.List;public interface OrderService extends IService<Order> {void updatePayStatus(String sn, String status);
}
package com.czxy.changgou4.service.impl;import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.czxy.changgou4.pojo.Order;
import com.czxy.changgou4.pojo.OrderGoods;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.util.*;@Service
@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {@Overridepublic void updatePayStatus(String sn, String status) {//更新状态baseMapper.updateStatus(sn,status);}
}

步骤五:修改OrderMapper,完成修改功能  

package com.czxy.changgou4.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.czxy.changgou4.pojo.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;@Mapper
public interface OrderMapper extends BaseMapper<Order> {/*** 更加sn修改状态* @param sn* @param status*/@Update("UPDATE tb_order SET STATUS = #{status} WHERE sn = #{sn}")void updateStatus(@Param("sn") String sn, @Param("status") String status);
}

测试:在rabbitMQ web控制台,可以手动发布消息

相关文章:

【畅购商城】微信支付之支付回调和支付状态

目录 Nuxt.js IP 启动 支付回调 回调接口 后端实现 查看支付状态 后端实现 前端实现 ​​​​​​​前置技术&#xff1a;RabbitMQ ​​​​​​​更新订单状态 ​​​​​​​Nuxt.js IP 启动 "config": {"nuxt": {"host": "0.0…...

【Compose multiplatform教程18】多平台资源的设置和配置

要正确配置项目以使用多平台资源&#xff0c;请执行以下操作&#xff1a; 添加库依赖项。 为每种资源创建必要的目录。 为限定资源创建其他目录&#xff08;例如&#xff0c;深色 UI 主题或本地化字符串的不同图像&#xff09;。 依赖项和目录设置 要访问多平台项目中的资源…...

MT6765核心板_MTK6765安卓核心板规格参数_联发科MTK模块开发

MTK6765安卓核心板是基于联发科高效八核处理器平台开发的一款强大硬件解决方案。这款核心板的核心是采用12纳米工艺打造的MTK6765 CPU&#xff0c;具备四个主频高达2.3GHz的CORTEX-A53核心和四个主频为1.8GHz的CORTEX-A53核心&#xff0c;提供了卓越的处理性能。用户可以根据需…...

conda常用维护命令

文章目录 1. 初始化和更新 Conda更新 Conda初始化 Conda&#xff08;如果需要&#xff09; 2. 管理环境创建新环境激活环境停用当前环境列出所有环境删除环境 3. 管理包安装包卸载包更新包更新所有包查找包列出已安装包 4. 导入导出环境导出环境配置从文件创建环境 5. 管理通道…...

Html——10 关键字和描述

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>淘宝网</title><meta name"keywords" content"我要自学网,自学HTML,自学CSS"/><meta name"description" content"要设置…...

Mysql(MGR)和ProxySQL搭建部署-Docker版本

项目路径&#xff1a;D:\study\backend\mysql\mgr 一、Mysql(MGR) 1.1 docker-compose.yaml volumes: # MySQL配置文件目录 - "./mysql-1/conf.d/my.cnf:/etc/mysql/my.cnf" # MySQL工作目录 - "./mysql-1/data:/var/lib/mysql" …...

QML学习(一) Qt Quick和QML介绍以及适用场景说明

一.介绍 1.Qt Quick 介绍 Qt Quick 提供了一套高动态&#xff0c;丰富的 QML 元素来定制用户界面的说明性框架。Qt Quick 有助于程序开发员与界面设计员的合作为便携式设备建立流畅的用户界面&#xff0c;例如&#xff1a;移动电话、媒体播放器&#xff0c;机顶盒以及上网本等…...

深入理解 PyTorch 的 view() 函数:以多头注意力机制(Multi-Head Attention)为例 (中英双语)

深入理解 PyTorch 的 view() 函数&#xff1a;以多头注意力机制&#xff08;Multi-Head Attention&#xff09;为例 在深度学习模型的实现中&#xff0c;view() 是 PyTorch 中一个非常常用的张量操作函数&#xff0c;它能够改变张量的形状&#xff08;shape&#xff09;而不改…...

使用PHP函数 “setcookie“ 设置cookie

在网站开发中&#xff0c;cookie是一种非常常用的技术&#xff0c;它用于在用户的浏览器中存储少量的数据&#xff0c;以便在不同页面之间传递信息。PHP提供了一个名为 "setcookie" 的函数&#xff0c;用于设置cookie的值和属性。在本文中&#xff0c;我们将学习如何…...

redis优化

在高并发、高性能、高可用系统中&#xff0c;Redis 的优化至关重要。以下是一些在面试中可以详细说明的 Redis 优化策略&#xff0c;以及具体的实践经验和技术亮点&#xff1a; 1. 数据模型与结构设计优化 使用合适的数据结构 &#xff1a;根据业务需求选择合适的 Redis 数据结…...

数据分析的革命——解读云数据库 SelectDB 版的力量

在当今数据驱动的时代&#xff0c;实时数据分析已成为企业决策中的关键一环。如何在海量数据中快速找到核心价值&#xff0c;如何让决策者在毫秒间洞悉变化&#xff0c;这不仅考验着企业的技术能力&#xff0c;也对基础设施提出了新的要求。云数据库 SelectDB 版&#xff0c;正…...

Ngnix介绍、安装、实战及用法!!!

一、Nginx简介 1、Nginx概述 Nginx (“engine x”) 是一个高性能的 HTTP 和 反向代理服务器&#xff0c;特点是占有内存少&#xff0c;并发能力强&#xff0c;能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数 。 2、正向代理 正向代理&#xff1a;如果把局…...

算法基础一:冒泡排序

一、冒泡排序 1、定义 冒泡排序&#xff08;英语&#xff1a;Bubble Sort&#xff09;是一种简单的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序&#xff08;如从大到小、首字母从A到Z&#xff09;错误就把他们交换过来。 …...

云开发实战教程:手把手教你高效开发应用

声明&#xff1a;本文仅供实践教学使用&#xff0c;没有任何打广告成分 目录 1.引言 2.云开发 Copilot介绍 云开发 Copilot 的功能与特点 3.环境准备 步骤一登录账号 步骤二新建环境 4.开发实践 4.1AI 生成低代码应用 4.2AI 生成低代码页面/区块 4.3AI 优化低代码组件…...

Git基本操作快速入门(30min)

Git基本操作快速入门&#xff08;30min&#xff09; 文章目录 Git基本操作快速入门&#xff08;30min&#xff09;1. 建立本地仓库2. 本地仓库链接到远端仓库3. 将本地仓库推送到远端4. Git常用命令 作为一名程序员&#xff0c;使用Github来进行代码的版本管理是必修课&#xf…...

VS Code AI开发之Copilot配置和使用详解

随着AI开发工具的迅速发展&#xff0c;GitHub Copilot在Cursor、Winsuf、V0等一众工具的冲击下&#xff0c;推出了免费版本。接下来&#xff0c;我将为大家介绍GitHub Copilot的配置和使用方法。GitHub Copilot基于OpenAI Codex模型&#xff0c;旨在为软件开发者提供智能化的代…...

QT中使用OpenGL function

1.前言 QT做界面编程很方便&#xff0c;QTOpenGL的使用也很方便&#xff0c;因为QT对原生的OpenGL API进行了面向对象化的封装。 如&#xff1a; 函数&#xff1a;initializeOpenGLFunctions()...... 类&#xff1a;QOpenGLVertexArrayObject、QOpenGLBuffer、QOpenGLShader…...

STM32-笔记16-定时器中断点灯

一、实验目的 使用定时器 2 进行中断点灯&#xff0c;500ms LED 灯翻转一次。 二&#xff0c;定时器溢出时间计算 Tout&#xff1a;定时器溢出时间 Ft&#xff1a;定时器的时钟源频率 ARR&#xff1a;自动重装载寄存器的值&#xff08;可设置ARR从0开始&#xff0c;但是计数到…...

Live555、FFmpeg、GStreamer介绍

Live555、FFmpeg 和 GStreamer 都是处理流媒体和视频数据的强大开源框架和工具&#xff0c;它们广泛应用于实时视频流的推送、接收、处理和播放。每个框架有不同的设计理念、功能特性以及适用场景。下面将详细分析这三个框架的作用、解决的问题、适用场景、优缺点&#xff0c;并…...

oracle基础:理解 Oracle SQL 中的 WHERE 后的 (+) 用法

在使用 Oracle 数据库进行 SQL 查询时&#xff0c;可能会遇到 WHERE 子句后带有 () 的语法。这是 Oracle 专有的外连接&#xff08;Outer Join&#xff09;表示法。虽然现代 SQL 标准推荐使用 LEFT JOIN 和 RIGHT JOIN 语法&#xff0c;但在某些遗留系统中&#xff0c;这种写法…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...