☰
微信小程序评分系统实战:SSM架构与前后端联调全解析
2026/9/28 11:43:45 网站建设 项目流程

拿到一套“微信小程序评分小程序”的全套资料,很多人第一反应是“不就一个小程序评分功能吗,能有多少东西”。实际上你把后端拆开看就会发现,这项目的核心价值不在小程序那几十个页面,而在后面的SSM架构、数据库设计、接口约定和整套前后端联调思路。我前后花了两天时间把它完整跑通,再把代码逐行捋了一遍,今天把这套东西的细节、步骤和踩过的坑一次性写清楚,给准备做课程设计、毕业设计或者想快速入门全栈开发的朋友参考。

这套评分小程序解决的是典型的“用户对指定对象打分、看排行、管理员维护数据”的业务闭环。用户端通过微信授权登录,可以对作品或项目进行打分评价,也能查看实时排行;管理端维护评分对象、发布公告、查看统计数据。整体技术栈是微信小程序+SSM(Spring+SpringMVC+MyBatis)+MySQL,附带的文档包含了需求分析、数据库设计、接口说明和部署文档,属于能直接照着跑、改一改就能变成自己项目的完整课设样例。

我按“先看懂设计,再动手跑通,最后解决坑”的顺序来写。如果你是第一次拿到这类带源码的项目,强烈建议按这个节奏走,别上来就双击启动,容易连代码在干什么都搞不清楚。

1. 项目整体定位与技术选型拆解

1.1 这套评分系统到底能做什么

从业务功能上拆,评分系统通常包含三个核心角色:普通用户、评分对象、管理员。用户端能看到评分对象的列表和详情,对某个对象进行打分并提交评语,提交后在排行榜里看到当前所有对象的得分排名;管理员则负责后台数据的维护,比如添加评分项目、上下架对象、查看系统公告、管理用户评分记录。

我调试这个项目时,给它设计了一个“校园活动作品评分”的使用场景:每个作品就是一个评分对象,用户可以给作品打1到10分并写评价,最后按平均分排序展示榜单。这个场景的好处是数据关系直观,非常适合理解项目结构。如果你拿到的源码里带了具体的表数据或者文档,直接按文档里的业务描述来理解就行,表结构基本都是围绕这三类核心数据展开的。

1.2 为什么后端选SSM而不是Spring Boot

你可能好奇,现在新项目不都用Spring Boot吗,怎么还有SSM?这里要说一个重要的事实:SSM不等于老技术,它是“Spring+SpringMVC+MyBatis”三个框架的组合,Spring Boot本身也是基于Spring框架的,区别主要在于自动配置和起步依赖。课设和毕设选择SSM,除了教学体系里还在讲这套组合,还有一个很实际的原因:SSM让你手动完成组件扫描、数据源配置、Mapper扫描这些关键步骤,你能真正理解Spring容器是怎么把Controller、Service、Mapper串起来的。Spring Boot把这些都自动配好了,代码少但学习效果打折。

从部署角度看,SSM项目通常打成war包放到Tomcat里运行,这和小程序的开发调试方式很匹配。开发时本地起Tomcat,小程序开发者工具直接通过局域网IP或localhost访问后端接口;正式部署时再挂域名和HTTPS证书。整个过程链路短、依赖简单,非常适合中小型课设项目。

1.3 前端选微信小程序的场景优势

评分这类轻交互业务,小程序比原生App合适得多。用户不需要下载安装,扫码或搜一下就能打开,非常符合“看完作品顺手打个分”的使用习惯。微信生态自带登录体系,前端调用wx.login拿到code,后端再通过接口换取openid,就不用自己再折腾一套注册登录了,这个流程对课设来说省了大量时间。

从开发难度看,小程序的前端技术栈是JavaScript+WXML+WXSS,上手曲线比Android或iOS原生开发低很多。页面的渲染、路由、请求库都是框架自带的,不需要自己处理复杂的布局适配。整个项目的前端代码量通常只有几百行,结构上分为index(首页)、detail(详情评分)、rank(排行榜)、mine(我的)这几个页面,逻辑清晰,非常适合作为前后端分离架构的入门范例。

1.4 整体架构与请求流转路径

这个项目的架构虽然称不上复杂,但前后端分离的层次感非常标准。客户端是微信小程序,服务端是SSM工程,数据库用MySQL,前后端通过HTTP接口通信,数据格式统一为JSON。

从一次完整的评分请求来看,流程是这样的:小程序端用户点击提交评分按钮,request.js封装的请求函数带着token和评分数据发起wx.request请求;后端Tomcat收到请求后由DispatcherServlet分发给对应的Controller;Controller接收参数后进行基础校验,调用Service层处理业务逻辑;Service调用Mapper接口操作数据库,完成插入或更新后返回影响行数;最终数据被包装成统一的Result对象,通过Jackson序列化成JSON返回给前端;小程序拿到返回结果后判断code值,成功则提示并刷新页面。

