简介一套用于企业内部活动积分管理的微信小程序完整源码覆盖成员登录、活动列表、完成活动、积分兑换等前台操作以及管理员发布活动、查看完成情况、积分统计排行、活跃度排行、历史积分与兑换记录等后台功能适合毕业设计、课程设计或需要搭建积分激励场景的小程序开发者参考。压缩包包含 2000 个文件约 31.49MB以 png/gif/svg 图片素材、css/scss/less 样式、html 页面、js 脚本等前端资源为主体另有 44 个 java 源码文件、1 个 sql 数据库脚本前端基于 uni-app/原生小程序后端支持 Java/PHP数据库为 MySQL 5.7。其中还收录了设计文档、部署文档、需求/演示与 project 工程文件可帮助快速理解会员登录、活动发布、积分兑换等核心流程的实现细节并对照 sql 脚本完成本地环境搭建。已有 63 人学习/下载适合从零梳理积分小程序前后端逻辑、扩展管理后台的开发者参考。1. 企业活动积分小程序这套源码包到底能解决什么问题企业活动积分小程序这类源码包我在外包和毕设辅导里见得太多了。它不是一个多复杂的架构而是一条把微信小程序端、后端接口、MySQL 数据存储串起来的完整链路员工在小程序里签到、答题、参与活动赚取积分管理员在后台维护活动和积分流水积分可以兑换礼品。标题里的“完整前后端mysqlLW”LW 在毕设语境里通常指“论文”或“设计文档”也就是说这套包不仅能跑还带着能写进答辩材料的需求说明和设计思路。适合三类人做毕业设计的学生、公司内部要做积分活动但不想从零搭架的开发以及想弄明白微信小程序前后端怎么交互的初学者。我的判断是这套源码最难的地方不在读代码而在把本地环境跑通。下面从目录结构开始按我实际接手这类项目的顺序拆给你看。2. 看懂目录再动手前后端分离结构与四张核心数据表2.1 从 zip 到可运行目录构成与先看哪三个文件拿到一个“企业活动积分小程序”压缩包先不要急着双击导入微信开发者工具先把目录结构列出来。常见结构长这样不同版本的包可能把小程序端叫miniprogram或wxapp$ unzip 企业活动积分小程序.zip -d activity-points $ cd activity-points $ tree -L 2 -d . ├── miniprogram │ ├── pages │ ├── utils │ └── app.js ├── server │ ├── src │ └── pom.xml ├── sql │ └── activity_points.sql └── LW └── 设计文档.docx如果你的 zip 解压出来中文目录乱码先检查是不是文件名编码问题。Windows 上压缩的 zip 用 macOS 自带的归档工具解压经常出现乱码这种情况我一般用 7-Zip 或命令行重新解压不要硬解。否则后面文件路径对不上微信开发者工具直接报找不到项目。我拿到这种包会先按这个顺序读三个文件第一sql目录下的.sql文件看建表语句和初始数据。第二server里的application.yml确认数据库名、端口、接口前缀。第三miniprogram/utils/request.js里的BASE_URL。为什么要按这个顺序因为这套源码能不能跑起来90% 取决于这三个地方的参数是否一致。表名对不上后端启动不报错但接口查出来的数据全是空接口前缀对不上小程序端请求全部 404BASE_URL写的是别人的域名你本地跑就会看到一堆超时。与其等运行时报错不如先做静态排查。注意不要根据目录名猜技术栈。有的包后端目录叫server里面其实是 Node.js有的叫backend里面是 Spring Boot。判断依据是根目录有没有pom.xml或package.json。这里以最常见的 Spring Boot MyBatis-Plus 为例展开因为配 MySQL 最省事SQL 文件也最规整。如果拿到的是 Node.js 版本后面配置文件的写法换成.env即可MySQL 和前端部分完全通用。2.2 为什么微信小程序必须走接口前后端分离是必然很多初学者第一次打开这类项目会想“能不能在小程序里直接连 MySQL 表”答案是不能。微信小程序的运行环境是双线程架构逻辑层跑在 JSCore 上渲染层跑在 WebView 里两端通过setData通信。为了安全微信官方不允许逻辑层直接建立数据库连接你只能用wx.request或wx.cloud访问远程接口。所以只要数据在 MySQL 里就必须有一个后端把数据库包一层 HTTP API这就是这套源码里server目录存在的意义。从这个角度看“前后端分离项目实战”这个说法用在这套源码上非常贴切小程序端只负责页面渲染和用户交互积分怎么算、流水怎么记、怎么防刷全部由后端决定。这样做有三个实际好处。第一积分规则变更不用重新发布小程序版本改后端接口即可。第二同一个后端可以同时服务小程序、管理后台和将来的 App不用重复写业务逻辑。第三数据库连接串、微信 secret 这些敏感信息不会被打进小程序包里真机预览和线上包里的wx.request只能看到接口地址看不到数据库密码。如果你之前跑过 springboot vue 前后端分离项目会发现这里的交互模型几乎一样只是把 Vue 换成了微信小程序原生框架。这里要提醒一句有些源码包会把管理后台也叫“前端”于是压缩包里出现“小程序端、管理后台、后端接口”三个目录。分清主次很重要小程序端是给员工用的管理后台是给运营用的后端接口是共享的。调试时先保证“小程序端 后端接口”这条链路通管理后台可以放到第二步。否则你盯着后台页面找问题永远定位不到小程序端发起的请求上。2.3 四张核心表用户、活动、积分流水、兑换记录如何设计企业活动积分的业务不复杂但表结构设计好坏直接决定后期防刷和对账好不好做。我拆过很多套类似源码做得规范的都会包含下面这四张表。我把核心建表语句整理成一份最小版本你可以拿它和源码包里的sql文件对照着看CREATE DATABASE IF NOT EXISTS activity_points DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE activity_points; -- 用户表openid 唯一积分余额冗余在这里 CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, openid VARCHAR(64) NOT NULL COMMENT 微信 openid, nickname VARCHAR(64) DEFAULT , avatar_url VARCHAR(500) DEFAULT , points INT NOT NULL DEFAULT 0 COMMENT 当前积分余额, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; -- 活动表不同活动类型对应不同积分值 CREATE TABLE activity ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(100) NOT NULL, type TINYINT NOT NULL COMMENT 1-签到 2-答题 3-抽奖 4-自定义, points INT NOT NULL DEFAULT 0 COMMENT 完成一次可得积分, start_time DATETIME DEFAULT NULL, end_time DATETIME DEFAULT NULL, status TINYINT NOT NULL DEFAULT 1 COMMENT 1-启用 0-停用, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT活动表; -- 积分流水表每一次积分变动都留痕 CREATE TABLE points_record ( id INT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL, activity_id INT DEFAULT NULL, change_type TINYINT NOT NULL COMMENT 1-获得 2-兑换扣减 3-管理员调整, points INT NOT NULL COMMENT 正负分, biz_no VARCHAR(64) DEFAULT NULL COMMENT 业务单号防重复, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_biz_no (biz_no), KEY idx_user_created (user_id, created_at) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT积分流水表; -- 兑换记录表积分换礼品的订单 CREATE TABLE exchange_order ( id INT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL, item_name VARCHAR(100) NOT NULL, points_cost INT NOT NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT 0-待发货 1-已发货, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT兑换订单表;这几个点值得细说。第一user表里的points是冗余字段因为积分排行榜要高频查询用户当前积分每次实时SUM流水表太慢。但冗余就要求后端在每次积分变动时用事务同时更新流水和余额否则两边一对比就出现账不平。第二points_record.biz_no的唯一索引是整个防刷体系里的最后一道防线业务单号一旦重复数据库直接拒绝插入第 4 章会展开讲。第三字段类型上积分用INT完全够用如果将来要接支付或者金额相关业务请改用DECIMAL(10,2)用FLOAT会出现精度问题这也是很多半路转行的开发常踩的坑。如果你拿到的sql文件里没有biz_no这个字段强烈建议自己加上。很多流传的源码包就是栽在“用户连续点击签到”这种最简单的并发场景上。加字段不影响原有接口Mapper 的插入语句补上这个值就行。另外建库和建表都用了utf8mb4微信用户的昵称里经常有 emojiutf8mb4才能正常存储用旧版的utf8会在写入时直接报Incorrect string value。数据库这一层没问题后面后端和小程序才会省心。3. 把 MySQL 和后端跑起来数据库导入、连接配置与接口启动3.1 MySQL 8 初始化建库、导数据、账号权限的三个命令先把 MySQL 装好。网上 mysql 安装教程、mysql 下载官网的教程已经很多我只强调和这套源码相关的三点字符集、认证插件、账号权限。以 MySQL 8.0 为例安装完成后用 root 登录mysql -uroot -p登录后先建库再导入源码包里的sql文件。建库时一定要指定utf8mb4否则等导入数据后才发现 emoji 乱码就晚了CREATE DATABASE IF NOT EXISTS activity_points DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;然后退出 MySQL用命令行导入。这个命令会把sql文件里的表结构和初始数据全部导入到activity_points库mysql -uroot -p activity_points sql/activity_points.sql导入成功后可以这样快速确认表有没有建出来mysql -uroot -p -e USE activity_points; SHOW TABLES;如果报ERROR 1044或ERROR 1046通常是把库名拼错了或者没有先建库。检查一下sql文件开头有没有CREATE DATABASE语句有的话建议把那行删掉统一用命令行建库避免后续开发和部署时库名混乱。接下来创建应用专用账号。源码包里后端配置默认用 root 的很多但我建议你换成独立账号。数据库密码会明文写在application.yml里如果代码要进公司 Git 仓库root 密码泄露等于数据库裸奔。创建账号和授权CREATE USER points_applocalhost IDENTIFIED BY Points2024; GRANT ALL PRIVILEGES ON activity_points.* TO points_applocalhost; FLUSH PRIVILEGES;注意points_applocalhost和points_app%是两回事。本地启动时后端和 MySQL 在同一台机器用localhost就行。如果 MySQL 跑在另一台服务器上后端要通过局域网 IP 连接就必须改成points_app%或指定 IP 段否则报Host 192.168.x.x is not allowed to connect。这个报错经典到几乎每周都能在群里看到。另外MySQL 8 默认使用caching_sha2_password认证老一点的后端驱动可能不认识连接时会报错。这个问题在第 5 章避坑里单独说这里先把账号建好。3.2 后端配置文件数据源、时区、SQL 日志的参数取舍Spring Boot 项目的配置集中在src/main/resources/application.yml重点关注这几项server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/activity_points?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: points_app password: Points2024 driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImplurl里这四个参数是血泪经验攒出来的。useSSLfalse是因为本地开发不需要加密连接不加会刷一大段 SSL 警告某些环境下甚至提示连接失败。serverTimezoneAsia/Shanghai解决 MySQL 连接时区差 8 小时的问题不加的话DATETIME类型返回的数据可能比实际少 8 小时签到记录会落在“昨天”。allowPublicKeyRetrievaltrue解决 MySQL 8 在部分驱动版本下报Public Key Retrieval is not allowed这个跟认证插件有关。characterEncodingutf8配合数据库的utf8mb4保证中文和 emoji 不会变成问号。mybatis-plus下有两个配置。map-underscore-to-camel-case: true负责把数据库的created_at自动映射成实体的createdAt省去一堆TableField注解log-impl: StdOutImpl会把每条 SQL 打印到控制台调试接口时能看到实际执行的语句和参数开发环境强烈建议保留。部署到生产后把这行注释掉或者换成 SLF4J 输出到文件避免日志全打在标准输出里排错时找不到内容。如果你的源码包用的是原生 MyBatis配置里去掉mybatis-plus:这一整段换成mybatis:其余不变。如果项目是 Node.js数据库连接串通常写在.env或config.js里参数含义完全一样把?后面的部分照搬过去即可。有一种容易漏的情况后端配置里写的是jdbc:mysql://localhost:3306/activity_points但你的 MySQL 实际端口是 3307 或者开了 Docker 映射那么这里也要同步改只改账号密码没意义。3.3 启动后端并用 curl 验证接口配置改完启动后端。Maven 项目先打包再运行cd server mvn clean package -DskipTests java -jar target/*.jar控制台出现Started ... in xx seconds说明启动成功。如果用的是 IDEA 这种 IDE也可以直接运行主类效果一样。Spring Boot 自带 Tomcat本地不需要额外装。启动后不要急着打开小程序先用 curl 验证后端还活着curl http://localhost:8080/api/health多数源码包会有一个健康检查接口。没有的话换成登录接口curl -X POST http://localhost:8080/api/user/login \ -H Content-Type: application/json \ -d {code:test-code-001}返回 JSON 里带token和userInfo就说明数据库连接正常、接口可以通。这时候再去微信开发者工具里跑小程序成功率高很多。如果启动时报数据库相关错误回到 3.1 和 3.2 重新核对账号、密码、库名、时区。如果返回 404检查接口前缀看后端的RequestMapping到底写的是/api还是/api/user。这里我把 curl 的结果存成一个文本文件后续小程序端接不上时回头对比能快速判断问题出在后端还是前端。本地接口通了再往后端和小程序联调走。4. 小程序端接后端请求封装、登录态与积分发放的幂等控制4.1 封装 wx.request统一 baseURL、token 与错误处理小程序端最常见的翻车点是每个页面各写各的wx.request域名散落一地改一次后端地址要全局搜索替换。我拿到这类源码的第一件事就是把请求统一封装到utils/request.js。下面这个版本足够跑通大多数活动积分小程序// utils/request.js const BASE_URL http://127.0.0.1:8080/api; function request({ url, method GET, data {}, needAuth true }) { return new Promise((resolve, reject) { const header { Content-Type: application/json }; const token wx.getStorageSync(token); if (needAuth token) { header[Authorization] Bearer token; } wx.request({ url: BASE_URL url, method, data, header, success(res) { if (res.statusCode 200 res.data.code 0) { resolve(res.data.data); } else if (res.statusCode 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/login/login }); reject(new Error(登录已过期)); } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(new Error(res.data.msg || 请求失败)); } }, fail(err) { wx.showToast({ title: 网络异常请检查后端是否启动, icon: none }); reject(err); } }); }); } module.exports { request, BASE_URL };这段代码做了三件事。第一把BASE_URL收敛到一个常量后端地址变动只改一处本地开发用http://127.0.0.1:8080真机调试改成电脑局域网 IP上线改成https域名。第二需要登录的接口自动带上Authorizationheader后端通过 token 识别用户。第三统一处理错误后端返回的 JSON 里code: 0表示成功非 0 弹 toast401表示登录过期清 token 并跳登录页避免用户在一个失效页面反复请求。很多网上源码包的封装只做res.data.code 0判断漏掉了statusCode 200这一层。如果后端整包返回 500res.data可能是空直接取msg会报Cannot read property msg of undefined。先判断 HTTP 状态码再判断业务码顺序不能反。另外fail分支里提示“检查后端是否启动”不是废话本地联调时大部分网络报错都是后端没起来或者手机连错了 IP。这就是微信小程序请求封装里最值得抄的一段。4.2 从 wx.login 到 openid登录态完整链路微信小程序的登录不能自己做账号密码必须走wx.login拿到临时code再把code发给后端由后端拿着appid和secret去微信接口换openid。一个典型登录页面的核心逻辑// pages/login/login.js const { request } require(../../utils/request); Page({ handleLogin() { wx.login({ success: async (res) { if (!res.code) { wx.showToast({ title: 获取 code 失败, icon: none }); return; } try { const data await request({ url: /user/login, method: POST, data: { code: res.code }, needAuth: false }); wx.setStorageSync(token, data.token); wx.setStorageSync(userInfo, data.userInfo); wx.switchTab({ url: /pages/index/index }); } catch (err) { console.error(login error, err); } }, fail: () wx.showToast({ title: 登录失败, icon: none }) }); } });后端收到code后用HttpClient请求微信的jscode2session接口参数带appid、secret、js_code、grant_typeauthorization_code微信返回openid和session_key。流程不长但有一个底线secret绝对不能出现在小程序代码里。小程序包可以被反编译任何写在前端的 secret 都等于公开。这也是为什么这套源码必须是“完整前后端”登录校验、数据库操作、secret 管理全都要放后端。本地开发时如果不想每次真调微信接口可以在后端加一个mock-login开关当code以mock开头时直接用code的哈希值当openid插入用户表。这样前端不依赖微信环境Postman 也能拿 token 测试其他接口。注意这个开关必须在生产配置里关闭否则任何人都能伪造 openid。我见过不止一个部署在公网上的 demomock-login没关被扫描到后积分排行榜直接被人刷爆。如果你要正式上线这门禁一定要加。4.3 积分发放的幂等控制三个闸口与后端代码活动积分小程序除登录外最核心的接口就是“签到得积分”。设计不好用户快速点两下就能拿双倍分。防重复发放的思路是三个闸口一起上前端按钮锁、后端幂等判断、数据库唯一索引。后端核心代码Transactional(rollbackFor Exception.class) public void signIn(Long userId, Long activityId) { String bizNo userId : activityId : LocalDate.now(); PointsRecord record new PointsRecord(); record.setUserId(userId); record.setActivityId(activityId); record.setChangeType(1); record.setPoints(10); record.setBizNo(bizNo); try { pointsRecordMapper.insert(record); } catch (DuplicateKeyException e) { throw new BusinessException(今天已经签到过不能重复领取); } userMapper.addPoints(userId, 10); }bizNo的格式直接决定幂等粒度userId:activityId:日期表示每个用户每天只能签到该活动一次去掉日期整个活动周期只能参与一次加了activityId可以支持多个活动并行。这个字符串要尽量短但足够唯一建议方案是userId:activityId:yyyy-MM-dd然后在points_record表里对biz_no建唯一索引。为什么要先插入流水再更新余额因为insert触发唯一索引冲突时会抛DuplicateKeyException在这里拦截能给出友好提示。如果先更新余额再插入流水并发场景下可能出现余额加了但流水插入被拒账不平。Transactional保证这两个操作要么都成功要么都回滚配合唯一索引即使同一个请求被重放数据库也会拒绝第二次插入。前端再把按钮在请求发出后置为disabled用户连点也不会发出第二个请求三个闸口各管一层。这里要特别说一下有的源码为了省事签到逻辑写成SELECT COUNT(*) FROM points_record WHERE user_id? AND DATE(created_at)CURDATE()先查询再插入。这种写法在低并发下没问题但两个请求同时通过查询就会都插入积分照样翻倍。数据库唯一索引是成本最低、最可靠的防线写 SQL 时一定不要省。前端防抖只是体验优化真正的安全边界必须落在后端和数据库。5. 避坑集中营从本地跑通到真机预览的 5 个翻车点5.1 开发者工具报“URL 不在合法域名列表中”现象小程序端请求后端控制台直接报request:fail url not in domain list接口一个都通不了。原因微信开发者工具默认校验 request 合法域名。本地联调用的http://127.0.0.1:8080不在你小程序账号配置的白名单里所以被拦。解决开发阶段打开微信开发者工具点右上角“详情” → “本地设置”勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。这个选项只对当前项目和当前工具生效不涉及线上。如果已经勾选仍然报错检查BASE_URL里是不是把http写成了https或者 URL 末尾多了空格和斜杠。注意即使本地能跑真机预览同样受这个限制所以真机测试也要勾选该选项。上线时再去微信公众平台“开发管理-开发设置-服务器域名”里配置必须是 HTTPS 且已备案的域名保存后生效需要几分钟不要改完就立刻拿手机试。提示上线前记得把“不校验合法域名”选项取消否则小程序审核会被拒。5.2 后端启动报 Access denied 或 Public Key Retrieval is not allowed现象java -jar启动 Spring Boot控制台出现Access denied for user points_applocalhost或者Public Key Retrieval is not allowed。原因前者是账号密码错误、账号 host 不匹配或密码策略问题后者是 MySQL 8 的caching_sha2_password认证插件和旧版 JDBC 驱动不兼容驱动第一次连接需要向服务器要公钥默认策略拒绝了。解决先确认 MySQL 里账号密码与application.yml完全一致注意密码里的特殊字符在 YAML 中要用引号包起来例如Points2024否则会被 YAML 解析出问题。然后确认 JDBC 驱动版本MySQL 8 对应驱动坐标com.mysql:mysql-connector-j版本 8.x驱动类名是com.mysql.cj.jdbc.Driver。连接 URL 加allowPublicKeyRetrievaltrueuseSSLfalse。如果还不行再考虑改认证插件ALTER USER points_applocalhost IDENTIFIED WITH mysql_native_password BY Points2024;但 MySQL 8.4 开始官方逐步移除了这个插件所以优先升级驱动和 URL 参数不要一上来就改认证方式。另外如果你用的是云数据库控制台一般会提供连接串直接复制过来改账号密码即可。5.3 电脑上能跑真机预览却白屏或全部超时现象开发者工具里页面正常点“真机预览”后手机上打开小程序页面加载不出来请求全部 timeout。原因这是一个黑匣子问题。开发者工具运行在电脑上127.0.0.1指向电脑本机手机上的小程序运行时127.0.0.1指向手机自己自然连不上电脑后端。另外即使BASE_URL改成了电脑的局域网 IP手机和电脑不在同一个网段、电脑防火墙拦截了 8080 端口或者公司 WiFi 开了 AP 隔离照样超时。解决把utils/request.js里的BASE_URL改成电脑的局域网 IP用ipconfigWindows或ifconfigmacOS/Linux查192.168.x.x那一行。确保 Spring Boot 监听在0.0.0.0默认就是如果配置里有server.address127.0.0.1必须删掉。然后放行防火墙 8080 端口Windows 在“高级安全防火墙”里加一条入站规则macOS 在系统设置里允许入站连接。最后手机和电脑连同一个 WiFi。如果公司 WiFi 互相 ping 不通用手机热点是最省事的方案。改完BASE_URL和后端配置小程序需要重新编译因为代码改动不会自动热更新到真机。5.4 积分被刷流水表出现重复记录现象用户连续快速点击签到按钮后端日志显示两个请求都成功数据库里出现两条biz_no完全相同的流水用户积分翻倍。原因前端没有防抖后端没有幂等校验数据库没有唯一索引。只用SELECT COUNT(*)判断是否签到过在并发下会有时间窗口两个请求都可能通过检查。解决按第 4.3 节的三个闸口完整实现。前端在请求发出后把按钮设为disabled直到返回后端插入前不查询直接靠points_record.biz_no唯一索引拦截重复插入冲突时捕获DuplicateKeyException返回“今天已经签到过”。日志里看到Duplicate entry 1:2:2026-04-18 for key uk_biz_no说明唯一索引生效了。另外更新积分用UPDATE user SET points points 10 WHERE id ?不要“先查出来再 set 回去”后者在并发下会丢失更新。修复后记得给历史流水表补唯一索引但先去重再建索引否则历史重复数据会导致建索引失败。具体去重 SQL 可以保留MIN(id)的记录再删其余重复项这里不展开。5.5 部署到服务器后接口 404 或 502现象本地正常把后端打包放到云服务器用 Nginx 反代后访问https://域名/api/user/login返回 404或者 502 Bad Gateway。原因常见三种。第一Spring Boot 启动参数没指定生产数据库连的还是本地库接口异常。第二Nginxlocation配置把/api路径转发错了。第三前后端分离项目里接口上下文路径没有统一后端设置了server.servlet.context-path/api前端BASE_URL还写/api实际路径变成/api/api。解决启动 jar 时用--spring.profiles.activeprod指定生产配置或者用环境变量注入数据库地址不要直接改 jar 里的配置。Nginx 配置先确认后端本地能通curl http://127.0.0.1:8080/api/user/login。如果本地通参考下面的 Nginx 配置server { listen 80; server_name act.example.com; location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }注意proxy_pass是http://127.0.0.1:8080/api/以/api/结尾这样原始请求/api/user/login会完整转发到后端如果proxy_pass只写到http://127.0.0.1:8080/Nginx 会去掉location前缀再转发变成/user/login后端没有这个路径就 404。502一般是后端没起来或者端口不通先看后端日志再netstat -tlnp | grep 8080确认端口监听状态。有些人在 Linux 上装完 MySQL 没改bind-address默认只监听本机后端通过局域网地址连不上也会引发接口异常。这几点都排查过前后端分离部署基本就不会再翻车。6. 进阶验证技巧验收、扩展与二次开发6.1 验收三件事账平、幂等、越权我拿到任何一套积分源码验收时只做三个检查。第一账平不平。把流水表按用户分组求和和user.points对比SELECT r.user_id, SUM(CASE WHEN r.change_type 1 THEN r.points ELSE -r.points END) AS sum_points, u.points FROM points_record r JOIN user u ON u.id r.user_id GROUP BY r.user_id, u.points HAVING sum_points ! u.points;有结果就说明存在积分多发漏发需要检查事务和扣减逻辑。第二幂等。同一个biz_no用脚本重复提交十次积分只能加一次流水只能出现一条。第三越权。普通用户 token 调用管理员接口应该返回 403后端必须用拦截器校验角色不能只靠前端隐藏按钮。这三个检查过了我才会认为这套源码可以正式投入使用。6.2 二次开发把签到积分做成可配置任务这套源码最常见的扩展需求是“不同活动给不同积分运营能自己配”。做法是把活动规则抽到activity表后端提供activity/list和user/signIn两个接口前端首页动态渲染活动列表。我一般会再给activity表加icon_url和sort_order两个字段避免每次加活动都要发小程序版本。如果要把小程序迁移到 uni-app保留utils/request.js的封装思路只把wx.request换成uni.request页面代码重写成本大概占一半。生产部署建议按第 5.5 节的 Nginx 方案走数据库用云厂商的 MySQL并在后端加一层 Redis 缓存排行榜热点数据但那一步已经超出“跑通源码”的范畴了。最后说一条我自己的教训每次拿到这种“完整前后端mysqlLW”的源码包我都会最先盯死时间字段和唯一索引因为积分业务最容易出账不平。宁可在建表时多想十分钟也别等上线后被运营拿着 Excel 对账。希望帮到你。本文还有配套的精品资源点击获取