TMDOG的Gin学习笔记_02——Gin集成支付宝支付沙箱环境

TMDOG的Gin学习笔记_02——Gin集成支付宝支付沙箱环境

博客地址:TMDOG的博客

作者自述:
最近忙着整理自己的项目代码,终于有时间更新一下博客。这次的内容是关于如何在Gin框架下集成支付宝的支付沙箱环境,具体包括如何初始化支付宝的SDK、生成支付链接和处理回调请求。不同于NestJS笔记,Gin学习笔记更专注于业务逻辑,而支付宝支付集成是大多数电商项目中不可缺少的部分,所以这一篇笔记对我来说也非常重要。

学习目标

学习如何将支付宝支付集成到Gin框架下,实现在沙箱环境中进行支付流程的模拟。

预期使用的技术栈:
Gin、支付宝SDK、Go

支付宝支付沙箱环境配置

1. 创建支付宝开放平台应用

首先,你需要在支付宝开放平台上创建一个应用:

  • 访问支付宝开放平台。
    请添加图片描述

  • 使用支付宝扫码登陆并进入控制台。

  • 向下划,在页面下面进入沙箱环境。

请添加图片描述
请添加图片描述

  • 接口加签方式中选择系统默认的证书模式,启用并查看
    请添加图片描述

  • 然后下载所有证书并,复制好应用私钥
    请添加图片描述

  • 接口内容加密方式中获取密钥并保存
    请添加图片描述

请添加图片描述

2. 安装支付宝SDK

支付宝官方提供了Go语言SDK,使用以下命令进行安装:

go get github.com/smartwalle/alipay/v3

3. 完整代码示例

我们将下载的证书放在项目目录下
请添加图片描述

package main

import (
	"context"
	"fmt"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/smartwalle/alipay/v3"
	"github.com/smartwalle/xid"
	"log"
	"net/http"
	"time"
)

var client *alipay.Client

const (
	kAppId        = "APPID"
	kPrivateKey   = "刚才保存的私钥"
	kServerPort   = "9989"                      //端口
	kServerDomain = "http://localhost:9989"//回调地址
	kSecretKey = "接口内容加密密钥"// 内容加密密钥
)

func main() {
	var err error
	
	// 初始化支付宝
	if client, err = alipay.New(kAppId, kPrivateKey, false); err != nil {
		log.Println("初始化支付宝失败", err)
		return
	}

	// 加载证书
	if err = client.LoadAppCertPublicKeyFromFile("appPublicCert.crt"); err != nil {
		log.Println("加载证书发生错误", err)
		return
	}
	if err = client.LoadAliPayRootCertFromFile("alipayRootCert.crt"); err != nil {
		log.Println("加载证书发生错误", err)
		return
	}
	if err = client.LoadAlipayCertPublicKeyFromFile("alipayPublicCert.crt"); err != nil {
		log.Println("加载证书发生错误", err)
		return
	}

	if err = client.SetEncryptKey(kSecretKey); err != nil {
		log.Println("加载内容加密密钥发生错误", err)
		return
	}

	// 配置 CORS 中间件
	corsConfig := cors.DefaultConfig()
	corsConfig.AllowAllOrigins = true                                   // 允许所有域名
	corsConfig.AllowMethods = []string{"GET", "POST", "OPTIONS"}        // 允许的 HTTP 方法
	corsConfig.AllowHeaders = []string{"Content-Type", "Authorization"} // 允许的请求头

	// 使用 gin 框架设置路由
	r := gin.Default()

	// 因为需要支付宝返回回调请求,是跨域的,所以需要处理跨域请求
	// 将 CORS 中间件应用到所有路由
	r.Use(cors.New(corsConfig))

	// 配置路由
	r.GET("/alipay/pay", pay)
	r.GET("/alipay/callback", callback)
	r.POST("/alipay/notify", notify)

	// 启动 HTTP 服务
	r.Run(":" + kServerPort)
}

func pay(c *gin.Context) {
	var tradeNo = fmt.Sprintf("%d", xid.Next())

	// 构造支付请求
	var p = alipay.TradePagePay{}
	p.NotifyURL = kServerDomain + "/alipay/notify"
	p.ReturnURL = kServerDomain + "/alipay/callback"
	p.Subject = "支付测试:" + tradeNo
	p.OutTradeNo = tradeNo
	p.TotalAmount = "100.00"
	p.ProductCode = "FAST_INSTANT_TRADE_PAY"

	// 打印支付请求数据
	log.Printf("支付请求数据: %+v", p)

	// 发起支付请求
	url, _ := client.TradePagePay(p)

	// 打印生成的支付链接
	log.Printf("支付链接: %s", url.String())

	// 重定向到支付链接
	c.Redirect(http.StatusTemporaryRedirect, url.String())
}

