支付宝沙箱版模拟网站在线完整支付流程(无营业无费用)内网穿透+局域网测试

文章目录

  • 一、介绍
      • 1. 支付
      • 2. 支付结果
  • 二、前提准备
      • 1. 支付宝开放平台
      • 2. 内网穿透
      • 3. 局域网
  • 三、order微服务
      • 1. 依赖、配置
      • 2. 工具类
          • 1. 二维码生成
          • 2. AlipayConfig
      • 3. 端点代码
          • 1. /generatepaycode
          • 2. /requestpay
          • 3. /payresult
          • 4. /receivenotify

环境如下

Version
手机安卓
支付平台支付宝
SpringBoot3.2.1
alipay-sdk-java4.38.200.ALL

一、介绍

系统处于开发阶段时,无需营业执照,无需任何费用,沙箱模拟网站在线完整支付流程。

参考资料如下:

  • 手机网站支付快速接入
  • alipay.trade.query(统一收单交易查询)
  • 异步通知说明

1. 支付

有一个在线网站,可以为商品生成支付二维码,手机支付宝扫码,支付。

支付流程大体如下:
在这里插入图片描述

2. 支付结果

获取支付结果有两种方法

  • 一种为主动查询。在顾客支付后再查询方可得到正确的结果,然而这个时机是无法确定的。
  • 一种为被动接收。顾客支付后,支付宝服务器向微服务发送消息通知。

在这里插入图片描述
在这里插入图片描述

二、前提准备

1. 支付宝开放平台

  1. 注册支付宝开放平台
    https://openhome.alipay.com/

  2. 来到控制台下滑找到沙箱
    https://openhome.alipay.com/develop/manage
    或者点这里进入沙箱环境
    https://openhome.alipay.com/develop/sandbox/app
    在这里插入图片描述

  3. 下载支付宝沙箱版到手机
    在这里插入图片描述

2. 内网穿透

  1. 下载软件
    https://hsk.oray.com/download
    本文选择的是贝锐花生壳,会赠送一个域名。

  2. 添加映射

    • 映射类型:HTTPS
    • 外网端口:貌似改不了
    • 内网ip:port:order微服务的地址端口。

在这里插入图片描述
这样之后,谁往https://5m34y83626.vicp.fun/orders/receivenotify发送请求,就相当于往order微服务的/orders/receivenotify这个端点发送请求。

3. 局域网

参考这篇文章
同一Wifi下允许手机访问电脑(win10)

主要目的就是要知道,手机通过什么ip可以访问到电脑。本文是192.168.0.102,所以访问192.168.0.102:63030就相当于访问到了order微服务

三、order微服务

1. 依赖、配置

		<!-- 支付宝SDK --><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.38.200.ALL</version></dependency><!--生成二维码--><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.3</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.3.3</version></dependency>
server:servlet:context-path: /ordersport: 63030pay:#扫描二维码得到urlqrcodeurl: http://???:63030/orders/requestpay?payNo=%salipay:APP_ID: ???APP_PRIVATE_KEY: ???ALIPAY_PUBLIC_KEY: ???

???填充分别为

  1. 在同一局域网中手机访问电脑的ip

  2. 沙箱环境->沙箱应用->应用信息->基本信息
    在这里插入图片描述

  3. 沙箱环境->沙箱应用->应用信息->开发信息->应用私钥

  4. 沙箱环境->沙箱应用->应用信息->开发信息->支付宝公钥
    在这里插入图片描述

2. 工具类

