ASP.NET网络商店销售管理系统的设计与实现

摘  要

随着软件技术的不断进步和发展,信息化的管理方式越来越广泛的应用于各个领域,对于任何网站系统的管理来说开发一套现代化的成员管理软件是十分必要的。通过这样的软件系统,可以做到成员的规范管理和快速查询,从而减少管理方面的工作量。有效的管理所有成员的信息就是成员管理系统完成的功能。销售管理系统是使用MS.NET平台中的ASP.NET开发基于B/S体系结构的Web应用程序,在Microsoft Visual Studio .NET 环境下,使用 C# 编程语言并结合Microsoft SQL Server 2000 数据库开发出一套网络版的销售管理系统。该系统由前端输入和后端管理组成。前端实现了用户注册,用户登录,购物车,定单查询,商品浏览(包括热门商品和新到商品),商品搜索等。后台实现了用户信息管理,管理员信息管理,商品信息管理,销售管理。通过这个系统,可以大大的提高网络管理者的工作效率和工作精度。

关键词网络商店;销售管理系统;模块;控件;C#.NET

1.4相关软件及技术介绍

1.4.1 ASP.NET技术

ASP.NET 是一种建立在通用语言上的程序构架,能被用于一台Web服务器来建立强大的Web应用程序。ASP.NET构架是可以用Microsoft(R)公司最新的产品 Visual Studio开发环境进行开发ASP.NET是基于通用语言的编译运行的程序,可以使它运行在Web应用软件开发者的几乎全部的平台上。通用语言的基本库,消息机制,数据接口的处理都能无缝的整合到ASP.NET的Web应用中。

1.4.2 SQL Server 

SQL Server 是一个具备完全 Web 支持的数据库产品,提供了对可扩展标记语言 (XML) 的核心支持以及在 Internet 上和防火墙外进行查询的能力,提供了以 Web 标准为基础的扩展数据库编程功能。

1.4.3 Visual Studio.net 2003

它是Microsoft推出.NET应用程序开发工具。它易学易用的特性得到很多的好评。Microsoft又推出新版的.NET应用程序开发工具 Visual Studio.NET 2005,加入更多的好用功能,是.net的好开发工具。

2.项目模块及框图

2.1 系统功能模快设计

系统主体采用B/ S(Browser/ Server ,浏览器/ 服务器) 结构,即采用目前分布式系统流行的3 层软件结构,即在传统的客户和服务器之间加入应用服务器(Application server) ,3 层即是表现层(浏览器) 、业务逻辑层(Web 服务器) 、数据层(数据服务器) ,系统简图如图2-1所示。数据服务器与Web 服务器是完全分开的,分开之后的3 层软件结构功能明确:客户层只提供应用程序的用户界面,负责与用户交互;业务逻辑层是应用系统的关键,它负责处理所有用户请求,进行具体的运算和决定程序的流程,并把处理结果返回给表现层;服务器层仍然提供的是数据库支持、维护和更新应用程序的数据。

2.2  网络销售管理流程图

图1 网络销售管理系统数据流程

2.3网络销售管理系统模块组织图

图2A系统模块组织图

图2B系统模块组织图

4.模块设计、分析、开发

4.1主页面设计

主页面是直接展示给用户的部分。在这一模块中,主要包括以下自定义控件和页面的实现:

页面头部控件(HeadMenu.ascx):主要包括登录链接和搜索框

商品分类导航控件(CategoryList.ascx):显示所有商品的列表,作为页面的左侧导航目录。

4.1.1页面头部控件设计

页面头部控件是为了方便用户快速导航到某个页面的,在HeaderMenu.ascx的设计中,具有技巧性的地方是如何展示给登录用户和匿名用户不同的导航条,为了区别登录用户和匿名用户,在HeaderMenu.ascx中将匿名用户所拥有的链接放在一个Span容器中,并将Span设为“Runat=Server”,这样就方便在代码中对去是否可见进行控制。同样,将登录用户需要的链接也放在另一个Span中。另
外,“搜索”也是一个超级链接,但它并非链接到某个Url。而是执行一条JavaScript语句“javascript:searh.submit()”,即把页面提交。如下图所示:

图3登录用户导航条                      图 4匿名用户导航条

控件代码的实现

在HeaderMenu的代码中,主要是判断用户的情况并控制Span容器的可见性。在HeaderMenu.ascx.cs中定义了下面的方法:

void showButton()

              {

                     //是否是匿名用户

                     if (Request.IsAuthenticated != true)

                     {

                            //登录用户区域不可见

                            areaLoggedIn.Visible = false;

                            //匿名用户区域可见

                            areaLoggedOut.Visible = true;

                     }

                     else

{

                            areaLoggedIn.Visible = true;

                            areaLoggedOut.Visible = false;

                     }

               }

这样在窗体加载即执行Pvage_Load()是调用上面的方法就可以实现效果了:

Private void Page_Load(object sender,System.EventArgs e)

{

     showButton();

}

4.1.2 商品分类导航控件的设计

     该控件显示所有商品的分类,单击目录中某个商品类别是将显示相应类别的商品列表页面。在CategoryList.ascx中主要用到了DataList控件,它用来绑定数据源。

控件代码的实现

private void Page_Load(object sender, System.EventArgs e)

              {

                     // 设置目录的选定项

                     string selectionID = Request.Params["selection"];

                     if ( selectionID != null)

           {

                            MyList.SelectedIndex = Int32.Parse(selectionID);

                     }

                     //将数据源绑定至DataList控件

                     MyList.DataSource = BLL.Product.GetCategoryList();

                     MyList.DataBind();

              }

可以看到,MyList的绑定数据源是方法GetCategoryList()的返回值,这个方法在BLL层中的Product类中,他调用数据库的存储过程GetCatergoryList。

4.2 商品信息模块页面

分类显示商品显示某种类型的所有商品。