这条链路里最值得学习的就是分层思想。Controller只负责接收参数和返回结果,不写SQL;Service只处理业务规则,不关心HTTP细节;Mapper只跟数据库打交道。每层各干各的活,出了问题也容易定位。

2. 数据库与接口设计,先定好数据的地基

2.1 核心表结构与字段设计要点

这个项目的数据库设计是整个源码里最值得看的模块之一。一般的评分系统至少需要五张表:用户表、管理员表、评分对象表、评分记录表、公告表。以我改过的一个版本为例,核心字段大致是这样设计的:

用户表 t_user 包含id、openid、nickname、avatar、create_time。openid是微信用户的唯一标识,加唯一索引防止重复绑定。这里有个容易踩坑的点,早期版本会专门存session_key,但出于安全和时效考虑,现在一般只保留openid即可,登录态由后端生成token来维护。

评分对象表 t_target 包含id、name、description、cover_img、category、status、create_time。status字段用来做上下架控制,status为1才在前端展示,这个设计比直接删除数据靠谱,删了想恢复就麻烦了。

评分记录表 t_score 包含id、target_id、user_id、score、comment、create_time。这张表建议给target_id和user_id加联合唯一索引,确保同一个用户对同一个评分对象只能有一条评分记录。用户重复提交时不是新增数据而是更新原记录,这是评分类系统防止刷分的标准做法。

公告表 t_notice 结构比较简单,id、title、content、create_time就够了,管理员发布后小程序首页拉取最新一条展示。

在设计表时,字符集统一用utf8mb4而不是utf8。utf8mb4是utf8的超集,支持emoji和特殊符号,用户昵称里如果带个特殊符号,用utf8可能直接写入报错。另外所有表都建议加上create_time字段,你在统计数据和调试问题时就知道时间戳有多重要。

2.2 统一返回结构和接口清单

在很多课设项目里常见的一个坏毛病是每个接口返回的数据格式都不一样,有的直接返回数组,有的返回带message的对象,前端解析起来只能到处判断。这套项目用了统一返回结构,核心Result对象包含三个字段:code表示状态码,200为成功,其他为失败;msg是给前端提示用的信息;data是业务数据本体。

接口清单我整理成了一张表,方便对照着理解:

接口地址请求方式功能说明请求参数
/api/user/loginPOST微信登录,后端返回tokencode
/api/target/listGET获取评分对象列表pageNum、pageSize、category
/api/target/detailGET查看对象详情id
/api/score/submitPOST提交或更新评分targetId、score、comment
/api/score/myGET查看我的评分记录无
/api/rank/listGET获取评分排行榜无
/api/notice/latestGET获取最新公告无
/api/admin/loginPOST管理员登录username、password
/api/admin/target/savePOST管理员新增修改对象对象字段

2.3 登录鉴权与评分防重设计

小程序登录流程比较固定:前端wx.login拿到临时code,发送给后端;后端拿着code调用微信的接口换取openid和session_key;后端用openid查用户表,不存在就自动注册一条新用户;随后生成一个token(可以是UUID或者JWT)返回给前端,前端存在storage里,后续请求在header里带上即可。

评分防重这块,除了数据库加联合唯一索引,后端在Service层也要查一次是否已有记录,存在就执行update,不存在就执行insert。这种做法比单纯依赖数据库报错要好,因为唯一索引冲突时抛出DuplicateKeyException虽然能兜底,但日志不够友好,用户也看不懂。先查再更新的方式能保证接口幂等,实际测试下来体验明显更好。

3. 落地部署:从IDEA到微信开发者工具的完整流程

3.1 环境版本搭配清单与说明

环境版本这门课,看似不起眼但最容易耗死人。我建议按下面这套组合来装,全部调试通过,不折腾:

  • JDK 1.8(不要用11或17,SSM老配置和Tomcat版本兼容性容易出问题)
  • Maven 3.6.x
  • IDEA 2021以后的版本都行
  • Tomcat 8.5(配JDK8最稳)
  • MySQL 5.7或8.0都行,8.0记得用对应的驱动版本
  • 微信开发者工具最新稳定版
  • Postman或Apifox用于接口调试

这里特别说一下MySQL驱动的问题。如果你用的是MySQL 8.0,驱动类名是com.mysql.cj.jdbc.Driver,连接URL必须带上serverTimezone=Asia/Shanghai,不然系统时间和数据库时间可能差8小时,这是很经典的一个坑。用MySQL 5.7的话,驱动类名可以写成com.mysql.jdbc.Driver,但为了统一,我建议新写的项目直接用cj驱动,并且在URL里统一加上serverTimezone和characterEncoding参数。