1. 二维码生成
package com.xuecheng.orders.config;import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.xuecheng.base.utils.EncryptUtil;
import jakarta.servlet.ServletOutputStream;
import org.apache.commons.lang3.StringUtils;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;/*** @author mumu* @version 1.0* @description 二维码生成工具* @date 2024/02/16 14:56*/
public class QRCodeUtil {/*** 生成二维码** @param content 二维码对应的URL* @param width   二维码图片宽度* @param height  二维码图片高度* @return*/public String createQRCode(String content, int width, int height) throws IOException {String resultImage = "";//除了尺寸,传入内容不能为空if (!StringUtils.isEmpty(content)) {ServletOutputStream stream = null;ByteArrayOutputStream os = new ByteArrayOutputStream();//二维码参数@SuppressWarnings("rawtypes")HashMap<EncodeHintType, Comparable> hints = new HashMap<>();//指定字符编码为“utf-8”hints.put(EncodeHintType.CHARACTER_SET, "utf-8");//L M Q H四个纠错等级从低到高,指定二维码的纠错等级为M//纠错级别越高,可以修正的错误就越多,需要的纠错码的数量也变多,相应的二维吗可储存的数据就会减少hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);//设置图片的边距hints.put(EncodeHintType.MARGIN, 1);try {//zxing生成二维码核心类QRCodeWriter writer = new QRCodeWriter();//把输入文本按照指定规则转成二维吗BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);//生成二维码图片流BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);//输出流ImageIO.write(bufferedImage, "png", os);/*** 原生转码前面没有 data:image/png;base64 这些字段,返回给前端是无法被解析,所以加上前缀*/resultImage = "data:image/png;base64," + EncryptUtil.encodeBase64(os.toByteArray());return resultImage;} catch (Exception e) {e.printStackTrace();throw new RuntimeException("生成二维码出错");} finally {if (stream != null) {stream.flush();stream.close();}}}return null;}public static void main(String[] args) throws IOException {QRCodeUtil qrCodeUtil = new QRCodeUtil();//String qrCode = qrCodeUtil.createQRCode("http://10.0.2.2:63030/orders/alipaytest", 200, 200);String qrCode = qrCodeUtil.createQRCode("http://192.168.0.102:63030/orders/alipaytest", 200, 200);System.out.println(qrCode);}
}

这里的content参数就是指二维码扫出来指向的url,在本文中,这个url指的是order微服务orders/requestpay端点,请求支付。

2. AlipayConfig
package com.xuecheng.orders.config;/*** @author mumu* @version 1.0* @description 支付宝配置参数* @date 2024/02/16 14:56*/
public class AlipayConfig {// 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static String notify_url = "https://5m34y83626.vicp.fun/orders/receivenotify";// 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址//public static String return_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";// 请求网关地址//public static String URL = "https://openapi.alipaydev.com/gateway.do";public static String URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";// 编码public static String CHARSET = "UTF-8";// 返回格式public static String FORMAT = "json";// 日志记录目录public static String log_path = "/log";// RSA2public static String SIGNTYPE = "RSA2";
}

这里的notify_url 指的是贝锐花生壳给的域名+/orders/receivenotify,用于支付宝服务器通知我们支付结果。
这里的URL 指的是支付宝网关地址,目前沙箱环境用的是固定的https://openapi-sandbox.dl.alipaydev.com/gateway.do,如有变更可以去 沙箱环境->沙箱应用->开发信息 校验。

3. 端点代码

1. /generatepaycode

前端点击“前往支付”按钮后,携带商品信息,向后端发送一个生成支付二维码的请求。后端收到商品信息,结合用户信息,为他们创建一张订单到数据库,包含金额等信息,订单号为payNo

于是我们把这个payNo拼接到二维码所表示的url中,当用户扫码后,携带订单号前往支付端点。

参考代码如下

		@Value("${pay.qrcodeurl}")private String qrcodeurl;
		//生成二维码QRCodeUtil qrCodeUtil = new QRCodeUtil();String url = String.format(qrcodeurl, payNo);String qrCode = null;try {qrCode = qrCodeUtil.createQRCode(url, 200, 200);} catch (IOException e) {XueChengPlusException.cast("生成二维码失败");}
2. /requestpay

后端返回二维码到前端,拿起手机,打开支付宝沙箱版登录。
账号密码在 沙箱环境->沙箱账号->买家信息
在这里插入图片描述
登录后,拿起扫一扫二维码,会请求形如http://192.168.0.102:63030/orders/requestpay?payNo=1758388376771436544,也就是请求到/requestpay端点。后端从数据库取出订单信息,比如金额等,填入bizContent ,作为支付宝api必要数据。

参考代码如下