func callback(c *gin.Context) {
	// 解析请求参数
	if err := c.Request.ParseForm(); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "解析表单数据失败",
		})
		return
	}

	// 打印回调的请求数据
	log.Printf("回调请求数据: %+v", c.Request.Form)

	// 获取支付宝回调数据中的签名字段
	sign := c.DefaultQuery("sign", "")
	if sign == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "签名参数缺失",
		})
		return
	}

	// 验证签名
	if err := client.VerifySign(c.Request.Form); err != nil {
		log.Println("回调签名验证失败", err)
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "签名验证失败",
		})
		return
	}

	log.Println("回调签名验证通过")

	// 获取回调中的订单信息
	outTradeNo := c.DefaultQuery("out_trade_no", "")
	totalAmount := c.DefaultQuery("total_amount", "")
	//tradeNo := c.DefaultPostForm("trade_no", "")

	// 验证支付金额
	if totalAmount != "100.00" { // 这里你可以根据自己的业务逻辑进行金额校验
		log.Printf("支付金额不匹配,expected: 100.00, received: %s", totalAmount)
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "支付金额不匹配",
		})
		return
	}

	// 查询订单状态
	var p = alipay.TradeQuery{}
	p.OutTradeNo = outTradeNo

	// 调用支付宝查询接口
	rsp, err := client.TradeQuery(context.Background(), p)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("查询订单 %s 时发生错误: %s", outTradeNo, err.Error()),
		})
		return
	}

	// 打印查询结果
	log.Printf("支付宝查询响应: %+v", rsp)

	// 检查支付状态
	if rsp.IsFailure() {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("支付查询失败: %s-%s", rsp.Msg, rsp.SubMsg),
		})
		return
	}

	// 如果支付成功,处理业务逻辑,如更新数据库、通知用户等
	if rsp.TradeStatus == "TRADE_SUCCESS" {
		log.Printf("订单 %s 支付成功", outTradeNo)
		// 这里可以写入支付成功后的业务逻辑,如更新订单状态、发货等
	} else {
		log.Printf("订单 %s 支付失败", outTradeNo)
		// 如果支付失败,可以进行相应的处理,如通知管理员等
	}

	// 返回成功响应
	c.JSON(http.StatusOK, gin.H{
		"message": fmt.Sprintf("订单 %s 支付成功", outTradeNo),
	})
}

func notify(c *gin.Context) {
	// 解析表单数据
	if err := c.Request.ParseForm(); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "解析表单数据失败",
		})
		return
	}

	// 打印接收到的异步通知数据
	log.Printf("异步通知请求数据: %+v", c.Request.Form)

	// 解析异步通知
	notification, err := client.DecodeNotification(c.Request.Form)
	if err != nil {
		log.Println("解析异步通知发生错误", err)
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "解析异步通知发生错误",
		})
		return
	}

	// 打印解析后的异步通知数据
	log.Printf("解析后的异步通知数据: %+v", notification)

	// 使用自定义请求进行查询
	var p = alipay.NewPayload("alipay.trade.query")
	p.AddBizField("out_trade_no", notification.OutTradeNo)

	// 查询订单信息
	var rsp *alipay.TradeQueryRsp
	if err = client.Request(context.Background(), p, &rsp); err != nil {
		log.Printf("异步通知验证订单 %s 信息发生错误: %s \n", notification.OutTradeNo, err.Error())
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("验证订单 %s 信息发生错误: %s", notification.OutTradeNo, err.Error()),
		})
		return
	}

	// 打印支付宝的查询响应数据
	log.Printf("支付宝查询响应: %+v", rsp)

	if rsp.IsFailure() {
		log.Printf("异步通知验证订单 %s 信息发生错误: %s-%s \n", notification.OutTradeNo, rsp.Msg, rsp.SubMsg)
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("异步通知验证订单 %s 信息发生错误: %s-%s", notification.OutTradeNo, rsp.Msg, rsp.SubMsg),
		})
		return
	}

	log.Printf("订单 %s 支付成功 \n", notification.OutTradeNo)

	// 确认通知成功
	client.ACKNotification(c.Writer)
}

涉及了三个主要的请求方法,分别是:

1. pay 请求方法
  • 作用: 这个方法是处理用户发起支付请求的地方。当用户请求 GET /alipay/pay 时,系统会生成一个支付链接,并将用户重定向到支付宝的支付页面。

  • 具体步骤:

    1. 创建一个唯一的订单号(tradeNo),这里通过 xid 包生成一个。
    2. 使用 alipay.TradePagePay 构建支付请求对象,设置支付相关的信息,如:通知地址(NotifyURL)、回调地址(ReturnURL)、商品描述(Subject)、订单号(OutTradeNo)和支付金额(TotalAmount)。
    3. 调用 client.TradePagePay(p) 向支付宝请求生成支付页面链接。
    4. 将生成的支付链接作为响应返回,并通过重定向将用户引导到支付宝的支付页面。

    该方法主要用于支付页面的生成和跳转,用户通过此链接进行支付操作。

2. callback 请求方法
  • 作用: 这个方法用于处理支付宝支付完成后的同步回调请求。当用户完成支付,支付宝会根据配置的 ReturnURL 返回到这个接口,并携带支付结果。

  • 具体步骤:

    1. 从回调请求中解析支付宝返回的数据。
    2. 获取回调中的签名参数,进行签名验证,确保回调数据未被篡改。
    3. 验证支付金额是否与预期一致。
    4. 使用支付宝的查询接口(TradeQuery)查询支付订单状态。
    5. 如果支付成功,则执行相应的业务逻辑(如更新订单状态、发货等)。
    6. 最终返回处理结果,如支付成功或失败的消息。

    这个方法的目的是处理支付完成后的验证和后续操作,确保支付数据的安全性与一致性。

3. notify 请求方法
  • 作用: 这个方法是处理支付宝支付后的异步通知请求。当用户支付完成后,支付宝会向 NotifyURL 发送异步通知,通知支付结果。支付宝会通过 POST 请求将支付结果发送到该接口。

  • 具体步骤:

    1. 解析支付宝发送的异步通知数据。
    2. 解码通知数据,得到支付结果。
    3. 查询支付订单的最新状态,验证订单是否支付成功。
    4. 确认支付成功后,可以进行进一步的处理,比如更新订单状态或进行其他业务逻辑。
    5. 最后返回一个确认响应(client.ACKNotification),告诉支付宝已经收到并处理完通知。

    这个方法用于处理支付完成后的异步通知,它可以确保系统及时接收到支付宝的支付通知并执行相应的后续处理。

这三个请求方法分别用于:

  • pay:生成支付链接并跳转到支付宝支付页面。
  • callback:同步回调,处理支付完成后的回调请求。
  • notify:异步通知,处理支付宝发送的支付成功通知。

4. 测试

直接在浏览器中测试,我们输入http://localhost:9989/alipay/pay,将会重定向到支付宝支付页面

请添加图片描述

在沙箱控制台右边栏当中点击沙箱账号可以填入买家邮箱和支付密码模拟支付
请添加图片描述

也可以下载手机支付宝沙箱版,用沙箱账号登录后扫码支付

我是使用手机扫码
请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述

我们发现经过两次重定向后最后进入http://localhost:9989/alipay/callback显示支付成功

第一次重定向后支付宝服务方会异步发送alipay/notify到自己的服务器

第二次重定向会直接同步发送回调请求alipay/callback显示在用户界面通知支付成功

5. 查看gin控制台

2024/11/08 19:33:33 
支付请求数据: 
{Trade:{AuxParam:{} NotifyURL:http://localhost:9989/alipay/notify ReturnURL:http://localhost:9989/alipay/callback AppAuthToken: Subject:支付测试:3717435097532596224 Ou
tTradeNo:3717435097532596224 TotalAmount:100.00 ProductCode:FAST_INSTANT_TRADE_PAY Body: GoodsDetail:[] BusinessParams:[] DisablePayChannels: EnablePayChannels: SpecifiedChannel: ExtendParams:<nil> Agr
eementSignParams:<nil> GoodsType: InvoiceInfo: PassbackParams: PromoParams: RoyaltyInfo: SellerId: SettleInfo: StoreId: SubMerchant: TimeoutExpress: TimeExpire: MerchantOrderNo: ExtUserInfo:<nil> QueryOptions:[]} AuthToken: QRPayMode: QRCodeWidth:}
2024/11/08 19:33:33 

