简介:JAVA微信小程序商城源码加完整后台,是一套基于SpringMVC、MyBatis、Spring、Maven与MySQL构建的电商系统,面向具备一定Java基础的中级开发者、小程序学习者及需要快速搭建商城的创业团队。资源涵盖商品发布、物流管理、评价系统、优惠券、运费计算、在线客服、在线支付、在线退款、微信管理等核心模块,前端采用H5与CSS3,后台基于Bootstrap-Ace框架,前后台结构分明,便于理解和二次开发。压缩包约20.5MB,适合本地导入运行与源码研读,可用于毕业设计、课程项目或商业项目起步。该资源已有5047人学习,整体功能链完整,能帮助读者掌握SSM框架整合、微信小程序接口对接以及电商后台常见业务逻辑的实现方式。
1. 从零手写商城不如改一套SSM源码:这套微信小程序商城到底藏着什么
拿到这套源码时我刚接一个二手商城项目,客户要的正是小程序端商品、下单、支付、退款、优惠券全套。从零写至少一个月,改一套能跑的源码,一周就能上线。这套源码技术栈是SpringMVC + MyBatis + Spring + Maven + MySQL,小程序端是原生微信小程序,管理后台用bootstrap-ace,功能覆盖商品发布、物流管理、评价、优惠券、运费、在线客服、微信支付、退款、微信管理。适合三类人:有Java基础想快速落地项目的开发者、拿商城当课程设计练手的学生、接私活要快速交付的独立开发者。下面按复现顺序把每一层的改造点拆开讲。
2. 先把环境对齐:JDK、Maven、MySQL、微信开发者工具的版本选择
拿到源码第一件事不是打开IDE,而是先把环境对齐。SSM是2015到2019年间的主流组合,现在跑它最省事的方式是照着当年那套环境来,而不是用最新版强行兼容。版本不对,后面每一步都会冒出莫名其妙的报错。
2.1 这套项目对JDK、Maven和Tomcat的真实要求
pom.xml里maven-compiler-plugin通常配置的是1.8,所以JDK直接用JDK 8,不要贪新用17或21。强行上高版本会遇到两个问题:一是javax.xml.bind类被移除,跑单元测试直接NoClassDefFoundError;二是项目里如果用了旧版Lombok,和新JDK不兼容,得升级Lombok依赖。没必要一开始就给自己加戏。
Maven用3.6.3最省心。3.8以上的Maven对settings.xml里的镜像拦截规则改了,如果沿用老配置可能会导致依赖下载失败。Tomcat用8.5就行,对应Servlet 3.1规范,SpringMVC在这上面跑多年了。手头是Tomcat 9问题也不大,但要注意servlet-api的jar别和项目里打包的冲突。MySQL这块,SQL文件导入时注意字符集,建表语句一般是utf8mb4,排序规则是utf8mb4_general_ci,MySQL 5.7直接吃,如果你用8.0,要把JDBC驱动换成mysql-connector-java 8.x,并在url里加上serverTimezone=Asia/Shanghai。
| 组件 | 推荐版本 | 关键原因 |
|---|---|---|
| JDK | 1.8 | pom.xml编译目标为1.8,避免javax.xml.bind缺失 |
| Maven | 3.6.3 | 镜像源兼容性最好,依赖拉取不折腾 |
| Tomcat | 8.5 | Servlet 3.1与SpringMVC配合成熟 |
| MySQL | 5.7 | 直接兼容utf8mb4建表语句 |
2.2 数据库初始化与JDBC配置修改
数据库是整条链路最容易卡住的一步。SQL文件一般放在源码的sql目录下,文件名常见shop.sql或mall.sql。用Navicat执行时注意一个坑:如果SQL文件里带CREATE DATABASE语句,而你已经连接了某个库,整文件执行会报错。我一般先手工建一个空库,再把SQL开头的CREATE DATABASE和USE语句删掉,只执行表结构和INSERT。
配置文件在src/main/resources目录下,最常见名字是jdbc.properties,内容大概是:
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/shop?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=123456注意最后一个password,源码默认密码各式各样,有人是root,有人是123456,还有人留空。这里不改对,启动Tomcat后所有数据库操作都报Access denied。改完建议在Navicat里用同一组账号试连一次,能连通再往下一步走。
另一个容易忽略的是jdbc.url里的characterEncoding。如果SQL文件是utf8mb4,建议把这里改成characterEncoding=utf8mb4,否则用户昵称或商品标题里的emoji入库全变问号。这问题在评价系统里尤其明显,等上线后用户反馈过来再改,又要更新连接池,成本高一截。
2.3 小程序的AppID配置与开发者工具导入
小程序端目录通常是wxapp或miniprogram,导入微信开发者工具时别选错目录。选“导入项目”,把整个小程序目录选中。AppID这里有个分水岭:只是看界面,用测试号就行;要跑通支付,必须用已认证的正式小程序AppID,否则wx.requestPayment直接被拒。
导入之后第一件事是改config.js或app.js里的全局配置:
// app.js 片段 globalData: { // 小程序端所有请求都走这个baseUrl baseUrl: 'http://127.0.0.1:8080/shop-api' }这里的baseUrl要和你后端Tomcat部署路径对起来。后端项目名如果是shop,Controller的@RequestMapping里带/api前缀,那baseUrl就是http://127.0.0.1:8080/shop/api,具体要看源码里URL前缀怎么拼。
改完这两处,在开发者工具里勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”就能本地联调。注意这只是开发环境开关,上线前必须关掉,换成正式域名,细节在第6章讲。
3. 小程序端到后台的数据链路:登录、商品、下单、支付全流程
小程序商城核心链路就一条:用户打开小程序 -> 登录拿openid -> 浏览商品 -> 下订单 -> 微信支付 -> 后台发货 -> 用户确认收货评价。这条链路跑通,商城基本活了。
3.1 登录态怎么建立:wx.login换openid
小程序登录不是传统账号密码,而是用wx.login拿到临时code,再把code发给后端,后端拿code和AppID、AppSecret一起调微信jscode2session接口,换回openid和session_key。openid是用户在微信体系里的唯一ID,商城系统直接拿它对应用户表。
小程序端代码一般是:
wx.login({ success(res) { if (res.code) { wx.request({ url: app.globalData.baseUrl + '/user/login', method: 'POST', data: { code: res.code }, success: (loginRes) => { // token 后续所有请求都要带,用于识别用户身份 wx.setStorageSync('token', loginRes.data.data.token) wx.setStorageSync('userInfo', loginRes.data.data.userInfo) } }) } } })这段代码要点:code是一次性的,有效期五分钟,用完作废,所以不要缓存code,每次冷启动重新调wx.login。token是后端生成的,可以用UUID,也可以生成JWT。这套老项目大概率是UUID存在session表里。
后端接口长这样:
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @PostMapping("/login") public Result login(@RequestBody Map<String, String> params) { String code = params.get("code"); // 调微信接口,常见做法是在WxService里封装 String openid = wxService.code2Session(code); User user = userService.findOrCreateByOpenid(openid); String token = UUID.randomUUID().toString().replace("-", ""); userService.saveToken(token, user.getId()); return Result.ok().put("token", token).put("userInfo", user); } }findOrCreateByOpenid是登录关键逻辑:用户第一次来自动创建账号,第二次直接查出来。不需要注册表单,这是小程序商城的通行做法。token和user_id的关系存数据库表,项目没引入Redis就存表,token过期时间可以在表里加expire_time字段。
3.2 商品列表接口:参数、SQL、返回结构
商品列表是必然要改的模块,因为不同商城分类和筛选条件不一样。接口一般:
@GetMapping("/goods/list") public Result list(@RequestParam(defaultValue = "0") Integer categoryId, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) { PageHelper.startPage(page, size); List<Goods> goodsList = goodsService.getGoodsByCategory(categoryId); PageInfo<Goods> pageInfo = new PageInfo<>(goodsList); return Result.ok().put("list", pageInfo.getList()).put("total", pageInfo.getTotal()); }PageHelper要看pom.xml里有没有引入pagehelper依赖,没有的话就是用MyBatis手写分页。
对应的Mapper XML:
<select id="selectGoodsByCategory" resultType="com.shop.entity.Goods"> SELECT id, name, main_image, price, original_price, stock, sales FROM t_goods <where> <if test="categoryId != null and categoryId != 0"> AND category_id = #{categoryId} </if> AND status = 1 </where> ORDER BY sort_order DESC </select>这里status字段很关键。商品有上下架状态:status=1上架,status=0下架。很多人在后台点“上架”,小程序端却不显示,多半是后台商品管理的状态没存对,或者前台SQL里没过滤status。这坑出现频率非常高,所以改商品模块时先确认新商品status默认值是1。
3.3 下单与微信支付:预支付参数生成与回调验证
支付是整个商城最核心、最容易出问题的环节。流程是:小程序端提交订单 -> 后端生成订单记录 -> 后端调微信支付API生成预支付订单 -> 返回prepay_id给前端 -> 前端调wx.requestPayment -> 用户输入密码 -> 微信服务器回调后端接口通知支付结果。
小程序端发起支付:
wx.request({ url: app.globalData.baseUrl + '/order/pay', method: 'POST', data: { orderId: orderId }, success(res) { const payParams = res.data.data wx.requestPayment({ timeStamp: payParams.timeStamp, nonceStr: payParams.nonceStr, package: payParams.package, // 注意这个key是 package,不是 packages signType: payParams.signType, paySign: payParams.paySign, success() { wx.showToast({ title: '支付成功' }) }, fail(err) { console.log('支付失败', err) } }) } })后端生成预支付订单:
public Map<String, String> createPrePayOrder(String openid, String orderNo, Integer totalFee) { // 微信支付参数 String appId = wxConfig.getAppId(); String mchId = wxConfig.getMchId(); // 常见做法是用WxJava库封装 WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); request.setBody("商城订单-" + orderNo); request.setOutTradeNo(orderNo); request.setTotalFee(totalFee); // 单位是分,不是元 request.setOpenid(openid); request.setTradeType("JSAPI"); request.setSpbillCreateIp("123.12.12.12"); // notifyUrl 必须和微信支付后台配置的完全一致 request.setNotifyUrl(wxConfig.getNotifyUrl()); WxPayUnifiedOrderResult result = wxPayService.createOrder(request); // 用 result.getPrepayId() 生成前端需要的 paySign return payParams; }totalFee单位是分。这个坑几乎每个人都踩过:订单表里存的是元,比如99.00,传给微信支付时忘了乘100,结果用户只需支付99分钱。商家看了可能要骂人。我一般在金额取出时用BigDecimal乘100转成整数分,再传给支付接口。
支付回调是第二个高频坑。微信服务器支付成功后向notifyUrl发POST请求,内容是XML。后端必须验签,再返回指定XML串。如果返回格式不对,微信会认为回调失败然后反复通知,日志里就会出现重复处理同一订单的记录。
3.4 退款与售后接口的调用边界
退款接口和支付一样,需要商户证书。微信支付退款API要求用商户API证书发起请求。常见项目里,证书文件apiclient_cert.p12放在resources目录下:
wx.pay.certPath=/data/cert/apiclient_cert.p12 wx.pay.certPwd=商户号证书密码默认是商户号本身。退款金额不能大于实付金额,后台退款表单提交时要校验。这个校验一旦漏掉,用户买100块的商品,申请退款200,接口调用直接报错,用户端看到异常提示,后台日志又一团乱麻。退款成功之后还要把订单状态改成已退款,优惠券如果已经核销要退回,这两步要放在同一个事务里。
4. 后台管理系统二次开发:bootstrap-ace骨架与优惠券、运费改造
后台管理是商城项目的运营门面,也是每天都要碰的地方。这套源码后台用bootstrap-ace模板,基于Bootstrap 3的Admin模板。左侧菜单、顶部导航、内容区三块构成。它的好处是随手拿一个HTML页面复制粘贴就能扩展出新功能页,不需要复杂脚手架,因为bootstrap-ace页面就是纯HTML加JS渲染,配合jQuery和后端返回的JSON就能干活。
4.1 bootstrap-ace后台的结构:菜单、页面与权限
打开后台首页会看到sidebar、navbar、main-content三块。新增一个菜单项要做两件事:先改侧边栏HTML,把菜单链接加上;再在后端Controller加对应页面路由。
<li> <a href="javascript:void(0)" class="dropdown-toggle"> <i class="ace-icon fa fa-tag"></i> <span class="menu-text">优惠券管理</span> </a> <ul class="submenu"> <li> <a href="/admin/coupon/list"> <i class="ace-icon fa fa-caret-right"></i> 优惠券列表 </a> </li> </ul> </li>后台Controller方法一般是返回视图名:
@RequestMapping("/coupon/list") public String couponList(Model model) { List<Coupon> list = couponService.getAll(); model.addAttribute("list", list); return "admin/coupon_list"; }注意返回值取决于ViewResolver前缀后缀配置。常见配置前缀是/WEB-INF/views/,后缀.jsp,那return的字符串会去对应目录找coupon_list.jsp。
权限控制这层,很多商城后台是简单处理:登录后把用户ID和角色存session,通过SpringMVC拦截器拦截/admin/开头的请求,没登录就重定向到登录页。二次开发时,新增页面只要放在/admin/路径下,拦截器自动覆盖。我见过不少项目在这里栽过:后台页面放在其他路径,绕过拦截器直接访问,数据裸奔。
4.2 优惠券模块:表结构、发放与核销逻辑
优惠券看起来复杂,核心就两张表。一张优惠券定义表,一张用户优惠券表。
CREATE TABLE `t_coupon` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) COMMENT '优惠券名称', `type` tinyint(1) DEFAULT '1' COMMENT '1满减 2折扣', `amount` decimal(10,2) DEFAULT NULL COMMENT '减免金额/折扣', `threshold` decimal(10,2) DEFAULT NULL COMMENT '使用门槛金额', `total_count` int(11) DEFAULT '0' COMMENT '发行总量', `receive_count` int(11) DEFAULT '0' COMMENT '已领取数量', `start_time` datetime COMMENT '有效开始时间', `end_time` datetime COMMENT '有效结束时间', `status` tinyint(1) DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `t_user_coupon` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) COMMENT '用户ID', `coupon_id` int(11) COMMENT '优惠券ID', `order_id` int(11) DEFAULT NULL COMMENT '核销订单ID', `status` tinyint(1) DEFAULT '0' COMMENT '0未使用 1已使用 2过期', `receive_time` datetime COMMENT '领取时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;total_count配合receive_count判断券是否发完。用户端领取接口要两步:先判断库存有没有发完,再插入t_user_coupon。这两步中间有并发时,会超发。常见做法是给t_coupon的receive_count做乐观锁,比如UPDATE时带上旧值判断:
UPDATE t_coupon SET receive_count = receive_count + 1 WHERE id = #{couponId} AND receive_count < total_count影响行数为0说明被并发抢完了。
核销逻辑在下单时:用户勾选一张可用优惠券,订单表冗余coupon_id和优惠券抵扣金额,生成订单同时把t_user_coupon的status改为1并关联order_id。注意一个边界:订单取消时用户优惠券要退回,把status改回0、order_id置空。很多项目退款时只退了钱,忘了退券,用户投诉说优惠券消失。
4.3 运费模板改造:按区域、按件数、按重量组合
运费系统是运营价值很高的模块。设计上一般有一张模板主表和一张模板明细表。
CREATE TABLE `t_freight_template` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) COMMENT '模板名称', `type` tinyint(1) DEFAULT '1' COMMENT '1按件 2按重量 3按金额', `default_fee` decimal(10,2) DEFAULT '0' COMMENT '首件/首重费用', `default_unit` decimal(10,2) DEFAULT '0' COMMENT '首件/首重数值', `add_fee` decimal(10,2) DEFAULT '0' COMMENT '续件/续重费用', `add_unit` decimal(10,2) DEFAULT '0' COMMENT '续件/续重数值', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;明细表用来存区域规则。比如“江浙沪首重8块续重2块,其他地区首重10块续重5块”,后台运费模板页面里,每一行是一个区域规则。订单提交时,后端拿收货地址省市区去明细表匹配区域,找到对应首重续重,按商品总重量计算。匹配不到就走默认模板。
这里最大的坑是区域匹配的数据格式:有的系统存省名称,有的存行政区域代码。我比较推荐存区域代码,比如浙江省是330000,前端地址选择器用的正是这个编码,匹配起来不折腾。如果源码里存的是名称,改起来需要在后台字典表里维护编码和名称映射,工作量会多出不少。
4.4 物流管理和在线客服的接入方式
物流管理模块,源码对接的大概率是快递鸟或快递100这类第三方接口。常见配置:
kdniao.appId=你的快递鸟AppId kdniao.appKey=你的快递鸟AppKey kdniao.reqUrl=https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx在后台订单列表点“查看物流”时,后端调第三方物流查询接口返回轨迹列表。注意:物流查询接口一般有频率限制,别在每次订单列表刷新时都调,要把轨迹缓存到本地表,比如缓存两小时。否则订单量一大,账号被限流,所有订单显示“无轨迹”,运营那边会连环问为什么。
在线客服这块,源码里最常见实现有两种。一种是直接用微信原生客服能力,小程序端放button按钮,设置open-type="contact",用户点击进入微信客服会话,由绑定在微信公众平台的客服人员接待。第二种是后端接入微信客服消息接口,把用户消息转发到自建后台,客服在后台回复。源码里如果有“微信管理”菜单,多半是AppID、AppSecret、客服URL配置放在一起。二次开发时,我建议先用原生方案跑通,低成本解决基础客服需求,业务复杂了再上自建客服。
5. 上线前最容易翻车的五个地方:支付回调、物流查询、评价图片、客服会话
这套源码我前后经手过两次,每次联调阶段都被固定几个问题卡住,有的是代码问题,有的是配置问题。下面列五个最有代表性的,按“现象、原因、解决”顺序讲。
5.1 支付回调进不了Controller
现象:用户在小程序端支付成功,钱也扣了,但订单状态一直不变,停留在“待支付”。
原因:notifyUrl填的不是外网可访问的HTTPS地址,或者和微信支付后台配置不一致。微信支付规定回调地址必须是公网HTTPS,而且不能带参数。本地联调用内网穿透,但穿透域名证书不全,微信服务器验签失败就会一直重试。
解决:先把notifyUrl改成微信支付后台配置的合法域名;然后检查后端回调方法是不是没加@ResponseBody,导致返回了视图而非XML字符串;最后回调方法里处理完业务要返回固定XML:
@RequestMapping("/pay/notify") @ResponseBody public String notify(HttpServletRequest request, HttpServletResponse response) { // 先验签再处理业务 WxPayNotifyResult result = wxPayService.parseOrderNotifyResult(request); // 幂等处理:判断orderNo是否已经处理过 orderService.handlePayNotify(result.getOutTradeNo(), result.getTransactionId()); // 返回成功通知,微信收到这个XML才停止重试 return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"; }我后来每次排查都是先看Tomcat日志里有没有微信服务器的POST请求进来,有请求但报错就是代码问题,没请求就是地址或证书问题。
5.2 物流查询一直报“无轨迹信息”
现象:后台录入了快递单号,小程序端点查看物流,一直显示无轨迹。
原因:两种常见情况。一种是快递公司编码不对,顺丰是SF,圆通是YTO,后台下拉框显示的是名称,存库的必须是编码;另一种是第三方接口的签名算法没对上,请求直接被拒。
解决:在配置里打开第三方接口调试模式,把请求数据和返回结果完整打出来,核对快递公司编码。快递鸟申请时要填业务背景,个人开发者可能被拒,可以换快递100的免费接口,参数更简单,对个人开发者友好。另外,服务商免费版一般只支持最近几个月的轨迹查询,老订单查不到是正常现象,前台提示文案要写清楚。
5.3 评价图片base64入库导致数据库膨胀
现象:用户上传评价图片后只显示成功,但数据库表瞬间多出几百KB,高峰期MySQL压力上升,订单接口变慢。
原因:小程序端上传图片时直接读文件转base64,后端存进数据库text字段。图片在数据库里估值膨胀三成左右,列表查询时如果SQL没有排除大字段,每次都要把几百KB拖出来,慢是必然的。
解决:图片上传走文件接口,后端把文件存到服务器磁盘或OSS,数据库里只存图片URL。文件上传接口:
@PostMapping("/upload") public Result upload(@RequestParam("file") MultipartFile file) { // 按日期分目录,防止一个目录文件过多 String dir = "/data/upload/" + LocalDate.now().toString(); File dirFile = new File(dir); if (!dirFile.exists()) { dirFile.mkdirs(); } String fileName = UUID.randomUUID().toString().replace("-", "") + ".jpg"; file.transferTo(new File(dirFile, fileName)); String url = "https://你的域名/upload/" + LocalDate.now() + "/" + fileName; return Result.ok().put("url", url); }数据库里只存URL,列表查询接口轻很多,JVM内存压力也小。从那以后我再没在业务表里见过图片大字段。
5.4 在线客服会话接不进来
现象:线上用户点客服按钮没反应,或提示“客服当前不在线”。
原因:微信原生客服功能需要在微信公众平台绑定客服人员,客服人员要在小程序客服插件里保持登录。后台没有设置客服,或客服没登录,前端点contact就提示不在线。个人主体的小程序,部分客服能力受限,也会出现这个问题。
解决:先在微信公众平台小程序后台“客服”菜单添加客服人员;然后让客服人员在微信里打开“小程序客服助手”保持在线;最后在代码里检查按钮适配,有的老版本基础库对contact支持不完整。
5.5 access_token没缓存导致频繁报错
现象:分享海报、客服消息等功能偶尔好偶尔坏,报错“invalid credential, access_token is invalid or not latest”。
原因:微信access_token有效期7200秒,每天调用次数有限。很多源码把获取逻辑直接写在业务方法里,每次都重新请求,旧的还没过期就被新token覆盖,其他还在用旧token的业务全部失效。
解决:做本地缓存。token存Redis或数据库,key固定,过期时间7200秒,获取时先查缓存,没有或过期再调微信接口:
public synchronized String getAccessToken() { String token = cacheService.get("wx_access_token"); if (token != null) { return token; } // 调微信接口获取新token String newToken = wxService.fetchAccessToken(); cacheService.set("wx_access_token", newToken, 7000); // 比7200少200秒,留余量 return newToken; }用数据库做缓存时注意加锁,防止多线程同时刷新。从那以后我所有微信项目都强制检查access_token缓存这一步。
6. 把源码改造成自己的项目:包名替换、打包部署、HTTPS校验一条龙
6.1 全局包名替换三步走
源码里的包名通常是com.shop或com.mall,是上一手项目留下的痕迹。改包名不只是为了好看,是避免以后别人一眼看出这是拿现成代码改的。先在文件管理器里复制整个项目一份再动,不要改造原目录。然后分三步走:第一步在IDEA里选中java根目录,右键Refactor -> Rename,把所有包名改成你的域名反写;第二步全局替换import语句和XML里出现的旧包名;第三步改pom.xml里finalName和你自己的artifactId。
# 全局替换示例,适合在服务器上快速替换配置文件里的旧包名 grep -rl "com.shop" --include="*.java" --include="*.xml" . | xargs sed -i 's/com.shop/com.yourdomain.mall/g'6.2 Maven打包与Tomcat部署
打包命令:
mvn clean package -DskipTests产物在target目录下,是个war包。把它放进Tomcat的webapps目录,启动Tomcat,看日志。部署后验证三件事:数据库连接是否通、启动日志有没有SQL异常、接口是否返回正常数据。
curl -X GET "http://127.0.0.1:8080/shop/api/goods/list?page=1&size=10"返回JSON数据说明后端正常。如果404或500,先看catalina.out日志,大部分问题是root路径和context-path不对齐。
6.3 合法域名与HTTPS转发校验
上线前最后一步,在微信公众平台小程序后台把request合法域名配成正式域名。微信要求必须是HTTPS,所以服务器要配SSL证书,常见做法用Nginx做443端口转发到Tomcat的8080。这里有一个容易出事的点:Nginx转发后支付回调路径变了。配置location规则时,路径要完整透传,不要重写。
server { listen 443 ssl; server_name yourdomain.com; ssl_certificate /data/ssl/yourdomain.pem; ssl_certificate_key /data/ssl/yourdomain.key; location /shop-api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; } }配置完用浏览器访问一下HTTPS地址,确认证书有效,再去小程序后台保存合法域名,整个链路才算闭合。
微信小程序商城这套源码,说到底是一个能跑通的骨架,真正值钱的是你在上面填的细节:优惠券怎么防超发、图片上传怎么不拖垮数据库、支付回调怎么保证幂等。上面这些坑,是我前后两次接手同类项目攒下来的血泪经验。从那以后我每次拿到这类源码项目,都强制先走一遍环境对齐、数据链路梳理、避坑清单排查这三步,不急着跑业务逻辑。按这套流程去复现这份源码,你踩的坑会少一大半。希望帮到你。
本文还有配套的精品资源,点击获取