简介:一份基于ASP.NET MVC与三层架构的完整商城系统源码,面向.NET开发者和电商项目二次开发人员,也适合高校学生作为毕业设计或课程项目参考。系统采用B/S模式,实现了会员等级积分、订单管理、购物车、支付宝/网银支付、确认收货好评、回收站等主流商城功能,页面运用MVC模板灵活展示,并通过数据合法性校验、回滚机制保障数据安全。开发环境为VS2013+SQL Server2008R2,使用存储过程直接操作数据,有效提升网站性能。资源包共2000个文件,以C#源码、MVC页面(.cshtml)、ASP.NET页面(.aspx)及前端脚本/样式(.js/.css)为主,还包含大量静态图片和数据库相关文件,压缩包大小127.65MB,目录结构清晰,便于定位与二次开发。包内另赠小程序商城源码,覆盖移动端购物场景。已有799人学习/下载这套资源,既能直接运行体验完整流程,也可在其基础上做功能扩展或架构研究。
1. ASP.NET商城源码实战:一套能跑通前后台的B/S架构老项目
做电商后台开发的人,手里要是没几套能直接翻源码的商城项目,遇到“客户要个带会员积分和支付宝支付的商城”这种需求时,多半得从零开始搭框架。这套ASP.NET商城源码属于典型的B/S模式项目,开发环境是VS2013加SQL Server 2008R2,默认采用MVC加三层架构,页面模板可切换,后台内置了会员等级、订单管理、购物车、回收站、评价和支付宝担保交易这些主流电商功能。更实在的是,它随包附赠一份微信小程序的源码工程(2048-小程序.zip),虽然上一轮交付的小程序工程是独立的,不能像网页那样直接在浏览器里跑,但正好补上了移动端展示这块短板。适合正在做.NET电商项目、需要参考存储过程和权限控件写法的开发人员,也适合拿来当毕业设计和二次开发底子。
这套系统最值得看的不是页面长什么样,而是它的数据层设计:大量业务操作通过视图和存储过程完成,在性能和安全上有明确取舍,支付宝接口的对接方式也保留了老项目的典型写法。接下来我会把它的架构拆开讲清楚,再从订单、会员、支付和模板这些实际模块入手,带着你把代码跑起来。
2. 架构与数据库:MVC+三层在VS2013和SQL2008R2下的落地方式
2.1 B/S架构与MVC+三层的真实分工
这套商城系统的整体结构是浏览器发起请求,IIS承载站点,后台通过ADO.NET连到SQL Server 2008R2数据库。项目里能看到Global.asax负责应用程序生命周期管理,比如Application_Start里注册路由和全局过滤器;页面文件如.ascx控件承担了前台展示和交互逻辑。
我拆过不少ASP.NET商城,这套代码在分层上属于典型的“用户界面层—业务逻辑层—数据访问层”三层结构,同时引入了MVC的页面模板机制。实际代码里的做法是:
- 用户界面层:
.aspx页面加.ascx用户控件,像UCDroplistPermission.ascx这种就是专门的权限下拉控件,RegionDropList.ascx和AjaxRegion.ascx负责地区联动。 - 业务逻辑层:处理订单状态流转、会员积分计算、购物车价格重算。
- 数据访问层:封装SQL操作,重点调用存储过程,例如分页查询商品列表、更新库存和积分。
// Global.asax 核心初始化逻辑 protected void Application_Start(object sender, EventArgs e) { // 注册MVC路由,默认路由指向Home/Index RouteConfig.RegisterRoutes(RouteTable.Routes); // 初始化SqlServer依赖,用于缓存失效通知 SqlDependency.Start(ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString); } protected void Application_Error(object sender, EventArgs e) { // 捕获未处理异常,写日志并回滚事务,避免数据脏写 Exception ex = Server.GetLastError(); if (ex != null) { LogHelper.WriteLog("GlobalError", ex); // 调用存储过程回滚当前未提交事务 DbHelper.ExecuteSql("IF @@TRANCOUNT > 0 ROLLBACK TRAN"); } }这段代码里,SqlDependency.Start是为了在商品数据变更时自动清缓存,减少数据库压力。Application_Error属于兜底逻辑,保证系统运行中遇到不可恢复错误时,数据库不会留下半截数据。
注意:
SqlDependency需要数据库开启Service Broker,如果SQL Server安装时没启用,这段代码会直接报错。实际调试中很多人忽略这一点。
2.2 数据库结构与存储过程设计
系统数据库文件对应SQL Server 2008R2版本,里面包含视图和大量存储过程。这些存储过程不只做单表操作,而是把多表联查、事务控制、分页逻辑全部封在数据库端。
-- 订单分页查询存储过程(简化版) CREATE PROCEDURE [dbo].[Proc_OrderPageList] @PageIndex INT, @PageSize INT, @UserId INT = NULL, @TotalCount INT OUTPUT AS BEGIN SET NOCOUNT ON; -- 统计总数,供分页控件使用 SELECT @TotalCount = COUNT(1) FROM Orders WHERE @UserId IS NULL OR UserId = @UserId; -- 利用ROW_NUMBER做高效分页,避免一次性加载全表数据 SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY OrderId DESC) AS RowId, * FROM Orders WHERE @UserId IS NULL OR UserId = @UserId ) AS t WHERE RowId BETWEEN (@PageIndex - 1) * @PageSize + 1 AND @PageIndex * @PageSize; END这个存储过程是商城后台订单列表的核心查询逻辑,代码里通过@UserId参数实现“查询全部订单”和“查询指定用户订单”的切换。分页这里用了ROW_NUMBER()而不是OFFSET FETCH,因为后者只在SQL Server 2012以上版本才支持,2008R2只能用这种写法。
在VS2013里调试这个项目时,建议直接把存储过程逐个过一遍,重点关注Proc_OrderCreate、Proc_UserRecharge这类涉及资金和积分的操作。它们内部用BEGIN TRAN配合@@ERROR判断事务成败,这是老项目的经典写法,逻辑比ORM生成的SQL要直观得多。
2.3 数据合法性校验与回滚机制
摘要里提到的数据合法性校验和回滚机制,是这套系统设计上比较严谨的地方。在页面层,通过ASP.NET验证控件和后台C#代码双重检查数据类型、日期格式、字符长度,并对特殊字符做转码,防止SQL注入。
// 用户控件中的输入校验示例 public static bool ValidateInput(string input, string fieldName, int maxLength, out string errorMsg) { errorMsg = string.Empty; if (string.IsNullOrEmpty(input)) { errorMsg = fieldName + "不能为空"; return false; } if (input.Length > maxLength) { errorMsg = fieldName + "长度不能超过" + maxLength + "个字符"; return false; } // 过滤危险字符,如单引号、尖括号等,防注入和XSS string dangerousChars = "'<>;%\"()&"; foreach (char c in dangerousChars) { if (input.IndexOf(c) >= 0) { errorMsg = fieldName + "包含非法字符"; return false; } } return true; }数据访问层在调用存储过程时,还会对参数化查询做二次保障,配合SQL Server事务回滚机制,让系统在出现异常时能自动回滚,保证库存、订单、支付流水这几个表的数据始终保持一致。这种做法在生产环境里很实用,很多基于EF的商城项目,反而会在并发下单时出现超卖或状态不一致的问题。这套老代码的这种设计,放到今天看也没过时。
3. 核心业务模块实战:会员、订单、购物车与评价的完整链路
3.1 会员等级与积分管理
系统内置了会员等级积分管理,用户在商城消费后自动获得积分,不同积分对应不同等级和折扣。这块逻辑主要在MemberLevel相关存储过程和后台页面中体现。
-- 用户下单后更新积分与等级(关键存储过程) CREATE PROCEDURE [dbo].[Proc_UserPointsUpdate] @UserId INT, @OrderAmount DECIMAL(18,2), @Points INT OUTPUT AS BEGIN BEGIN TRAN; -- 积分按订单金额1:1累积,上不封顶 UPDATE Users SET Points = Points + @OrderAmount, TotalAmount = TotalAmount + @OrderAmount WHERE UserId = @UserId; -- 根据累计消费金额自动升级等级 UPDATE Users SET LevelId = ( SELECT TOP 1 Id FROM MemberLevel WHERE MinAmount <= TotalAmount ORDER BY MinAmount DESC ) WHERE UserId = @UserId; SELECT @Points = Points FROM Users WHERE UserId = @UserId; IF @@ERROR <> 0 BEGIN ROLLBACK TRAN; RETURN -1; END COMMIT TRAN; END这套积分逻辑直接埋在存储过程里,好处是订单提交和积分更新在同一事务中完成,不会出现订单生成了但积分没加的情况。对应的PCC.ascx和Region.ascx主要是地区级联选择控件,用户注册时选择省市区,数据来源也是数据库中的地区表,通过AjaxRegion.ascx的异步回发实现省市区的三级联动,不需要页面刷新。
3.2 购物车与订单状态机
购物车在商城系统里算核心中的核心。这套系统的购物车数据保存在数据库表中,每次添加、修改商品都会同步更新数据库,这比用Session存购物车的方案更稳,用户换设备登录后购物车数据还在。
// 购物车添加商品逻辑(BLL层) public static bool AddToCart(int userId, int productId, int quantity) { // 先查购物车是否已存在该商品 DataTable dt = DbHelper.ExecuteDataTable( "SELECT * FROM Cart WHERE UserId=@uid AND ProductId=@pid", new SqlParameter("@uid", userId), new SqlParameter("@pid", productId)); if (dt.Rows.Count > 0) { // 已存在则累加数量,并检查库存上限 int newQty = (int)dt.Rows[0]["Quantity"] + quantity; if (newQty > 999) newQty = 999; DbHelper.ExecuteSql( "UPDATE Cart SET Quantity=@qty WHERE UserId=@uid AND ProductId=@pid", new SqlParameter("@qty", newQty), new SqlParameter("@uid", userId), new SqlParameter("@pid", productId)); } else { // 不存在则新增购物车记录 DbHelper.ExecuteSql( "INSERT INTO Cart(UserId, ProductId, Quantity, AddTime) VALUES(@uid,@pid,@qty,GETDATE())", new SqlParameter("@uid", userId), new SqlParameter("@pid", productId), new SqlParameter("@qty", quantity)); } // 调用存储过程重算购物车总金额 DbHelper.ExecuteSql("EXEC Proc_CartTotal @UserId=@uid", new SqlParameter("@uid", userId)); return true; }这段代码展示了购物车模块最常见的“有则改、无则加”处理逻辑。这里的Proc_CartTotal存储过程会在每次添加后重算总金额和总数量,返回给页面上的购物车角标。
订单状态流转分为“待付款 → 已付款 → 待发货 → 已发货 → 已完成 → 已取消”几个阶段,对应数据库里的OrderStatus字段。涉及退货时,系统支持“确认收货好评”后生成评价记录,同时返还积分到用户账户。
3.3 回收站与软删除机制
这里说的回收站不是Windows那个回收站,而是商城的商品和订单的软删除机制。删除商品时不会真从数据库里移除记录,而是把IsDeleted字段置为1,这样后台还能通过回收站恢复误删的商品或订单。
-- 软删除商品,保留数据可恢复 UPDATE Products SET IsDeleted = 1, DeleteTime = GETDATE() WHERE ProductId = @ProductId; -- 后台回收站恢复商品 UPDATE Products SET IsDeleted = 0, DeleteTime = NULL WHERE ProductId = @ProductId;回收站的设计逻辑是把业务数据的生命周期拉长,给运营留了后悔药。这类设计在商城后台很常见,特别是订单和商品这类数量大、误操作概率高的表,硬删除的后果通常很严重。
3.4 确认收货与评价闭环
确认收货和好评功能,是把交易闭环的最后一步补上。订单发货后,用户点击确认收货,系统会更新订单状态,并跳转到评价页面。
// 确认收货并触发评价入口 public static bool ConfirmReceive(int orderId, int userId) { // 校验订单是否属于当前用户且状态为已发货 int rows = DbHelper.ExecuteSql( @"UPDATE Orders SET OrderStatus = 5, ReceiveTime = GETDATE() WHERE OrderId=@oid AND UserId=@uid AND OrderStatus = 4", new SqlParameter("@oid", orderId), new SqlParameter("@uid", userId)); if (rows > 0) { // 订单确认收货后,触发积分发放 DataTable dt = DbHelper.ExecuteDataTable( "SELECT OrderAmount FROM Orders WHERE OrderId=@oid", new SqlParameter("@oid", orderId)); decimal amount = Convert.ToDecimal(dt.Rows[0]["OrderAmount"]); DbHelper.ExecuteSql( "EXEC Proc_UserPointsUpdate @UserId=@uid, @OrderAmount=@amount", new SqlParameter("@uid", userId), new SqlParameter("@amount", amount)); return true; } return false; // 订单状态不对或不属于该用户则返回失败 }注意这里的OrderStatus参数是个关键点。代码里用4表示已发货、5表示已完成,这套状态值是数据库里的硬编码,二次开发时如果自己新增状态,一定不能跟原有的数字冲突,否则会出现订单状态错乱的“玄学”问题。
4. 支付宝接入与付款流程:担保交易、即时到账和网银的配置参数
4.1 三种支付方式共存
系统支持支付宝担保交易(含即时到账)和网银付款三种模式。担保交易是老版本支付宝的经典模式,资金先由支付宝托管,买家确认收货后卖家才能拿到钱,适合B2C商城。即时到账则适用于虚拟商品或信任度高的交易场景,资金直接进卖家账户。
三种支付方式的接入,系统里是通过ShowPaymentMode.ascx这个控件在前台切换显示的。后台会根据商品类型和商家配置自动决定展示哪种支付按钮,前端代码结构如下:
// 支付方式选择控件核心逻辑 protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // 从数据库读取商家配置的支付方式列表 DataTable dt = DbHelper.ExecuteDataTable( "SELECT PayCode, PayName FROM PaymentConfig WHERE IsEnabled=1"); foreach (DataRow row in dt.Rows) { // 根据PayCode动态创建支付按钮 string payCode = row["PayCode"].ToString(); if (payCode == "alipay_escrow") { // 担保交易按钮 litPayment.Text += "<input type='radio' name='paytype' value='alipay_escrow' />支付宝担保交易"; } else if (payCode == "alipay_direct") { // 即时到账按钮 litPayment.Text += "<input type='radio' name='paytype' value='alipay_direct' />支付宝即时到账"; } } } }4.2 支付宝接口参数配置清单
支付宝接口对接需要设置商户号、密钥、回调地址等参数。这套代码中,这些配置统一存在Web.config或数据库的PaymentConfig表里。实际对接时,你需要准备以下参数:
| 参数名 | 配置位置 | 说明 |
|---|---|---|
PartnerID | Web.config | 支付宝签约商户号,以2088开头的16位数字 |
SellerEmail | Web.config | 商家支付宝账号 |
PrivateKey | Web.config | RSA私钥,老版本用MD5签名,新版本用RSA2 |
NotifyUrl | 支付请求地址 | 支付宝服务器异步通知回调地址,必须公网可访问 |
ReturnUrl | 支付请求地址 | 支付完成后同步跳转地址 |
PayType | 支付控件 | alipay_escrow / alipay_direct 二选一 |
// 构造支付宝支付请求(旧版接口示例) public static string BuildAlipayRequest(string orderNo, decimal amount, string payType) { // 从Web.config读取配置 string partnerId = ConfigurationManager.AppSettings["alipay_partner"]; string sellerEmail = ConfigurationManager.AppSettings["alipay_seller"]; string privateKey = ConfigurationManager.AppSettings["alipay_key"]; string notifyUrl = ConfigurationManager.AppSettings["alipay_notify_url"]; string returnUrl = ConfigurationManager.AppSettings["alipay_return_url"]; // 拼接参数并生成MD5签名 SortedDictionary<string, string> parameters = new SortedDictionary<string, string>(); parameters.Add("service", payType == "alipay_escrow" ? "create_partner_trade_by_buyer" : "create_direct_pay_by_user"); parameters.Add("partner", partnerId); parameters.Add("seller_email", sellerEmail); parameters.Add("out_trade_no", orderNo); parameters.Add("subject", "商城订单" + orderNo); parameters.Add("total_fee", amount.ToString("F2")); parameters.Add("notify_url", notifyUrl); parameters.Add("return_url", returnUrl); // 按key排序后拼接成待签名字符串 StringBuilder sb = new StringBuilder(); foreach (var kv in parameters) { sb.Append(kv.Key).Append("=").Append(kv.Value).Append("&"); } string signContent = sb.ToString().TrimEnd('&') + privateKey; string sign = Md5Encrypt(signContent); // 构建自动提交表单 return BuildAutoSubmitForm(parameters, sign); }注意这套代码用的是老版本MD5签名方式,现在的支付宝开放平台已经主推RSA2密钥,正式上线前建议升级到新接口。如果你是学习研究用途,直接跑通流程就行;如果要上生产环境,需要替换签名算法和接口地址。
4.3 异步通知与订单状态同步
支付宝异步通知(NotifyUrl)是整个支付链路里最容易翻车的一环。服务器收到支付宝的通知后,需要先验签,再判断订单金额是否一致,最后更新订单状态。这套系统的做法是:
// 支付宝异步通知处理 public void HandleAlipayNotify() { // 1. 获取支付宝POST过来的参数 string tradeStatus = Request.Form["trade_status"]; string outTradeNo = Request.Form["out_trade_no"]; string totalFee = Request.Form["total_fee"]; string tradeNo = Request.Form["trade_no"]; // 2. 验签:使用支付宝公钥验证签名 bool isSignValid = AlipayCore.VerifySign(Request.Form); if (!isSignValid) { Response.Write("fail"); return; } // 3. 验签通过后查订单,比对金额 DataTable dt = DbHelper.ExecuteDataTable( "SELECT * FROM Orders WHERE OrderNo=@no", new SqlParameter("@no", outTradeNo)); if (dt.Rows.Count == 0) { Response.Write("fail"); return; } decimal orderAmount = Convert.ToDecimal(dt.Rows[0]["OrderAmount"]); if (Math.Abs(orderAmount - Convert.ToDecimal(totalFee)) > 0.01m) { // 金额不一致,疑似篡改,记录日志并返回失败 LogHelper.WriteLog("AlipayNotify", "金额不一致: 订单" + outTradeNo); Response.Write("fail"); return; } // 4. 判断交易状态,更新订单和支付流水 if (tradeStatus == "TRADE_SUCCESS" || tradeStatus == "TRADE_FINISHED") { DbHelper.ExecuteSql( "UPDATE Orders SET OrderStatus=1, PayTime=GETDATE(), TradeNo=@tradeNo WHERE OrderNo=@orderNo AND OrderStatus=0", new SqlParameter("@tradeNo", tradeNo), new SqlParameter("@orderNo", outTradeNo)); Response.Write("success"); } }这里的关键是Response.Write("success")必须输出纯文本success,不能有任何多余的HTML或换行,否则支付宝会一直重发通知,造成重复处理。我在一次调试中踩过这个坑,页面因为是MVC模板带了页头页脚,输出了一堆HTML,支付宝那边就疯狂重试了12次。
5. 避坑指南:运行环境兼容性、权限控件与中文乱码的五个排查点
5.1 现象:Visual Studio 2013无法打开项目
原因:项目文件.csproj可能是旧版本格式,或者是用更高版本VS保存过,导致VS2013加载时提示“不兼容”。
解决:用记事本打开.csproj文件,检查<Project ToolsVersion>节点。如果是12.0,VS2013可以正常打开;如果是14.0或更高,需要改成12.0并删除项目中的packages.config里高版本依赖项。同时确认目标框架是.NET Framework 4.5,因为VS2013默认支持的最高版本就是4.5.1。
5.2 现象:附加数据库时报“数据库文件版本高于当前实例”
原因:SQL Server 2008R2的数据库文件(.mdf)可以通过低版本创建,但高版本创建的数据库文件,低版本实例无法直接附加。
解决:如果只有高版本数据库的备份文件(.bak),在SQL Server 2012及以上版本还原后,用“生成脚本”功能导出全部表结构和数据,再在2008R2上执行脚本重建。更省事的方式是直接用VS2013自带的数据库项目(SQL Server Database Project)来管理结构。这个代码包自带的数据库文件,一般可以直接附加,但如果附加失败,按上面步骤处理。
5.3 现象:页面加载报“未能加载文件或程序集 AjaxControlToolkit”
原因:项目的Bin目录缺少AjaxControlToolkit.dll,或者版本与项目引用的版本不一致。
解决:在NuGet包管理器中重新安装对应版本的AjaxControlToolkit。具体操作是右键项目 → 管理NuGet程序包 → 搜索“AjaxControlToolkit” → 选择与项目匹配的版本安装。安装完成后,确认Web.config中的<controls>节点引用了正确命名空间。
5.4 现象:中文数据显示为乱码
原因:数据库排序规则与页面编码不一致,或者连接字符串中未指定字符集。
解决:在Web.config的连接字符串中加上Character Set=utf8(如果使用MySQL)或确保数据库排序规则为Chinese_PRC_CI_AS(SQL Server)。同时确认页面<meta charset="utf-8">设置正确,并且Response.Charset和Response.ContentEncoding已设置为UTF-8。
<connectionStrings> <add name="ConnStr" connectionString="server=.;database=Shop;uid=sa;pwd=123456;Character Set=utf8;" providerName="System.Data.SqlClient" /> </connectionStrings>5.5 现象:后台权限控件不起作用,所有用户都能访问管理页面
原因:UCDroplistPermission.ascx和UCPermission.ascx控件的权限判断逻辑依赖Session中的用户角色值,如果Session名与代码中读取的键名不一致,权限控制会失效。
解决:全局搜索Session["Admin"]或Session["UserRole"]等键名,确认与登录页面写入的Session键完全一致。另外检查这些控件在.aspx页面中的注册方式和位置,确保它们在页面加载的生命周期早期就完成权限绑定。
// 权限控件加载逻辑 protected void Page_Load(object sender, EventArgs e) { // 检查当前登录用户是否具有访问权限 if (Session["Admin"] == null) { Response.Redirect("/Admin/Login.aspx?returnUrl=" + Request.Url.PathAndQuery); return; } // 从数据库读取用户权限列表并绑定到下拉控件 int adminId = Convert.ToInt32(Session["AdminId"]); ddlPermission.DataSource = DbHelper.ExecuteDataTable( "SELECT PermId, PermName FROM Permissions WHERE AdminId=@aid", new SqlParameter("@aid", adminId)); ddlPermission.DataBind(); }这里补一句:老项目的Session依赖很重,如果部署时使用多台服务器做负载均衡,需要把Session模式改为StateServer或SQLServer,否则会出现用户登录后操作被跳回登录页的情况。这套代码没有内置Redis Session共享,生产环境部署时要特别注意。
6. 小程序商城端调试技巧:从解压到在微信开发者工具里跑通
6.1 小程序工程的结构与页面渲染逻辑
随包赠送的2048-小程序.zip是一个微信小程序工程,解压后能看到典型的微信小程序目录结构:app.js(全局逻辑)、app.json(全局配置)、pages目录下是各个页面。这个工程本身是一个2048小游戏,但它的项目配置和请求封装模式,可以直接套用到商城小程序的开发里。
// 小程序 app.js 全局初始化逻辑 App({ globalData: { // 商城API接口地址,替换成你自己部署的后端域名 apiBaseUrl: 'http://localhost:8080', // 登录后存储的用户令牌 token: '', userInfo: null }, onLaunch: function () { // 尝试从本地缓存恢复登录状态 const token = wx.getStorageSync('token'); if (token) { this.globalData.token = token; } }, // 统一的网络请求封装,自动携带token request: function (url, method, data, successCallback, failCallback) { wx.request({ url: this.globalData.apiBaseUrl + url, method: method || 'GET', data: data || {}, header: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.globalData.token }, success: function(res) { // 业务状态码为0表示成功,非0表示业务错误 if (res.data.code === 0) { successCallback(res.data.data); } else { wx.showToast({ title: res.data.msg || '请求失败', icon: 'none' }); if (failCallback) failCallback(res.data); } }, fail: function(error) { console.error('Request Error:', error); wx.showToast({ title: '网络异常,请稍后重试', icon: 'none' }); if (failCallback) failCallback(error); } }); } });这段代码里封装了request方法,统一处理请求头、业务状态码和错误提示。商城小程序里的商品列表、登录、下单这些页面,直接调用this.request就行,不需要每个页面再写一遍wx.request。
6.2 用微信开发者工具导入和调试
微信开发者工具是官方调试器,安装后直接导入解压后的工程目录,选择“小程序项目”,填写AppID。没有AppID的话,可以点“测试号”创建临时AppID,功能上基本不受限制。
# 解压赠送的小程序工程到工作目录 cd D:\projects unzip 2048-小程序.zip -d my-mall-miniapp # 用微信开发者工具打开my-mall-miniapp目录 # 在工具右上角选择 "详情" -> "本地设置" -> 勾选"不校验合法域名"调试时最重要的一步:勾选“不校验合法域名”。开发阶段后端API如果用的是http://localhost或者局域网IP,不勾这个选项,wx.request会被拦截报错。
6.3 把2048小程序改造为商城页面的切入点
把2048小程序工程改造成商城小程序,核心工作集中在三个方向:
- 替换
pages/index/index页面的UI,把数字格子布局改为商品卡片列表。 - 在
app.js的request方法中把apiBaseUrl改成实际部署的接口地址,并确保后端接口返回{code:0,data:...}格式。 - 新增
pages/cart/cart和pages/order/order页面,用这个封装的request方法调用商城接口。
// 改造后的商品列表页面核心逻辑 Page({ data: { products: [], loading: false, pageIndex: 1, pageSize: 10 }, onLoad: function () { this.loadProducts(); }, // 调用app.js封装的request方法加载商品列表 loadProducts: function () { if (this.data.loading) return; this.setData({ loading: true }); const app = getApp(); app.request( '/api/Product/GetPageList', 'GET', { pageIndex: this.data.pageIndex, pageSize: this.data.pageSize }, (data) => { this.setData({ products: data.list, loading: false }); }, () => { this.setData({ loading: false }); } ); }, // 下拉刷新 onPullDownRefresh: function () { this.setData({ pageIndex: 1 }); this.loadProducts(); wx.stopPullDownRefresh(); } });改造的难点不在代码量,而在后端接口的返回格式统一。商城后端如果返回的是DataTable序列化后的{“list”:[...]}格式,前端需要适配;如果返回的是老式ASP.NET的JSON序列化格式,字段名大小写也要处理好。
6.4 本地联调的常用手段
小程序不能直接访问localhost,因为开发者工具运行在你电脑上,localhost指向你电脑,但真机预览时,localhost指向的是手机自身。所以本地联调时,一般通过以下方式:
- 把
apiBaseUrl改成电脑的局域网IP,如http://192.168.1.100:8080,手机和电脑连同一WiFi就能访问。 - 使用微信开发者工具自带的“真机调试”功能,扫码后手机和电脑建立通道,请求会转发到开发者工具,开发者工具再访问局域网IP。
- 抓包查看请求参数时,老项目里习惯在代码里直接
Response.Write返回JSON字符串,没有状态码包裹,开发小程序端时需要注意这种裸数据格式。
从那次把2048小游戏改成商城小程序之后,我再拿到类似的项目,第一件事就是先把app.js里的请求封装和后端接口文档对照一遍,确认参数格式统一,再动手改页面。这套商城源码加小程序工程配合起来,前后端都能练到,作为学习素材确实值。希望这次的拆解对你上手这套源码有帮助。
本文还有配套的精品资源,点击获取