支付链接: https://openapi-sandbox.dl.alipaydev.com/gateway.do?alipay_root_cert_sn=687b59193f3f462dd5336e5abf83c5d8_02941eef3187dddf3d3b83462e1dfcf6&app_cert_sn=17811ce5cb5cf99a255aa
c61c6a11ae8&app_id=9021000141668546&biz_content=pYwkNjCG66efEQCRHGGZCO%2B46LHmZe15cel6apDQiiKhmB%2Bt%2B79id%2Fli5No%2B4PC%2F0CckV20dSx%2Fr0mL5JDwysgCtvijdgWWyiPffxrfv0iLsSXMqC7VAOY0Mr9cA32uL01mEH39nE9I
zTrcCjdJ9x1GN2tXhU57IFCy%2FbnSd3OfJcrLqJyKxxFlTtrjpdCCL1SBM1VxSo%2B9C8zL%2FlzfKDw%3D%3D&charset=utf-8&encrypt_type=AES&format=JSON&method=alipay.trade.page.pay&notify_url=http%3A%2F%2Flocalhost%3A9989%
2Falipay%2Fnotify&return_url=http%3A%2F%2Flocalhost%3A9989%2Falipay%2Fcallback&sign=buxn%2Fiwm3kBnCJbpIDi8Bz%2BYyJ1PFpYUR%2B%2Frh54aSzyDlyuMKlVHNO0AbSeAP5eyXXIK%2FbKJ8MMSETkfWEpDO%2Fuk4O4yzlBn0VMyZnoIT
vRDIvUJYuCpKXgBXplfuVI6YEzA6S2S0l6%2BQuzIRpqHlK0VJoDahiWisr95YOxb8ld8oH37UO%2F%2BvbrHMYWT7BLTWz%2FVqh0ELMKX%2BhsAeGBM1HlNAe1gpk3CB4%2FTIH%2BGUbicv9TcTOV2nLLKCLkqmnqOlmhK%2FB%2BnbP52j7%2FbuGaV5hx%2FSnKeARdMZJW1tr3A7cWKyBpGOGf%2BylvBGvySg046aeRDo5l6OEnX3J10zdflUg%3D%3D&sign_type=RSA2&timestamp=2024-11-08+19%3A33%3A33&version=1.0

[GIN] 2024/11/08 - 19:33:33 | 307 |     31.9174ms |             ::1 | GET      "/alipay/pay"

2024/11/08 19:34:09 
回调请求数据: 
map[app_id:[9021000141668546] auth_app_id:[9021000141668546] charset:[utf-8] method:[alipay.trade.page.pay.return] out_trade_no:[3717435097532596224] seller_id:[208872
1048676520] sign:[R2vAtE5H22B5Z+rVvlvQBiokQWl84bH2E9peZDON1LEg82SXVS4F1FWIPDtifhI+CvUQ0Kj+oLHDuaoWMeAZhjRpwWQ+Q1htfDuFLcHPYN9ZSFWglw0dCmZ8cjPBy5Y0A5NcH2qAJQcCpKqtr6t9nFsk/U4PT4WW0i614AoLod7J94bqJwm0IhC
pGxGCFyhlL8MnNXDRAg28Ne139n4O7GDNiw6PQtcmybGCmNW8YxEh1oP+tDj6+cATbxlwzeCmB4veowSS66JuAec3GqxLMFyXGOuLKUtrHAo6Uhth9pRKtVHVK8E5JLi97sB6N+hSX4h1qOBjybuvbRXao/RqjQ==] sign_type:[RSA2] timestamp:[2024-11-08 19:34:06] total_amount:[100.00] trade_no:[2024110822001476540504411933] version:[1.0]]

2024/11/08 19:34:09 
回调签名验证通过
HYBAmount: BKAgentRespInfo:<nil> ChargeInfoList:[] DiscountGoodsDetail: VoucherDetailList:[]} rminalId: FundBillList:[] StoreName: BuyerUserId:2088722048676545 B
2024/11/08 19:34:10 订单 3717435097532596224 支付成功