3.2 后端SSM工程一步步搭起来

拿到源码后先用IDEA以Maven项目的方式导入。导入完成后,优先看pom.xml,确认这几个核心依赖都在:spring-webmvc、mybatis、mybatis-spring、mysql-connector-java、druid或c3p0连接池、jackson-databind。如果缺了依赖,Maven刷新后会报红,补上对应坐标即可。

接下来看web.xml,SSM项目里这个文件负责启动Spring容器和SpringMVC容器。它需要配置DispatcherServlet拦截所有请求,同时配置CharacterEncodingFilter强制UTF-8编码。这里有个细节:CharacterEncodingFilter一定要放在DispatcherServlet前面注册,否则POST请求的中文参数到Controller里就是乱码,因为过滤器执行顺序是按mapping顺序来的。

spring-mvc.xml重点看三件事:包扫描路径是否正确,Controller所在的包是否被扫到;mvc:annotation-driven是否配置,这决定了JackJSON和参数绑定是否生效;内部资源视图解析器虽然评分接口都用@RestController,但万一要返回页面,有个配置兜底总是好的。

spring-mybatis.xml里是核心的数据库配置。Druid数据源的配置项包括driverClassName、url、username、password,还有initialSize和maxActive连接池参数。SqlSessionFactoryBean要指定mapperLocations路径,通常是classpath:mapper/*.xml,这样MyBatis才能找到SQL映射文件。最后用MapperScannerConfigurer扫描Mapper接口包,让Spring自动为每个Mapper接口生成代理实现。

实际跑项目时,数据库脚本要提前导入。源码里通常附带sql文件,用Navicat或命令行source执行就行。如果文档里没附主动生成表的脚本,一条关键经验是:项目中所有的Mapper XML里出现的表名,就是你要创建的目标,按字段结构补建表即可。

Tomcat里部署项目时,注意看Application Context路径。IDEA里配置Tomcat时默认的Deployment会有一个访问路径,比如/ssm_score_war_exploded,那么后端接口的完整地址就是http://localhost:8080/ssm_score/api/target/list。这个路径很容易被忽略,前端请求失败时先确认是不是这里没对上。

3.3 小程序端页面与请求封装

小程序的工程结构一般包含app.js、app.json、utils、pages目录。app.json注册所有页面路径,pages目录下每个页面由四个文件组成:js逻辑、wxml结构、wxss样式、json配置。

utils/request.js是整个前端最关键的封装,骨架代码思路大概是这样的:

const BASE_URL = 'http://localhost:8080/ssm_score'; function request(url, method = 'GET', data = {}) { return new Promise((resolve, reject) => { const token = wx.getStorageSync('token'); wx.request({ url: BASE_URL + url, method: method, data: data, header: { 'Content-Type': 'application/json', 'token': token || '' }, success(res) { if (res.data.code === 200) { resolve(res.data.data); } else { wx.showToast({ title: res.data.msg, icon: 'none' }); reject(res.data); } }, fail(err) { wx.showToast({ title: '网络异常', icon: 'none' }); reject(err); } }); }); } module.exports = { request };

这里BASE_URL要和后端Tomcat部署路径保持一致。开发阶段在微信开发者工具里可以勾选“不校验合法域名”,这样能用http加localhost调试,真机预览则需要后端部署到HTTPS域名或者用真机调试配合内网穿透。

评分页是核心交互页面。用户在页面里选择分数或点击星星,再把评语填进textarea,点击提交时先做前端校验,分数为0或评语为空格都直接拦截,然后调request提交。提交按钮在请求发出后加loading状态防连点,等回调成功后跳转回列表页,并刷新最新数据。这段逻辑不复杂,但前端校验这块千万别省,很多后端接口没有做过多的容错,前端不拦,脏数据直接进库。

3.4 前后端联调的关键路径

联调阶段我习惯用Postman先把后端接口全部过一遍,再开小程序对接。打开Postman,新建请求输入http://localhost:8080/ssm_score/api/target/list,如果是GET请求直接Send,返回JSON数组说明后端基本通了。登录接口需要在Body里选raw+JSON,填上code参数模拟wx.login传来的临时凭证。如果登录接口返回了token,就说明用户登录这条链路是通的。

后端通了再回小程序端调试。前端报错时有一个黄金排查顺序:先看网络面板里的请求有没有发出去,再看状态码是什么,最后看返回的JSON结构有没有被正确解析。有一次我的前端在解析排行榜数据时一直显示undefined,查了半天发现是列表数据字段是avgScore,而后端JavaBean里写的是avgscore,字母大小写对不上,Jackson默认的映射策略对首字母大小写很敏感,这类问题就是在联调时才容易暴露。

4. 实操中的常见问题与排查技巧实录

4.1 上不了数据库:JDBC连接失败排查

报错信息通常长这样:Could not get JDBC Connection 或者 Communications link failure。出现这个先别慌,按照从上到下的顺序检查:第一步看MySQL服务有没有启动,Windows下services.msc里查MySQL服务状态;第二步看连接URL里的IP和端口对不对,本地项目不要写成localhost而数据库跑在虚拟机里的情况经常出现;第三步确认用户名密码没有混进空格;第四步看驱动版本和数据库版本是否匹配。

实际调试中我发现一个容易被忽视的点:连接URL里的数据库名必须存在,否则也会报连接失败。假设你的URL配的是jdbc:mysql://localhost:3306/score_db,但MySQL里根本没建这个库,驱动会直接抛出Unknown database的异常,这个看异常信息就能发现。

4.2 Mapper绑定异常是怎么回事

Invalid bound statement (not found)是SSM项目里出现频率极高的问题。这个异常的意思是Spring容器中确实存在Mapper接口的Bean,但调用某个方法时找不到对应的SQL语句。常规原因有三个:第一,Mapper接口和XML文件没有在同一个包路径下,比如接口在com.xxx.mapper,XML在resources/com/xxx/mapper,这是正确的,XML放错目录就会漏扫;第二,XML文件里namespace没有写成接口的全限定名;第三,接口方法和XML里语句的id对不上,大小写不一致也算不对。

排查技巧是直接看编译后的target目录,XML有没有被Maven复制过去。很多情况下源码里XML放对了,没做build,运行的就是旧的class文件,白白卡了半小时。确认target目录里存在对应的XML,再用Maven的clean命令清掉重来,问题基本能解决。

4.3 请求老是不通:404/500类问题

小程序请求后端返回404,最常见的原因是部署路径和访问路径不匹配。比如后端访问路径是/ssm_score,前端BASE_URL写成了http://localhost:8080,这就直接404。另外还要看Controller里的@RequestMapping是不是两层拼接的,类上写了/api,方法上写了/target/list,那么完整路径一定是/api/target/list,漏掉任何一层都访问不到。

返回500就去看日志。IDEA控制台或Tomcat的logs目录下catalina.out,拉到最底部看Caused by那一行,这往往才是根因。有一次我遇到空指针,翻日志发现是Service里根据前端传来的id查对象,查出来是null,没有判空就直接拿去get字段了。这种问题代码层面好解决,记住一条:所有可能为null的中间结果都加判空,哪怕后端接口的入参看起来很正常。

4.4 中文乱码与时间错乱

中文乱码问题有三个层面,要分清是谁在乱码。如果Postman里返回的中文是正常的,小程序端显示乱码,那是小程序的编码问题,检查请求的header里有没有带charset=UTF-8;如果Postman里就乱码,那是后端返回时编码不对,在SpringMVC的配置文件里设置消息转换器的编码;如果存入数据库后乱码,那是数据库连接URL或表结构字符集的问题,URL里加characterEncoding=utf8,表的字符集改成utf8mb4并重建数据。

时间错乱通常是时区问题。MySQL 8.0的连接URL必须带serverTimezone=Asia/Shanghai,否则返回的时间比实际晚8小时。还有一个容易踩的坑是数据库连接池和系统时区不一致,看起来数据存对了,前端一显示还是对不上,这时要看JDBC URL里的时区和操作系统时区是否统一。

4.5 评分重复提交与数据一致性问题

前端用户手快连点两次提交按钮,后端可能会收到两条一模一样的评分请求。很多课设项目的处理方式是前端加个loading变量挡住按钮,但这只能挡正常人,拦不了并发请求。更稳妥的方案就是我前面说的:评分表加联合唯一索引,后端Service里先查询后更新。即便Promsie的请求并发打到后端,数据库层面的唯一约束也能兜住最后一道防线。

我在实际压测时遇到过另一个数据问题:排行榜的平均分精度不对。MySQL里AVG函数算出来可能有小数,如果直接用Double接收,精度没问题;但如果你在前端显示前做了toFixed(2)处理,那数字是对的。要注意的是不要在SQL里提前ROUND,否则排序时可能出现两个对象平均分一样,排名不好看。排序时用原始的平均值排,展示时再格式化,体验最好。

最后再分享一点个人体会。这类课设项目拿到手,不要急着把代码跑起来就完事。我习惯先把数据库的ER关系画出来,搞懂每张表的关联;再打开Mapper XML,把所有SQL读一遍;最后再看Controller和Service的对应关系,看接口有没有按照统一规范做。这套流程走下来,你会对SSM分层、前后端联调、数据一致性产生非常直观的体感。等你把这个项目完整吃透,再换成自己想要的评分场景,比如饭店评分、课程评教、作品投票,只需要改表结构和少量业务代码就可以复用整个架构,这比从零写一套要高效得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询