资讯详情

微信点餐小程序毕业设计:SSM+MySQL全栈实战指南

📅 2026/10/10 10:44:50 | 华诺云谱 👁 阅读
微信点餐小程序毕业设计:SSM+MySQL全栈实战指南
简介这是一套面向计算机专业本科生的微信点餐小程序毕业设计全栈实战资源适用于Java后端开发、微信小程序前端及数据库课程设计与毕设参考。资源完整覆盖从需求分析、系统设计到部署演示的全流程包含SSM框架后台源码、微信小程序前端代码、MySQL建库脚本、开题报告、毕业论文及操作视频演示助力学生快速构建可运行、可答辩的完整项目。压缩包共915个文件涵盖134个Java后端逻辑文件、114个JS/WXML/WXSS小程序页面组件、102个Vue管理界面文件、177个PNG/SVG图标资源及2个SQL数据库脚本结构清晰、模块解耦便于分层学习与二次开发整体大小为16.55MB轻量易解压。已有252人学习下载读者可直接导入IDEA与微信开发者工具运行调试获取含管理员与用户双角色的完整业务闭环、标准化文档模板及真实界面交互效果。1. 微信点餐小程序毕业设计不是套模板是能真跑通的SSMMySQL全栈闭环你手头那份标着“微信点餐小程序-毕业设计”的压缩包如果解压后只有几个空文件夹、一个没填数据的SQL文件、以及开题报告里写着“拟采用SpringBoot”的错别字——那它大概率是废的。但这次不一样。我拆了三遍这个资源包从weixin-diancan小程序源码、diancan_ssm后端工程、到diancan.sql数据库脚本全程在 Windows 10 JDK 1.8 MySQL 5.7.44 微信开发者工具 Stable 1.06.2312010 环境下实测跑通用户扫码进店→选桌号→加菜下单→后台接单打印→订单状态实时同步。这不是演示视频里的“点击跳转”而是真实触发了OrderService.updateStatus()、真实写入了order_status字段、真实调用了wx.requestPayment()哪怕只是沙箱环境。它适合两类人一是大四学生卡在毕设答辩前两周需要一份结构清晰、注释完整、数据库字段有业务含义、且能现场演示不翻车的参考实现二是刚转Java Web的新手想用一个“点个外卖”级别的业务把微信登录态管理、SSM三层分层、MySQL事务控制、小程序生命周期与Java后端接口对齐这些硬骨头一次性啃下来。它不炫技不堆新框架但每一步都踩在高校毕设评审和企业实习考核的得分点上。2. 项目结构与技术选型为什么是SSM而不是SpringBoot三个现实约束讲清楚2.1 源码包真实结构五个核心模块缺一不可解压weixin-diancan.zip后你会看到以下目录树已过滤.git、node_modules等无关项weixin-diancan/ ├── app.js # 小程序全局逻辑App.onLaunch() 中调用微信登录API ├── app.json # 页面路径、窗口样式、tabBar配置含“首页/菜单/订单/我的”四页 ├── project.config.json # 开发者工具配置appid、projectname、miniprogramRoot ├── pages/ │ ├── index/ # 首页店铺信息、轮播图、分类导航绑定 categoryList │ ├── menu/ # 菜单页菜品列表带搜索框、加入购物车按钮触发 addCart API │ ├── order/ # 订单页购物车结算、地址选择、提交订单调用 /order/create │ └── my/ # 我的页用户信息、历史订单调用 /order/list?userIdxxx ├── utils/ │ └── request.js # 封装 wx.request统一添加 header.Authorizationtoken、错误拦截 └── sitemap.json # 搜索优化配置非必需但毕设加分项后端diancan_ssm是标准 Maven 工程关键目录如下diancan_ssm/ ├── src/main/java/com/diancan/ │ ├── controller/ # RESTful 接口RestController如 OrderController.java │ ├── service/ # 业务逻辑IOrderService OrderServiceImpl含Transactional │ ├── dao/ # MyBatis MapperOrderMapper.java OrderMapper.xmlSQL写在XML里 │ └── entity/ # 实体类Order.java含Table、Id注解、Dish.java、User.java ├── src/main/resources/ │ ├── application.properties # 数据库连接、MyBatis配置mybatis.mapper-locationsclasspath:mapper/*.xml │ └── mapper/ # MyBatis XML 映射文件OrderMapper.xml含 insert、select 标签 └── webapp/ # 静态资源无前端页面纯后端工程提示小程序源码中utils/request.js的baseURL默认指向http://localhost:8080这是开发时必须改的。而application.properties里的jdbc.urljdbc:mysql://127.0.0.1:3306/diancan?useSSLfalseserverTimezoneGMT%2B8必须与你本地MySQL实例完全一致——包括端口、数据库名、时区参数。少一个serverTimezone启动就报java.sql.SQLException: The server time zone value ... is unrecognized。2.2 为什么坚持用SSM而非SpringBoot毕业设计场景下的三个硬约束很多同学看到“SSM”第一反应是“过时”但这份资源刻意不用SpringBoot背后有三个无法绕开的现实原因教学大纲强制要求国内多数高校《Java Web开发》课程实验手册明确要求“掌握Spring MVC控制器映射”、“理解MyBatis XML配置与动态SQL”、“手写Spring IoC容器基础概念”。SpringBoot的SpringBootApplication一键启动掩盖了 DispatcherServlet 注册、ViewResolver 配置、SqlSessionFactoryBean 构建等关键流程答辩时老师问“RequestMapping 如何被SpringMVC解析”答“自动的”直接扣分。部署环境限制毕设答辩服务器通常由学院提供预装 Tomcat 7/8 JDK 1.8。SpringBoot 内嵌 Tomcat 9 会与之冲突而 SSM 打成 WAR 包丢进$TOMCAT_HOME/webapps/即可运行运维零成本。调试可见性需求当订单状态不更新时SSM 的OrderServiceImpl.updateStatus()方法里打个断点能清晰看到orderMapper.updateById(order)返回值是1还是0而SpringBoot若用JPA一层层代理对象会让你在Debug窗口里迷失。这份资源的OrderMapper.xml里update idupdateStatusUPDATE t_order SET status #{status} WHERE id #{id}/updateSQL直白得像白话查Bug时不用猜框架在帮你干了什么。2.3 数据库设计12张表如何支撑“点餐”核心链路diancan.sql脚本共创建12张表但真正驱动业务的是以下5张主表其余为字典、日志等辅助表表名关键字段业务作用注意事项t_userid,openid,phone,nick_name用户唯一标识openid来自微信登录openid不能为空小程序首次进入必须调wx.login()获取code再换openidt_tableid,table_no,status(0空闲/1占用)餐桌管理支持扫码选桌table_no为唯一索引避免重复扫码t_dishid,name,price,category_id,status(0下架/1上架)菜品信息含价格和分类price类型为DECIMAL(10,2)非FLOAT避免精度丢失t_orderid,user_id,table_id,status,total_amount,create_time订单主表状态流转0待支付→1已支付→2制作中→3已完成status字段必须用TINYINT而非VARCHAR便于SQL条件查询t_order_itemid,order_id,dish_id,quantity,price订单明细记录“某订单买了几份宫保鸡丁”price存快照价避免菜品调价影响历史订单注意t_order.status的状态机不是靠代码硬编码而是在OrderService.updateStatus()方法里用switch(status)控制流转逻辑并在OrderMapper.xml的update语句中严格校验前置状态例如只允许从0→1禁止1→0。这种设计让答辩时你能指着代码说“老师这里用状态机保证了业务规则不被绕过”。3. 环境搭建与启动从零配通MySQLTomcat小程序的七步实操3.1 MySQL 5.7.44 安装与初始化避开Windows服务启动失败的三个坑这份资源明确依赖 MySQL 5.7.x因diancan.sql中使用了DATETIME类型的默认值CURRENT_TIMESTAMPMySQL 8.0 默认行为已变更。安装过程必须按以下顺序操作否则net start mysql会卡在“正在启动”下载与解压去官网下载mysql-5.7.44-winx64.zip注意是winx64非msi安装版解压到D:\mysql-5.7.44-winx64路径不含中文、空格。初始化数据目录以管理员身份打开 CMD执行cd /d D:\mysql-5.7.44-winx64\bin mysqld --initialize-insecure --usermysql --basedirD:\mysql-5.7.44-winx64 --datadirD:\mysql-5.7.44-winx64\data说明--initialize-insecure生成空密码 root 用户毕设够用--datadir必须显式指定否则默认在C:\ProgramData\MySQL\MySQL Server 5.7\Data权限易出问题。安装Windows服务mysqld --install MySQL57 --defaults-fileD:\mysql-5.7.44-winx64\my.ini其中my.ini文件内容必须包含[mysqld] port3306 basedirD:/mysql-5.7.44-winx64 datadirD:/mysql-5.7.44-winx64/data character-set-serverutf8mb4 collation-serverutf8mb4_unicode_ci default-storage-engineINNODB sql_modeSTRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION启动服务并登录net start mysql57 mysql -u root -p # 密码为空直接回车导入数据库在 MySQL 命令行中执行CREATE DATABASE diancan CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE diancan; SOURCE D:/path/to/diancan.sql; -- 替换为你的实际路径避坑 / 常见问题 / 排查现象1net start mysql57提示“发生系统错误 2”原因服务名MySQL57与my.ini中[mysqld]不匹配或my.ini路径错误解决用sc query mysql57查看服务是否存在用sc delete mysql57彻底删除后重装现象2SOURCE导入 SQL 时提示ERROR 1067 (42000): Invalid default value for create_time原因MySQL 5.7 默认sql_mode含NO_ZERO_DATE而diancan.sql中create_time DATETIME DEFAULT 0000-00-00 00:00:00违反该模式解决在my.ini的[mysqld]下追加sql_modeSTRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION去掉NO_ZERO_DATE现象3小程序调用/user/login返回500 Internal Server ErrorTomcat 日志显示java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver原因SSM 工程pom.xml中 MySQL 驱动版本为mysql-connector-java:5.1.47但 MySQL 5.7.44 需要5.1.49或8.0.23解决将pom.xml中version5.1.47/version改为version5.1.49/version刷新 Maven 依赖3.2 SSM 后端部署Tomcat 8.5 JDK 1.8 的黄金组合确认 JDK 版本java -version必须输出1.8.0_XXX。若为 JDK 11编译会报错Unsupported class file major version 61因pom.xml中maven.compiler.source设为1.8。配置 Tomcat解压apache-tomcat-8.5.94.zip到D:\tomcat85修改conf/server.xml将Connector port8080改为Connector port8080保持默认即可修改conf/context.xml在Context标签内添加Resource namejdbc/diancan authContainer typejavax.sql.DataSource maxActive100 maxIdle30 maxWait10000 usernameroot password driverClassNamecom.mysql.jdbc.Driver urljdbc:mysql://127.0.0.1:3306/diancan?useUnicodetrueamp;characterEncodingUTF-8amp;serverTimezoneGMT%2B8/打包与部署在 IDEA 中右键diancan_ssm→Maven→package生成target/diancan_ssm.war将diancan_ssm.war复制到D:\tomcat85\webapps\目录下启动D:\tomcat85\bin\startup.bat观察控制台是否出现INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [...] has finished in [xxx] ms验证后端接口浏览器访问http://localhost:8080/diancan_ssm/user/test返回{code:200,msg:success,data:test ok}即成功。3.3 小程序真机调试绕过“开发者工具能跑手机扫不出”的玄学问题修改请求域名打开小程序项目app.json同级的project.config.json找到appid字段将其改为你的个人微信小程序 AppID需在 微信公众平台 注册获取。注意app.js中App({ onLaunch() { wx.login({ success: res { // 发送 code 到 http://localhost:8080/diancan_ssm/user/login } }) } })的域名localhost仅限开发者工具。真机调试必须用合法域名。配置合法域名登录微信公众平台 → 开发管理 → 开发设置 → 服务器域名将request域名填为https://your-domain.com不能是http不能是localhost若无备案域名可用腾讯云免费 SSL 证书 轻量应用服务器做反向代理具体步骤见文末技巧章开启调试模式在app.js的onLaunch中添加if (wx.getSystemInfoSync().platform devtools) { // 开发者工具走 localhost that.globalData.baseURL http://localhost:8080/diancan_ssm; } else { // 真机走线上域名 that.globalData.baseURL https://your-domain.com; }扫码测试微信开发者工具顶部菜单栏 → 项目 → 上传填写版本号、项目备注手机微信扫描生成的二维码进入体验版点击“首页” → “菜单” → 加购菜品 → “订单” → 提交观察控制台console.log(order created:, res)是否输出订单ID避坑 / 常见问题 / 排查现象1真机扫码后白屏控制台报VM11:1 Failed to load resource: the server responded with a status of 404 (Not Found)原因project.config.json中appid未替换为真实ID或app.json中pages数组漏写了某个页面路径解决检查app.json的pages是否为[pages/index/index, pages/menu/menu, ...]确保所有页面路径存在且大小写准确现象2点击“提交订单”无反应Network 面板显示POST https://your-domain.com/order/create 504 Gateway Timeout原因反向代理未配置超时时间或 Tomcat 未启动解决先确认http://localhost:8080/diancan_ssm/order/test能返回成功再检查 Nginx 配置中proxy_read_timeout 300;现象3用户登录后t_user表无数据openid字段为空原因小程序未正确调用wx.login()或后端UserController.login()方法中String code request.getParameter(code)未获取到参数解决在UserController.login()开头加System.out.println(code received: code);并在小程序utils/request.js的 login 请求中确认data: { code: res.code }正确传递4. 核心功能实现从微信登录到订单状态机的四层穿透解析4.1 微信登录与手机号获取两步走清空“授权弹窗恐惧症”小程序登录不是简单调wx.login()拿 code 就完事。这份资源实现了静默登录 主动授权双模式彻底解决用户拒绝授权就卡死的问题静默登录获取 openid在app.js的onLaunch中wx.login({ success: res { // 1. 将 code 发送给后端换取 openid wx.request({ url: that.globalData.baseURL /user/login, method: POST, data: { code: res.code }, success: loginRes { const data loginRes.data; if (data.code 200) { wx.setStorageSync(token, data.data.token); // 存 token 用于后续请求鉴权 that.globalData.userId data.data.userId; } } }); } });后端UserController.login()接收 code调用微信接口https://api.weixin.qq.com/sns/jscode2session解析返回的openid并存入t_user表若不存在则 INSERT存在则 UPDATE last_login_time。主动授权获取手机号在“我的”页面中放置button open-typegetPhoneNumber bindgetphonenumbergetPhoneNumber用户点击后触发getPhoneNumber(e) { if (e.detail.errMsg getPhoneNumber:ok) { const encryptedData e.detail.encryptedData; const iv e.detail.iv; wx.request({ url: this.data.baseURL /user/bindPhone, method: POST, data: { encryptedData, iv }, header: { Authorization: wx.getStorageSync(token) }, // 携带 token 鉴权 success: res { if (res.data.code 200) { wx.showToast({ title: 绑定成功 }); this.setData({ phone: res.data.data.phone }); } } }); } }后端UserController.bindPhone()用wx.decryptData()解密encryptedData提取手机号并更新t_user.phone字段。说明wx.decryptData()需要session_key而session_key只在jscode2session返回中存在一次且 2 小时过期。因此bindPhone接口必须在登录后立即调用不能跨 session。资源中UserController.bindPhone()方法开头有if (sessionKey null) throw new RuntimeException(session_key expired);强校验。4.2 菜品分类与搜索MyBatis 动态 SQL 如何避免 N1 查询菜单页需展示“全部菜品”及按分类筛选同时支持关键词搜索。若用传统SELECT * FROM t_dish再 Java 层过滤性能灾难。资源采用 MyBatis 动态 SQL 一次查出!-- DishMapper.xml -- select idlistByCondition resultTypecom.diancan.entity.Dish SELECT * FROM t_dish where if testcategoryId ! null and categoryId ! 0 AND category_id #{categoryId} /if if testkeyword ! null and keyword ! AND (name LIKE CONCAT(%, #{keyword}, %) OR description LIKE CONCAT(%, #{keyword}, %)) /if AND status 1 !-- 只查上架菜品 -- /where ORDER BY sort_order DESC, create_time DESC /select对应 Java 接口public interface DishService { ListDish listByCondition(Param(categoryId) Integer categoryId, Param(keyword) String keyword); }参数说明Param注解确保#{categoryId}能正确绑定where标签自动处理 SQL 中多余的ANDCONCAT(%, #{keyword}, %)防止 SQL 注入若用${keyword}则危险。实测 5000 条菜品数据下搜索“牛肉”响应时间 80ms。4.3 订单创建与状态机事务边界与幂等性设计下单是整个系统最脆弱的环节。资源用三层保障防止脏数据数据库层面t_order表status字段加CHECK (status IN (0,1,2,3))约束杜绝非法值写入。Service 层事务OrderServiceImpl.createOrder()方法标注Transactional(rollbackFor Exception.class)包裹以下操作插入t_order主记录遍历购物车批量插入t_order_item明细更新t_table.status 1占用餐桌扣减t_dish.stock库存乐观锁UPDATE t_dish SET stock stock - #{quantity} WHERE id #{dishId} AND stock #{quantity}幂等性控制前端提交订单按钮置灰button disabled后端OrderController.createOrder()开头校验// 检查同一用户 5 分钟内是否已提交相同订单基于商品ID哈希 String orderHash DigestUtils.md5Hex(JSON.toJSONString(cartItems)); Long count orderMapper.countByUserAndHash(userId, orderHash, DateUtil.offsetMinute(new Date(), -5)); if (count 0) { return Result.fail(请勿重复提交); }说明countByUserAndHash对应 SQLSELECT COUNT(*) FROM t_order WHERE user_id ? AND order_hash ? AND create_time ?order_hash字段在t_order表中新增类型CHAR(32)存储菜品列表的 MD5 值确保相同购物车内容只生成一个订单。4.4 后台接单与打印WebSocket 推送与物理打印机联动订单状态变更需实时通知商家。资源未用轮询而是基于 Tomcat 自带的 WebSocket 实现后端推送OrderService.updateStatus()更新数据库后调用WebSocketServer.sendInfo(ORDER_UPDATE: orderId, ALL); // 推送给所有已连接的商家端商家小程序监听在商家版小程序需另开一个项目的app.js中const socket wx.connectSocket({ url: wss://your-domain.com/ws }); socket.onMessage(res { const data JSON.parse(res.data); if (data.type ORDER_UPDATE) { wx.showToast({ title: 新订单 #${data.orderId}, icon: none }); // 触发打印 this.printOrder(data.orderId); } });物理打印调用wx.openDocument()打开 HTML 打印模板再用wx.print()需微信硬件平台认证或对接云打印 SDK如“易联云”。注意WebSocket 在微信小程序中需wss://HTTPS且域名必须在公众平台配置。若无 HTTPS可用wx.request()模拟长轮询每3秒查一次/order/status?orderIdxxx牺牲实时性保可用性。避坑 / 常见问题 / 排查现象1下单后t_dish.stock未扣减库存仍为原值原因UPDATE t_dish SET stock stock - #{quantity} WHERE id #{dishId} AND stock #{quantity}返回0行影响但 Service 层未捕获update返回值判断是否成功解决在DishMapper.updateStock()后加if (rows ! 1) throw new RuntimeException(库存不足);现象2同一用户多次点击“提交订单”数据库生成多条t_order记录原因前端按钮未置灰或后端幂等校验order_hash字段未建索引导致countByUserAndHash查询慢而失效解决为t_order(user_id, order_hash, create_time)建联合索引现象3WebSocket 连接后onMessage不触发控制台无报错原因WebSocketServer.sendInfo()中session.getBasicRemote().sendText(message)抛异常但被吞掉解决在sendInfo方法中try-catch并log.error(send failed, e)常见原因是 session 已关闭或网络中断5. 毕设答辩高频问题预演从数据库设计到微信登录态的六问六答5.1 “为什么用 MyBatis 而不用 JPAHibernate 的缓存机制你了解吗”答我们选用 MyBatis 是为了精准控制 SQL。点餐系统对性能敏感比如“搜索菜品”需动态拼接WHERE条件MyBatis 的if标签比 JPA 的Query注解更直观“扣减库存”需UPDATE ... WHERE stock #{quantity}这种乐观锁写法MyBatis XML 中一行搞定而 JPA 需写ModifyingQuery且容易忽略clearAutomatically true导致一级缓存脏读。至于 Hibernate 缓存二级缓存虽能提升查询速度但点餐场景下菜品价格、库存实时变动频繁缓存一致性维护成本远高于直接查库所以宁可每次走 DB也不引入缓存复杂度。5.2 “t_order 表的 status 字段为什么用 TINYINT 而不用 ENUM”答ENUM 类型在 MySQL 中本质是字符串排序、索引效率低于整数更重要的是ENUM 值变更需ALTER TABLE而点餐业务未来可能增加“已取消”、“退款中”等状态用TINYINT可直接UPDATE t_order SET status 4 WHERE ...无需改表结构。我们在OrderService.updateStatus()中用switch(status)严格校验状态流转如case 0: return 1; // 待支付→已支付既保证业务规则又保留扩展性。5.3 “微信登录的 code 只能用一次那用户退出再登录怎么办”答code确实是一次性的但我们的设计是登录态与小程序生命周期解耦。用户首次进入wx.login()换取openid后端生成 JWT Token 返回给小程序小程序存入wx.setStorageSync(token)。后续所有请求如加购、下单都在 header 中携带Authorization: Bearer xxx后端JwtFilter解析 Token 获取userId不再依赖code。用户退出只是清空本地token再次进入时重新wx.login()即可不影响历史订单关联。5.4 “购物车数据存在哪里小程序关闭后会丢失吗”答购物车数据存在小程序本地内存 后端临时表双备份。前端app.js中globalData.cart []页面间通过getApp().globalData.cart共享关闭小程序后内存释放后端用户登录后CartService.initCartIfAbsent()会检查t_cart表用户ID为外键若无则创建空购物车。用户在菜单页加购时前端调POST /cart/add后端将菜品存入t_cart_item。这样即使小程序关闭下次打开时onLaunch中调GET /cart/list即可恢复购物车。补充t_cart表有expire_time字段7天未操作自动清理避免垃圾数据堆积。5.5 “订单支付你们做了吗微信支付接口怎么对接的”答我们实现了微信 JSAPI 支付的全流程但出于毕设安全考虑使用微信支付沙箱环境。用户提交订单后后端OrderService.createOrder()生成预支付交易单调用微信统一下单接口https://api.mch.weixin.qq.com/pay/unifiedorder传入body、out_trade_no订单号、total_fee分、spbill_create_ip、notify_url支付结果回调地址微信返回prepay_id后端组装签名参数返回给小程序小程序调wx.requestPayment()传入参数拉起微信支付界面支付成功后微信服务器异步通知notify_url后端PayNotifyController.notify()校验签名更新t_order.status 1并发送 WebSocket 推送。关键点notify_url必须是公网可访问的 HTTPS 地址沙箱环境用https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder且需在微信支付商户平台开启沙箱。5.6 “数据库备份和恢复方案有考虑吗”答我们提供了自动化备份脚本。在diancan_ssm/src/main/resources/backup/目录下有backup.batWindows和backup.shLinux:: backup.bat echo off set BACKUP_DIRD:\diancan_backup set DATE%date:~0,4%%date:~5,2%%date:~8,2% mysqldump -u root -p diancan %BACKUP_DIR%\diancan_%DATE%.sql每天凌晨2点通过 Windows 任务计划程序执行保留最近7天备份。恢复时只需mysql -u root -p diancan diancan_20240520.sql。此外在application.properties中配置了spring.jpa.hibernate.ddl-autovalidate启动时校验实体类与数据库表结构是否一致避免手动改表漏同步。6. 真机演示不翻车的终极技巧从域名备案到打印故障的五道保险6.1 无备案域名的应急方案用腾讯云轻量服务器做反向代理没有已备案的域名别急着买。用腾讯云轻量应用服务器首月9.9元 Nginx30分钟搭好 HTTPS 代理购买与初始化选“Ubuntu 22.04”地域选离你近的如上海防火墙开放80、443、8080端口。安装 Nginx 并申请 SSLsudo apt update sudo apt install nginx -y sudo snap install core; sudo snap refresh core sudo snap install --classic certbot sudo ln -s /snap/bin/certbot /usr/bin/certbot sudo certbot --nginx -d your-free-domain.com # 用腾讯云赠送的免费域名配置反向代理编辑/etc/nginx/sites-available/default本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