[GIN] 2024/11/08 - 19:34:10 | 200 |    805.5153ms |             ::1 | GET      "/alipay/callback?charset=utf-8&out_trade_no=3717435097532596224&method=alipay.trade.page.pay.return&total_amount=100.00&sign=R2vAtE5H22B5Z%2BrVvlvQBiokQWl84bH2E9peZDON1LEg82SXVS4F1FWIPDtifhI%2BCvUQ0Kj%2BoLHDuaoWMeAZhjRpwWQ%2BQ1htfDuFLcHPYN9ZSFWglw0dCmZ8cjPBy5Y0A5NcH2qAJQcCpKqtr6t9nFsk%2FU4PT4WW0i614AoLod7J94bqJwm0IhCpGxGCFyhlL8MnNXDRAg28Ne139n4O7GDNiw6PQtcmybGCmNW8YxEh1oP%2BtDj6%2BcATbxlwzeCmB4veowSS66JuAec3GqxLMFyXGOuLKUtrHAo6Uhth9pRKtVHVK8E5JLi97sB6N%2BhSX4h1qOBjybuvbRXao%2FRqjQ%3D%3D&trade_no=2024110822001476540504411933&auth_app_id=9021000141668546&version=1.0&app_id=9021000141668546&sign_type=RSA2&seller_id=2088721048676520&timestamp=2024-11-08+19%3A34%3A06" 19%3A34%3A06"

我们可以看到所有的参数、以及请求

但是,我们发现并没有接收到notify请求、因为我们没有在控制台设置回调地址,并且也是处于本地网络环境,设置了也接收不到。
要想正确收取notify请求就需要在公网环境中部署。

支付宝的沙箱环境支持模拟支付过程,因此可以避免涉及真实交易的风险。你可以在支付宝开放平台的沙箱环境中获取测试用的账户和支付信息。测试时,使用支付宝提供的沙箱账号来模拟支付。

总结

通过本篇学习笔记,我们成功地将支付宝支付集成到了Gin框架中,并在沙箱环境中模拟了支付流程。我们介绍了如何使用支付宝SDK创建支付订单,如何配置回调处理支付结果。集成支付宝支付是电商系统中重要的一部分,本篇笔记为后续功能扩展和真实支付接入打下了基础。接下来,我将继续深入研究其他支付方式的集成与优化,敬请期待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/911620.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

cmake could not find a package configuration file provided by “Microsoft.GSL“

通过查找 dir C:\vcpkg\installed\x64-windows /s /b | findstr Microsoft.GSL vspkg安装 git clone https://github.com/microsoft/vcpkg.git cd vcpkg .\bootstrap-vcpkg.bat .\vcpkg --version

cocos creator 3.8.3物理组件分组的坑

坑&#xff0c;坑的不行的大坑 group用的二进制的左移获取十进制的数值 目前是这样判断的&#xff0c;也不知道对不对&#xff0c;什么get、set Group没找到

【AI写作宝-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

计算机毕业设计Python流量检测可视化 DDos攻击流量检测与可视化分析 SDN web渗透测试系统 网络安全 信息安全 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

2024.11最新Hexo+GitHub搭建个人博客

2024.11最新HexoGitHub搭建个人博客 一、Hexo介绍 Hexo 是一个快速、简洁且高效的博客框架&#xff0c;有丰富的主题和插件可供使用。 Hexo 使用 Markdown&#xff08;或其他标记语言&#xff09;解析文章&#xff0c;在几秒内&#xff0c;即可利用靓丽的主题生成静态网页。这…

王道考研之数据结构

数据结构系列 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 数据结构 数据结构系列1.线性表1.1 线性表的定义和相关概念1.2 线性表的创销 增删查改 判空表长打印 2.顺序表2.1 顺序表定义和相关概念2.2 顺序表的静态实现2.3 顺序表的…

java导出word文件(手绘)

文章目录 代码细节效果图参考资料 代码细节 使用的hutool的WordUtil&#xff0c;WordUtil对poi进行封装&#xff0c;但是这一块的官方封装的很少&#xff0c;很多细节都没有。代码中是常见的绘制段落&#xff0c;标题、表格等常用api Word07Writer writer WordUtil.getWriter(…

LeetCode 0685.冗余连接 II:并查集(和I有何不同分析)——详细题解(附图)

【LetMeFly】685.冗余连接 II&#xff1a;并查集&#xff08;和I有何不同分析&#xff09;——详细题解(附图) 力扣题目链接&#xff1a;https://leetcode.cn/problems/redundant-connection-ii/ 在本问题中&#xff0c;有根树指满足以下条件的 有向 图。该树只有一个根节点&…

git原理与上传

言&#xff1a; git是一个软件&#xff0c;gitee/github是一个网站&#xff0c;这里有什么联系吗&#xff1f;我们身为一个程序员不可能不知道github&#xff0c;但是毕竟这是外国的网站&#xff0c;我们不翻墙的情况下&#xff0c;是无法访问的(或者就是太慢了&#xff0c;或…

Go语言的常用内置函数