ProductList.aspx页面的布局和首页基本相似,不同的是,在页面的中心位置放置了一个Reperter控件来绑定数据源,Repeater控件中用一个表格的第一行作为它的HeaderTemplate,而ItemTempmlate项中绑定了数据源的相应字段。“购物”也是通过超级链接来实现页面的传递。主要代码如下:

       //页的大小

              private static int PageSize = 5;

              private void Page_Load(object sender, System.EventArgs e)

              {

                     if (!Page.IsPostBack)

                     {

                            //显示第一页的记录

                            ShowResult(0, PageSize);

                     }

              }

              void ShowResult(int pageIndex, int pageSize)

              {

/绑定Repeater控件

products.DataSource = BLL.Product.GetProductsByCategory(int.Parse(Request.QueryString["categoryId"](pageSize, pageIndex);

                     products.DataBind();

                     //调用Product类中的方法获得该类商品的总数

                      int resultCount = BLL.Product.GetProductCountByCategory(int.Parse(Request.QueryString["categoryId"]));

                     int count;

                     //如果查询结果总数是页大小的整数倍

                     if (resultCount%PageSize == 0)

                     {

                            count = resultCount/PageSize;

                            PageCount.Text = count.ToString();

                     }

                     else

                     {

                            count = resultCount/PageSize+1;

                            PageCount.Text = count.ToString();

                     }

                     page.Items.Clear();

                     //绑定页码到DropDownList控件

                     for(int i=0; i<count; i++)

                     {

                            ListItem item = new ListItem((i+1).ToString(), i.ToString());

                            page.Items.Add(item);

                     }

                     page.SelectedIndex = pageIndex;

              }

4.3 用户信息管理模块设计


4.3.1登录页面设计

图5 用户登录界面

在这个系统中采用Froms验证方式,当自定义的验证程序确认用户身份时,可以让Froms验证系统发出Cookie,Cookie中除了包含验证票据之外,还可以通过程序写入被验证用户的标识信息,比如用户编号,然后使用该Cookie访问个人的信息。Forms验证方式还可以保证有权限要求的页面无法被匿名用户访问。例如,密码修改页面(ChangePwd.aspx)不能被匿名用户访问,要达到上诉目标,需要在配置文件Web。Config里面创建一个项。代码如下:

<!_验证方式为Forms_>

<authentication mode=”Forms”>

  <formsname=”eshop” loginUrl=”signIn.aspx”protecon=”all”path=”/”/>

</authentication>

     需要注意的是,<forms>标记中,name的值为验证系统所发出的Cookie的名称,loginUrl表示匿名用户被重定向到的页面的地址。如何防止ChangPwd不被匿名用户直接访问呢,也需要创建下面的项:

<location path=”ChangePwd.aspx”>

<system.web>

    <authorization>

          <!--拒绝匿名用户-->

          <deny user=”?”/>

  </authorization>

  </system.web>

</location>

同样,用户可以注销验证信息,注销页面(SignOut.aspx)代码如下:

     private void Page_Load(object sender, System.EventArgs e)

              {

                     //注销验证信息

                     System.Web.Security.FormsAuthentication.SignOut();

                     //清空Session

                     Session.Clear();

                     //返回首页

                     Response.Redirect("default.aspx");

            }

4.3.2 注册页面的设计


    注册新用户时候,仅需输入最基本的信息,个人详细资料在注册之后再进行修改,Register.aspx的界面主要是接收一些用户输入的文本框,以及相应的验证控件、“注册”按钮和显示提示信息的Lable控件。

图6 注册页面

代码的实现:通过存储过程AddNewUser实现注册的功能:

CREATE  PROCEDURE AddNewUser

(

         @username nvarchar(50),

         @password nvarchar(50),

         @question nvarchar(50),

         @answer nvarchar(50),

         @result int output

)

AS

      /*是否存在相同的用户名*/

      if not exists (SELECT * FROM USERINFO WHERE USERNAME=@USERNAME )

      BEGIN

            /*插入新的用户记录*/

            INSERT INTO USERINFO (USERNAME, USERPWD, QUESTION, ANSWER)

                   VALUES (@USERNAME, @PASSWORD, @question, @answer)

            /*将Result赋值为新添加用户的UserId*/

            SELECT @result = SCOPE_IDENTITY()

       END

        ELSE

       BEGIN

            SET @RESULT = -1

       END

     该存储过程带有输出参数,如果有相同的用户存在,输出参数为-1,否则,输出的参数的值为该用户的UserID。在User类中定义方法AddNewUser()调用AddNewUser存储过程,

4.4购物车功能的设计与实现

在前面的流程图中,我们可以看到这个购物流程是不允许匿名用户拥有购物车的,匿名用户注册并登录之后,才能使用购物车。登录用户的购物车编号CartID为用户编号。CartID生成过程中用到了Cookie,Cookie是用来保存个人信息的对象,它存在于客户端。针对购物车的功能,设计了ShoppingCart类,其中定义了GetShoppingCartID(),代码如下:

public String GetShoppingCartID()

        {

            HttpContext Context = HttpContext.Current;

// 如果该用户已经通过验证后登录了系统,

那么以该用户的UserID作为购物车ID

            if (Context.User.Identity.Name != "")

            {

                Response.Redirect("/esop/SignIn.aspx");

             }

             if (Context.Request.Cookies["ShoppingCartID"] != null)

            {

                return Context.Request.Cookies["ShoppingCartID"].Value;

             }

在数据库中定义了存储过程ShoppingCartAddItem,实现向购物车添加商品的功能,代码如下:

CREATE Procedure ShoppingCartAddItem

(

    @CartID nvarchar(50),

    @ProductID int,

    @Quantity int

)

As

DECLARE @CountItems int

SELECT

    @CountItems = Count(ProductID)

FROM

    ShoppingCart

WHERE

    ProductID = @ProductID

  AND

    CartID = @CartID

IF @CountItems > 0  /* 该购物车中已有该商品的记录,更新数量 */

    UPDATE

       ShoppingCart

    SET

        Quantity = (@Quantity + ShoppingCart.Quantity)

    WHERE

      ProductID = @ProductID

      AND

        CartID = @CartID

ELSE  /* 该购物车中没有这个商品的记录,插入新记录 */

    INSERT INTO ShoppingCart

    (

        CartID,

        Quantity,

        ProductID

    )

    VALUES

    (

        @CartID,

        @Quantity,

        @ProductID

    )

GO


4.5 购物车的结算设计与实现

图 7 商品结算界面

如果用户的预存款金额不足够支付本次购物,则会出现“存款不足”的提示如果能够支付,则生成新的订单,实现预存款支付订单的存储过程代码如下:CREATE PROCEDURE PayOrder

@userId int,

@totalcost decimal,

@result int output

 AS

       DECLARE @tmp decimal

       /*@tmp为当前用户预存款金额*/

       SELECT @tmp =  acount

       FROM UserInfo

       WHERE userID = @userId

       /*如果预存款不足*/

       IF @tmp <@totalcost

       BEGIN

              /*置标志为-1*/

              SET @result = -1

       END

       /*预存款足够支付,扣除相应的金额*/

       ELSE

       BEGIN

              UPDATE UserInfo

              SET acount = acount -@totalcost

              WHERE userId= @userId

              /*置标志为1*/

              SET @result = 1

       END

GO

4.6查询销售情况页面的设计

 模块的查询支持按月查询、日查询。查询的结果是每种商品的相关的定单数、售出数量和销售收入。页面主要包括3个DropDownList,分别用来选择年、月、日,两个按钮分别进行按月查询和按日查询,以及显示查询的结果的DataGrid。页面第一次加载时,显示日期为当前日期,并绑定到当前的销售情况。


图8销售情况图

代码的实现

查询销售情况的存储过程定义为GetSails,有3个输入参数,分别为@year(年)、@month(月)、@day(日)。当@day为0时,表示查询月记录,否则为查询当日记录。

  在adminDB类中定义GetSails()方法调用上面的GetSails存储过程,并返回记录集。代码如下:

    public  DataSet GetSails(string year, string month, string day)

              {

                     SqlParameter[] para = {

                       new SqlParameter("@year", int.Parse(year)),

                       new SqlParameter("@month", int.Parse(month)),

                       new SqlParameter("@day", int.Parse(day))

                                                                           };

                            return eshop.DAL.SQLHelper.ExecuteDataset(eshop.DAL.SQLHelper.CONN_STRING, CommandType.StoredProcedure, "GetSails", para);

              }

在用户表示层,首先需要绑定选择日期的DropDownList。定义BindDate()方法,代码如下:

void BindDate()

              {

                     //绑定年

                     for (int i=2007; i<2020; i++)

                     {

ListItem item = new ListItem(Convert.ToString(i),Convert.ToString(i));

                      Year.Items.Add(item);

                     }

                     //绑定月

                     for (int i = 1 ; i<13 ; i++)

                     {

ListItem item1 =  new ListItem(Convert.ToString(i),Convert.ToString(i));

                       Month.Items.Add(item1);

                     }

                     //绑定日

                     for (int i=1; i<32; i++)

                     {

                            ListItem item2 =  new;

                            Day.Items.Add(item2);

                     }

              }

此外,定义绑定DataGrid的方法BindGrid():

void BindGrid(string year, string month, string day)

              {

                     GridSails.DataSource = new AdminDB().GetSails(year, month, day);

                     GridSails.DataBind();

              }

在页面加载时间处理方法Page_Load()中对数据进行绑定,并显示当前日期以及当日销售记录:

         private void Page_Load(object sender, System.EventArgs e)

              {

                     if (!Page.IsPostBack)

                     {

                            BindDate();

                            //绑定当天记录

                            BindGrid(DateTime.Now.Year.ToString(), DateTime.Now.Month.ToString(),

DateTime.Now.Day.ToString());

                            //显示为当前日期

                            Year.SelectedValue = DateTime.Now.Year.ToString();

                            Month.SelectedValue =  DateTime.Now.Month.ToString();

                            Day.SelectedValue = DateTime.Now.Day.ToString();

//插入日志

AdminDB.InsertAction("查看当日销售记录", System.DateTime.Now, User.Identity.Name);

                     }

              }

最后,在两个按钮单击事件处理方法中添加绑定数据以及插入日志的代码:

//查询所选日期的月销售记录

         private void QueryMonth_Click(object sender, System.EventArgs e)

              {

BindGrid(Year.SelectedValue, Month.SelectedValue, "0");

AdminDB.InsertAction("查看"+Year.SelectedValue+"年"+Month.SelectedValue+"月"

                            + "的销售记录", System.DateTime.Now, User.Identity.Name);

               }

              //查询所选日期的日销售记录

private void QueryDay_Click(object sender, System.EventArgs e)

{

BindGrid(Year.SelectedValue, Month.SelectedValue, Day.SelectedValue);

AdminDB.InsertAction("查看"+Year.SelectedValue+"年"+Month.SelectedValue+"月"

+ Day.SelectedValue +"日的销售记录",  System.DateTime.Now,User.Identity.Name 

}

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

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

相关文章

TPV-W5 24V 48V 系列——正负双输出和单输出,工业级环境温度,用于PCB安装的国际标准结构

TPV-W5系列提供正负双输出和单输出&#xff0c;工业级环境温度&#xff0c;用于PCB安装的国际标准结构。此系列产品小巧&#xff0c;效率高&#xff0c;低输出纹波及能承受3000V以上的耐压&#xff0c;用于需要正负电压或单输出和高隔离电压的场合。封装有SIP和DIP可选。

JAVA基础之线程池原理与源码简读

线程 线程是调度CPU资源的最小单位&#xff0c;线程模型分为KLT和ULT模型&#xff0c;JVM使用的KLT模型java线程与OS线程保持1:1的映射关系&#xff0c;也就是说每一个java线程对应操作系统一个线程。Java线程有以下几种生命状态&#xff1a; NEW&#xff1a;新建状态RUNNABL…

单调栈|503.下一个更大元素II

力扣题目链接 class Solution { public:vector<int> nextGreaterElements(vector<int>& nums) {// 拼接一个新的numsvector<int> nums1(nums.begin(), nums.end());nums.insert(nums.end(), nums1.begin(), nums1.end());// 用新的nums大小来初始化resu…

我独自升级崛起在哪下载 我独自升级电脑PC端下载教程分享

将于5月8日在全球舞台闪亮登场的动作角色扮演游戏《我独自升级崛起》&#xff0c;灵感源自同名热门动画与网络漫画&#xff0c;承诺为充满激情的游戏玩家群体带来一场集深度探索与广阔体验于一身的奇幻旅程。该游戏以独特的网络武侠世界观为基底&#xff0c;展现了一位普通人踏…

[Java、Android面试]_22_APP启动流程(中频问答)

欢迎查看合集&#xff1a; Java、Android面试高频系列文章合集 本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料。 整理成了面试系列&#xff0c;由于时间有限&#xff0c;每天整理一点&am…

【个人博客搭建】(17)使用FluentValidation 参数校验

FluentValidation 是一个用于 .NET 的开源验证库&#xff0c;它提供了一种流畅的接口和强类型验证规则&#xff0c;使得验证逻辑表达得更加清晰和简洁。&#xff08;Apache-2.0&#xff09; FluentValidation 的主要作用包括&#xff1a; 提高代码可读性&#xff1a;通过使用 F…

Python ArcPy批量将大量栅格文件的投影坐标系转为地理坐标系

本文介绍基于Python语言中的ArcPy模块&#xff0c;批量将多个遥感影像由投影坐标系转为地理坐标系的方法。 在之前的文章中&#xff0c;我们介绍过将单独1景遥感影像的投影坐标系转为地理坐标系的方法&#xff0c;大家可以参考文章投影坐标系转为地理坐标系&#xff1a;GDAL命令…

Voice Conversion、DreamScene、X-SLAM、Panoptic-SLAM、DiffMap、TinySeg

本文首发于公众号&#xff1a;机器感知 Voice Conversion、DreamScene、X-SLAM、Panoptic-SLAM、DiffMap、TinySeg Converting Anyones Voice: End-to-End Expressive Voice Conversion with a Conditional Diffusion Model Expressive voice conversion (VC) conducts speak…

【爬虫】爬取A股数据写入数据库(一)

1. 对东方财富官网的分析 步骤&#xff1a; 通过刷新网页&#xff0c;点击等操作&#xff0c;我们发现https://datacenter-web.eastmoney.com/api/data/v1/get?请求后面带着一些参数即可以获取到相应数据。我们使用python来模拟这个请求即可。 我们以如下选择的页面为切入点…

滑动窗口 | 1652. 拆炸弹 |LeetCode

文章目录 题目介绍暴力(可以过力扣竟然。不愧是简单题)&#xff1a;滑动窗口 祝你天天开心 题目介绍 你有一个炸弹需要拆除&#xff0c;时间紧迫&#xff01;你的情报员会给你一个长度为 n 的 循环 数组 code 以及一个密钥 k 。 为了获得正确的密码&#xff0c;你需要替换掉每…

关系型数据库MySql分库分表带来的问题以及解决方案

水平分表 水平分表是什么&#xff1f; 将一张表横向拆分为多张表&#xff0c;拆分的表&#xff0c;依然在同一个库中。 例如&#xff0c;user表有400w条记录&#xff0c;将user表拆分成4张表&#xff0c;每张表100w条记录。拆分后的表名&#xff0c;分别叫做user_0、user1、u…

内网用户是如何连接上互联网的?详解NAT网络地址转换技术

背景 https://blog.csdn.net/weixin_43972437/article/details/107344633 不知道你有没有过困惑&#xff0c;都说现在 ipv4 地址耗尽了&#xff0c;但是我们为什么还能上网呢&#xff1f;原来这都要归功于 NAT 网络地址转换技术。 比如我们接入了中国移动的宽带&#xff0c;宽…

重学SpringBoot3-SPI机制

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-SPI机制 什么是 SPI&#xff1f;Spring Boot 中的 SPI 机制spring.factories 文件自动配置的实现启动流程中的作用 SPI实际应用步骤 1: 新建模块步骤 2:…

扩展学习|一文读懂知识图谱

一、知识图谱的技术实现流程及相关应用 文献来源&#xff1a;曹倩,赵一鸣.知识图谱的技术实现流程及相关应用[J].情报理论与实践,2015, 38(12):127-132. &#xff08;一&#xff09;知识图谱的特征及功能 知识图谱是为了适应新的网络信息环境而产生的一种语义知识组织和服务的方…

HarmonyOS开发案例:【卡片二级联动】

1 卡片介绍 使用ArkTS语言&#xff0c;实现一个导航与内容二级联动的效果。 2 标题 二级联动&#xff08;ArkTS&#xff09; 3 介绍 介绍了如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能&#xff1a; 切换左侧导航&#xff0c;右侧滚动到对应…

自定义类型②③——联合体和枚举

自定义类型②③——联合体和枚举 1.联合体1.1 联合体类型的声明1.2 联合体的特点1.3 相同成员结构体和联合体的对比1.4 联合体大小的计算1.5 联合体的应用①1.5 联合体的应用② 2. 枚举2.1 枚举类型的声明2.2 枚举类型的特点2.3 枚举的优点 1.联合体 1.1 联合体类型的声明 关…

Python sqlite3库 实现 数据库基础及应用 输入地点,可输出该地点的爱国主义教育基地名称和批次的查询结果。

目录 【第11次课】实验十数据库基础及应用1-查询 要求: 提示: 运行结果&#xff1a; 【第11次课】实验十数据库基础及应用1-查询 声明&#xff1a;著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 1.简答题 数据库文件Edu_Base.db&#…

有什么方便的教学口语软件?6个软件教你快速练习口语

有什么方便的教学口语软件&#xff1f;6个软件教你快速练习口语 以下是六个方便实用的教学口语软件&#xff0c;它们可以帮助您快速练习口语&#xff1a; AI外语陪练: 这是一款知名的语言学习软件&#xff0c;提供多种语言的口语练习课程。它采用沉浸式的学习方法&#xff0…

【数字图像处理笔记】Matlab实现图像平滑算法 均值-中值-高斯滤波 (三)

&#x1f48c; 所属专栏&#xff1a;【数字图像处理笔记】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x…

jetson实操(二):jetson nano发送短信到指定用户

文章目录 一、准备工作二、代码实现 一、准备工作 腾讯云网址&#xff1a;点击 注&#xff1a;需先申请“短信签名”和“短信正文”&#xff0c;按照要求填写申请即可&#xff0c;腾讯云的审核效率还是很快的&#xff0c;一般在1-2个小时内就会有结果&#xff0c;链接&…
最新文章