	@Value("${pay.alipay.APP_ID}")String APP_ID;@Value("${pay.alipay.APP_PRIVATE_KEY}")String APP_PRIVATE_KEY;@Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")String ALIPAY_PUBLIC_KEY;
	@RequestMapping("/requestpay")public void requestpay(String payNo, HttpServletResponse httpResponse) throws AlipayApiException, IOException {//约束XcPayRecord payRecord = orderService.getPayRecordByPayNo(payNo);if (payRecord == null){XueChengPlusException.cast("支付记录不存在,异常!");}if ("601002".equals(payRecord.getStatus())){XueChengPlusException.cast("已支付,无需重复支付");}//获得初始化的AlipayClientAlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);//创建API对应的requestAlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//在公共参数中设置回跳和通知地址alipayRequest.setNotifyUrl(AlipayConfig.notify_url);//alipayRequest.setReturnUrl(AlipayConfig.return_url);JSONObject bizContent = new JSONObject();//商户订单号,商家自定义,保持唯一性bizContent.put("out_trade_no", payNo);//支付金额,最小值0.01元bizContent.put("total_amount", payRecord.getTotalPrice());//订单标题,不可使用特殊符号bizContent.put("subject", payRecord.getOrderName());bizContent.put("product_code", "QUICK_WAP_WAY");alipayRequest.setBizContent(bizContent.toString());//填充业务参数String form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单httpResponse.setContentType("text/html;charset=" + AlipayConfig.CHARSET);httpResponse.getWriter().write(form);//直接将完整的表单html输出到页面httpResponse.getWriter().flush();}

后端把form 返回到手机,这个form会唤起支付功能,手机上完成支付,支付宝服务端就会收到请求。

3. /payresult

现在订单支付完了,怎么知道支付结果呢?一种是主动查询,需要当时向支付宝服务器发送支付请求时填入的out_trade_no,也就是payNo。可以设计一个前端按钮“查询支付结果”,发送请求到后端/payresult端点,后端主动携带payNo去支付宝服务器请求结果。

参考代码如下

	@Value("${pay.alipay.APP_ID}")String APP_ID;@Value("${pay.alipay.APP_PRIVATE_KEY}")String APP_PRIVATE_KEY;@Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")String ALIPAY_PUBLIC_KEY;
 		//查询支付状态//获得初始化的AlipayClientAlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);//创建API对应的requestAlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();JSONObject bizContent = new JSONObject();//商户订单号,商家自定义,保持唯一性bizContent.put("out_trade_no", payNo);alipayRequest.setBizContent(bizContent.toString());//填充业务参数AlipayTradeQueryResponse response = null;try {response = alipayClient.execute(alipayRequest);} catch (AlipayApiException e) {XueChengPlusException.cast("查询支付宝支付状态失败");}//解析支付结果PayStatusDto payStatusDto = new PayStatusDto();payStatusDto.setOut_trade_no(payNo);payStatusDto.setTrade_no(response.getTradeNo());payStatusDto.setTrade_status(response.getTradeStatus());payStatusDto.setApp_id(APP_ID);payStatusDto.setTotal_amount(response.getTotalAmount());return payStatusDto;

然后可以根据response.getTradeStatus()的值校验是否支付成功,然后编写后续业务代码。

4. /receivenotify

除了主动查询支付结果之外,还可以定义端点,让支付宝服务端异步通知我们。支付宝服务器在公网,所以我们也需要一个公网来接收它的请求,利用内网穿透技术,把我们的/receivenotify端点暴露到公网,并指定notify_url来告知支付宝服务端该向哪里发起异步通知,指定notify_url/requestpay那一步完成。

参考代码

    @Value("${pay.alipay.APP_ID}")String APP_ID;@Value("${pay.alipay.APP_PRIVATE_KEY}")String APP_PRIVATE_KEY;@Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")String ALIPAY_PUBLIC_KEY;
	@PostMapping("/receivenotify")public void receivenotify(HttpServletRequest request,HttpServletResponse response) throws AlipayApiException, IOException {Map<String,String> params = new HashMap<String,String>();Map requestParams = request.getParameterMap();for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {String name = (String) iter.next();String[] values = (String[]) requestParams.get(name);String valueStr = "";for (int i = 0; i < values.length; i++) {valueStr = (i == values.length - 1) ? valueStr + values[i]: valueStr + values[i] + ",";}//乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");params.put(name, valueStr);}//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)////计算得出通知验证结果//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)boolean verify_result = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);if(verify_result) {//验证成功////请在这里加上商户的业务逻辑程序代码//商户订单号String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");//支付宝交易号String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");//交易状态String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");//交易金额String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");//——请根据您的业务逻辑来编写程序(以下代码仅作参考)——if (trade_status.equals("TRADE_SUCCESS")) {PayStatusDto payStatusDto = new PayStatusDto();payStatusDto.setOut_trade_no(out_trade_no);payStatusDto.setTrade_no(trade_no);payStatusDto.setTrade_status(trade_status);//app_id和total_amount可以不填payStatusDto.setApp_id(APP_ID);payStatusDto.setTotal_amount(total_amount);System.out.println(payStatusDto);orderService.saveAliPayStatus(payStatusDto);}System.out.println("success");response.getWriter().write("success");}else{response.getWriter().write("支付情况校验失败");}}

完。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

红队笔记Day4 -->多层代理(模拟企业拓扑)

声明&#xff1a;本机文章只用于教育用途&#xff0c;无不良引导&#xff0c;禁止用于从事任何违法活动 前几天的红队笔记的网络拓扑都比较简单&#xff0c;今天就来模拟一下企业的真实网络拓扑&#xff0c;以及攻击方法 一般的大企业的网络拓扑如下&#xff1a;&#xff1a;…

基于Springboot+Vue实现的宿舍管理系统

基于SpringbootVue的宿舍管理系统 1.系统相关性介绍1.1 系统架构1.2 设计思路 2.功能模块介绍2.1 用户信息模块2.2 宿舍管理模块2.3 信息管理模块 3. 源码获取以及远程部署 前言&#xff1a; 在现代教育环境中&#xff0c;学生宿舍的管理显得尤为重要&#xff0c;需要一套能…

如何在Windows中配置多个显示器?这里提供详细步骤

Windows可以通过多种方式使用多个显示器&#xff0c;扩展或复制主显示器。你甚至可以关闭主显示器。以下是如何使用简单的键盘快捷键更改辅助显示设置。 使用WindowsP投影菜单 要快速更改Windows 10处理多个显示器的方式&#xff0c;请按WindowsP。屏幕右侧会弹出一个名为“投…

图表示学习 Graph Representation Learning chapter1 引言

图表示学习 Graph Representation Learning chapter1 引言 前言1.1图的定义1.1.1多关系图1.1.2特征信息 1.2机器学习在图中的应用1.2.1 节点分类1.2.2 关系预测1.2.3 聚类和组织检测1.2.4 图分类、回归、聚类 前言 虽然我并不研究图神经网络&#xff0c;但是我认为图高效的表示…

电脑重装系统之Windows 10 企业版 LTSC 2021

简介 Windows 10 22H2对于我来说太不简洁&#xff0c;最受不了的一点是微软强行硬塞给我一些并没有什么luan用的应用和功能&#xff0c;比如&#xff1a;天气&#xff0c;Onedrive......以及臃肿的ui设计。而且强行进行自动更新&#xff0c;我是真的受不了这个&#xff0c;看着…

leetcode:343.整数拆分

解题思路&#xff1a; 拆分的越多越好&#xff08;暂且认为&#xff09;&#xff0c;尽可能拆成m个近似相等的数&#xff0c;会使得乘积最大 dp含义&#xff1a;将i进行拆分得到最大的积为dp[i] 递推公式&#xff1a;j x dp[i-j](固定j&#xff0c;只通过凑dp[i-j]进而实现所…

optee UTA加载

流程 动态TA按照存储位置的不同分为REE filesystem TA&#xff1a;存放在REE侧文件系统里的TA&#xff1b; Early TA&#xff1a;被嵌入到optee os里的在supplicant启动之前就可用了。 这里我们讲的是常规的存放在REE侧文件系统里的TA。 通过GP标准调用的与TA通信的命令(opens…

【AIGC】Stable Diffusion的ControlNet参数入门

Stable Diffusion 中的 ControlNet 是一种用于控制图像生成过程的技术&#xff0c;它可以指导模型生成特定风格、内容或属性的图像。下面是关于 ControlNet 的界面参数的详细解释&#xff1a; 低显存模式 是一种在深度学习任务中用于处理显存受限设备的技术。在这种模式下&am…

Vue的一些基础设置

1.浏览器控制台显示Vue 设置找到扩展&#xff0c;搜索Vue 下载这个 然后 点击扩展按钮 点击详细信息 选择这个&#xff0c;然后重启一下就好了 ——————————————————————————————————————————— 2.优化工程结构 src的components里要…

MySQL数据库基础第四篇(多表查询与事务)

文章目录 一、多表关系二、多表查询三、内连接查询四、外连接查询五、自连接查询六、联合查询 union, union all七、子查询1.标量子查询2.列子查询3.行子查询4.表子查询 八、事务八、事务的四大特性九、并发事务问题十、事务隔离级级别 在这篇文章中&#xff0c;我们将深入探讨…

数据结构之队的实现

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

用HTML5 Canvas创造视觉盛宴——动态彩色线条效果

目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!-- 声明文档类型为XHTML 1.0 Transitional -…

Python四级考试笔记

Python四级考试笔记【源源老师】 四级标准 一、 理解函数及过程、函数的参数、函数的返回值、变量作用域等概念。 二、 能够创建简单的自定义函数。 三、 理解算法以及算法性能、效率的概念&#xff0c;初步认识算法优化 效率的方法。 四、 理解基本算法中递归的概念。 五、 掌…

【开源】SpringBoot框架开发独居老人物资配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询社区4.2 新增物资4.3 查询物资4.4 查询物资配送4.5 新增物资配送 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的独居老人物资配送系统&#xff0c;包含了社区档案、…

win7自带截图工具保存失效解决办法

今日发现一台远航技术的win7中自带的截图工具使用时正常&#xff0c;保存图片时没有弹出保存位置的对话窗口&#xff0c;无法正常保存图片。解决方案如下&#xff1a; 1、进入注册表编辑器。开始-搜索程序和文件-输入 regedit 按下回车键&#xff0c;打开注册表&#xff1b; 2、…

多模态基础---BERT

1. BERT简介 BERT用于将一个输入的句子转换为word_embedding&#xff0c;本质上是多个Transformer的Encoder堆叠在一起。 其中单个Transformer Encoder结构如下&#xff1a; BERT-Base采用了12个Transformer Encoder。 BERT-large采用了24个Transformer Encoder。 2. BERT的…

静态时序分析:SDC约束命令set_clock_transition详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 在静态时序分析&#xff1a;SDC约束命令create_clock详解一文的最后&#xff0c;我们谈到了针对理想(ideal)时钟&#xff0c;可以使用set_clock_transition命令直…

数据结构与算法:双向链表

朋友们大家好啊&#xff0c;在上节完成单链表的讲解后&#xff0c;我们本篇文章来对带头循环双向链表进行讲解 双向链表 双向链表、头节点和循环的介绍构建双向链表节点的构建初始化双向循环链表&#xff08;空链表&#xff09;销毁双向链表 链表的打印双向链表头尾的插与删尾插…

Medical Boundary Diffusion Modelfor Skin Lesion Segmentation

皮肤病灶分割的医学边界扩散模型 摘要 由于多尺度边界关注和特征增强模块的进步&#xff0c;皮肤镜图像中的皮肤病变分割最近取得了成功。然而&#xff0c;现有的方法依赖于端到端学习范式&#xff0c;直接输入图像和输出分割图&#xff0c;经常与极其困难的边界作斗争&#…

B端系统升级方案模板:针对美观性和体验性升级(总体方案)

大家好&#xff0c;我是大美B端工场&#xff0c;专注于前端开发和UI设计&#xff0c;有需求可以私信。本篇从全局分享如何升级B端系统&#xff0c;搞B端系统升级的有个整体思维&#xff0c;不是说美化几个图标&#xff0c;修改几个页面就能解决的&#xff0c;这个方案模板&…