文章目录 一、Strings包字符串处理包定义Strings包的基本用法Strconv包中常用函数 二、Time包三、Math包math包概述使用math包 四、随机数包&#xff08;rand&#xff09; 一、Strings包 字符串处理包定义 Strings包简介&#xff1a; 一般编程语言包含的字符串处理库功能区别…

React 入门课程 - 使用CDN编程React

1. 第一个React 注意&#xff1a;在vscode里&#xff0c;使用Live Server来运行html文件。 index.html <html><head><link rel"stylesheet" href"index.css"><script crossorigin src"https://unpkg.com/react17/umd/react.de…

苍穹外卖day09超出配送范围前端不提示问题

同学们在写苍穹外卖项目day09时调用了百度地图api来判断用户地址是否超出配送范围&#xff0c; 但是在黑马官方的课程或资料中&#xff0c;出现这样的问题时只会向用户端的控制台报错并不会提醒用户 如下图&#xff1a; 解决方法&#xff1a; 其实解决方法很简单只需要找到向…

ARXML汽车可扩展标记性语言规范讲解

ARXML: Automotive Extensible Markup Language &#xff08;汽车可扩展标记语言&#xff09; xmlns: Xml name space &#xff08;xml 命名空间&#xff09; xsd: Xml Schema Definition (xml 架构定义) 1、XML与HTML的区别&#xff0c;可扩展。 可扩展&#xff0c;主要是…

【开源项目】经典开源项目数字孪生智慧小镇——开源工程及源码

飞渡科技数字孪生小镇管理平台&#xff0c;依托自研数字孪生引擎平台&#xff0c;将5G、物联网、大数据、人工智能等数字化技术融合应用&#xff0c;采集、整合、应用小镇的规划、运营、管理等数据&#xff0c;实现特色小镇全域管理系统化以及精细化。 基于地理信息系统&#x…

探索 Move 编程语言:智能合约开发的新纪元

目录 引言 一、变量的定义 二、整型 如何在Move中表示小数和负数&#xff1f; 三、运算符 as运算符 布尔型 地址类型 四、什么是包&#xff1f; 五、什么是模块&#xff1f; 六、如何定义方法&#xff1f; 方法访问权限控制 init方法 总结 引言 Move 是一种专为区…

智能提醒助理系列-jdk8升级到21,springboot2.3升级到3.3

本系列文章记录“智能提醒助理”产品建设历程&#xff0c;记录实践经验、巩固知识点、锻炼总结能力。 本篇介绍技术栈升级的过程&#xff0c;遇到的问题和解决方案。 一、需求出发点 智能提醒小程序 当前使用的是jdk8&#xff0c;springboot2.3,升级到jdk21和springboot3.3 学…

算法|牛客网华为机试31-40C++

牛客网华为机试 上篇&#xff1a;算法|牛客网华为机试21-30C 文章目录 HJ31 单词倒排HJ32 密码截取HJ33 整数与IP地址间的转换HJ34 图片整理HJ35 蛇形矩阵HJ36 字符串加密HJ37 统计每个月兔子的总数HJ38 求小球落地5次后所经历的路程和第5次反弹的高度HJ39 判断两个IP是否属于同…

第六十三周周报 GCN-CNNGA

文章目录 week 63 GCN-CNNGA摘要Abstract1. 题目2. Abstract3. 文献解读3.1 Introduction3.2 创新点 4. 网络结构4.1 数据分析4.2 混合深度学习框架的发展4.3 Mul4.4 CNN block4.5 GCN block4.6 GRU block4.7 注意力机制4.8 模型评估标准 5. 实验结果5.1 不同邻接矩阵的性能评价…

人工智能——小白学习指南

知孤云出岫 目录 1. **智能评测系统**2. **个性化学习路径推荐**3. **虚拟学习助手**4. **学习行为分析**5. **数据驱动的教学决策**6. **自动化课程推荐**7. **数据隐私与安全保护** 人工智能知识点的总结和学习路线&#xff0c;以数据表格形式呈现&#xff0c;并附带在教育行…

「Mac畅玩鸿蒙与硬件21」鸿蒙UI组件篇11 - Canvas 组件的静态进阶应用

在鸿蒙应用开发中&#xff0c;Canvas 组件不仅用于基础绘图&#xff0c;还提供了处理复杂路径和渐变效果的多种手段&#xff0c;帮助开发者实现精美的静态图形。本篇将介绍如何在 Canvas 中绘制复杂路径、创建渐变填充效果。 关键词 Canvas 组件复杂路径绘制渐变填充 一、Canv…