简介:这份资源是一套面向毕业设计场景的大学生闲置物品交易小程序完整项目,基于微信小程序+SSM+MySQL开发,源码、数据库脚本、毕业论文与演示视频一并打包,适合计算机相关专业学生完成课题设计或快速搭建校园二手交易原型。压缩包共1180个文件,约51.16MB,涵盖小程序前端(wxml/wxss/js)、后台管理系统(vue、java、xml)、数据库sql文件以及运行环境配置脚本等,类型齐全且目录结构清晰,便于直接导入开发工具调试。目前已有162人学习下载,可用作课程设计参考或二次开发蓝本。除核心业务代码外,还附带环境安装批处理、项目配置备份与演示视频,帮助读者从环境启动到功能实现快速跑通全流程,节约前期摸索时间。
1. 大学生闲置物品交易小程序:一套SSM老栈毕业设计方案,值不值得动手
每年毕业季都能看到同一类选题:基于微信小程序 + SSM + MySql 的校园闲置交易平台。它之所以反复出现,是因为这个组合恰好卡在答辩老师和学生都能接受的中间地带——前端用小程序的原生语法,后端用教材里最常见的 SSM 框架(Spring + SpringMVC + MyBatis),数据库用 MySql,整套东西既不是纯网页项目,也没有引入 Spring Boot 这类更现代但超出课程大纲的框架。对于需要源码 + 数据库 + 毕业论文 + 视频演示一起交付的毕业设计场景,这套组合的成熟度非常高,网上可参考的同类项目多,出了问题也容易搜到答案。
这篇文章我会按一套可复现的顺序来拆:先把后端和数据库在本地跑起来,再做小程序端,最后讲联调阶段最容易翻车的地方。整个过程不需要你懂微服务或者分布式,只需要你有一台能装 MySql 和 JDK 的电脑,以及一个微信开发者工具。如果你正在为毕业设计选题或者接手类似项目头疼,这篇文章能帮你省下至少一周的试错时间。
2. SSM 后端与 MySql:为什么毕业设计还在用这套老组合,以及本地跑通后端的最小步骤
2.1 SSM 选型逻辑:对比 Spring Boot,SSM 到底输在哪、赢在哪
先说一个很多人不愿意承认的事实:SSM 在实际企业开发里已经基本被 Spring Boot 取代了。但毕业设计选 SSM,并不是老师不懂行情,而是课程体系没跟上。大多数高校的 Java 课程还在讲 Spring 的 XML 配置、SpringMVC 的注解控制器、MyBatis 的 mapper 映射,这和你实习时用的 Spring Boot 有代差。如果你在 SSM 项目里硬引入 Spring Boot 和 MyBatis-Plus,答辩时反而会问得更多:为什么不用 XML 配置?自动配置的原理是什么?到时候解释不清楚,分数反而不如老老实实用 SSM。
从落地角度看,SSM 项目有一个硬优势:它跑在 Tomcat 上,以 war 包形式部署,这和教材里的实验环境完全一致。MySql 建库建表、导入 .sql 文件、修改 jdbc.properties 数据库连接串,这一套流程在任何一台 Windows 电脑上都能复现。而 Spring Boot 的内嵌 Tomcat 对很多学生来说是黑匣子,出了问题不知道怎么排查。我见过不少用 Spring Boot 做毕业设计的人卡在打包这一步,反而用 SSM 的同学半小时就跑通了。
所以结论是:如果目标是顺利毕业、快速交付,SSM 不是坏选择;如果目标是往后找工作,你需要额外补 Spring Boot。这篇博文按 SSM 来讲,因为这就是大多数同类项目交付物的真实状态。
2.2 拿到源码包后第一步:先看目录,别急着点运行
不管你是从学长那边拷来的项目,还是网上找的“大学生闲置物品交易小程序”源码包,第一件事不是启动 IDE,而是把压缩包解开,按下面这个清单核对目录结构。SSM 项目的目录结构非常固定,缺了任何一个关键部分,后面都会浪费时间。
project-root/ ├── pom.xml // Maven 依赖管理,SSM 项目必须有 ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/xxx/controller/ // SpringMVC 控制器 │ │ │ └── com/xxx/service/ // 业务逻辑层接口 │ │ │ └── com/xxx/mapper/ // MyBatis 数据访问接口 │ │ ├── resources/ │ │ │ ├── jdbc.properties // 数据库连接配置 │ │ │ ├── spring-mvc.xml // SpringMVC 配置 │ │ │ └── mybatis-config.xml // MyBatis 全局配置 │ │ └── webapp/ │ │ └── WEB-INF/web.xml // Web 应用描述符 │ └── test/ // 测试代码,非必需 └── sql/ └── campus_secondhand.sql // 数据库初始化脚本核对完目录后,用 IDEA 以 Maven 项目方式导入。这里有一个常见的坑:很多学生直接把解压后的文件夹拖进 IDEA,导致 Maven 依赖没有解析。正确做法是File -> New -> Project from Existing Sources,选择 pom.xml,然后等 IDEA 右下角 Maven 依赖下载完成。如果你用的是 JDK 17 而项目是基于 JDK 8 编译的,大概率会报UnsupportedClassVersionError,这时需要装一个 JDK 8 并切换 Project Structure 里的 SDK。
2.3 初始化 MySql 数据库:用命令行还是图形工具,参数怎么设
SSM 项目的数据访问层基于 MyBatis,它需要连接一个真实存在的 MySql 实例。数据库初始化这一步,我推荐你用 Navicat 或者 dbx 这类数据库工具执行 .sql 脚本,而不是在 IDEA 里折腾。原因是 .sql 文件可能包含多语句、触发器或者存储过程,图形工具的执行日志更直观,报错时能看到具体行号。
先在你的 MySql 里创建一个单独的用户,不要直接拿 root 来用。原因很简单,jdbc.properties 里如果写了 root 密码,代码一旦泄露,整台数据库等于裸奔。虽然是本地开发,但养成分离用户的习惯没有坏处。
CREATE DATABASE campus_secondhand DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'campus_app'@'localhost' IDENTIFIED BY 'Campus@2024'; GRANT ALL PRIVILEGES ON campus_secondhand.* TO 'campus_app'@'localhost'; FLUSH PRIVILEGES;然后执行项目 sql 目录下的初始化脚本。如果脚本是按库名导出的,工具会直接创建表;如果是按表导出的,你需要先手动选中刚才创建的campus_secondhand库再导入。导入后重点验证三张核心表:用户表、商品表、订单表。你可以用下面这条 SQL 快速确认:
USE campus_secondhand; SHOW TABLES; SELECT COUNT(*) FROM t_user; SELECT COUNT(*) FROM t_goods; SELECT COUNT(*) FROM t_order;执行完如果没有报错,说明数据库这一侧基本就绪。常见的报错集中在两种:一种是Unknown database,说明脚本开头没有建库语句而你又没选中目标库;另一种是Incorrect table definition,说明脚本里的字段类型和 MySql 版本不兼容,比如 MySql 5.7 不支持某些 8.0 的默认值写法。遇到这类问题直接改脚本比重新找项目更省时间。
2.4 修改 jdbc.properties 并启动 Tomcat:端口、时区、编码三个必调参数
数据库就绪后,把项目里的 jdbc.properties 改成你自己的连接信息。这个文件在src/main/resources下,内容一般是这样的:
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/campus_secondhand?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai jdbc.username=campus_app jdbc.password=Campus@2024有三个参数要说明一下。useSSL=false必须加,因为 MySql 5.7 之后默认开启 SSL 握手,本地开发环境没有配置证书,不加这个参数会报Communications link failure或者 SSL 连接错误。serverTimezone=Asia/Shanghai必须加,否则 MySql 8.0 的驱动会拿服务器默认时区去解析,导致时间字段差 8 个小时,你明明发布了一分钟前的商品,列表上却显示三小时前。characterEncoding=utf8和useUnicode=true要同时出现,只写其中一个时,中文写入数据库容易出现乱码。
改完后在 IDEA 里配置 Tomcat。点Run -> Edit Configurations -> 加号 -> Tomcat Server -> Local,注意 Deployment 标签页里要把 war exploded 加上,Application context 填/,不要填项目名。为什么不填项目名?因为小程序端的wx.request请求 URL 是写死在代码里的,如果后端上下文路径是/ssm_secondhand,那你所有接口都得带上这个前缀。本地开发时统一用根路径/,联调最简单。启动 Tomcat 后看到控制台输出Spring MVC DispatcherServlet且没有异常堆栈,后端就算通了。
3. 核心表设计:商品、订单、用户三张表怎么建字段,才能让标签筛选和订单状态不翻车
3.1 用户表与商品表:外键该不该加,图片字段用 VARCHAR 还是 TEXT
数据库设计这部分,是毕业论文里占篇幅最多的内容,也是答辩老师最爱追问的地方。你不要照着网上随便一个 .sql 脚本背下来就完事,得能说清楚每个字段为什么这么设计。
先看用户表。男生女生都在同一个校园里交易,用户表通常不复杂,核心字段是学号、昵称、手机号、头像路径、微信 openid。openid 是唯一索引,这是小程序登录态的关键。一个容易踩坑的点是:openid 的字符长度。微信返回的 openid 是 28 位左右,但如果你用了 VARCHAR(32),在模拟器和真机上都能跑,但入库时如果微信以后调整了格式,长度就不够了。做毕业设计不用预留太多,但直接给 VARCHAR(64) 没有坏处。
商品表是最容易设计出问题的一张表,因为“闲置物品”天然有分类和图片需求。常见做法是给商品表加category_id用整数关联分类表,而不是直接存字符串。为什么?因为小程序端的分类筛选是高频操作,用字符串存储意味着每次筛选都要做模糊匹配,索引失效不说,分类改名的时候所有商品数据都要跟着改。用整数外键关联一张只有几十行的分类表,后续扩展基本不需要动商品表。图片字段别用 TEXT,TEXT 在 MyBatis 里映射成字符串没问题,但在 MySql 里 TEXT 不能有默认值,而且排序和分组会被限制。正确做法是存图片的相对路径字符串,比如/upload/goods/20240615_001.jpg,用VARCHAR(255)。上传的图片文件放在 Tomcat 的虚拟目录里,数据库里只存路径,这样备份数据库时不会把图片文件也一起导出去。
3.2 订单表的状态机设计:10 个字段值得抄,状态字段用 TINYINT 不用 VARCHAR
订单表是这套小程序里最复杂的表,因为它要同时承载交易流程和纠纷追溯。一个真实的校园闲置交易,订单状态至少要有这些:待付款、待发货、待收货、已完成、已取消、退款中。所以状态字段不建议用 VARCHAR 直接存“已完成”这种中文,因为小程序端和后端都要根据状态切换按钮文案和操作逻辑,中文状态值一旦写错一个全等匹配就失效。实际项目里更常用 TINYINT 存状态码,0 代表待付款,1 代表已付款待发货,2 代表已发货待收货,3 代表已完成,4 代表已取消,5 代表退款中。
订单表必有的字段包括:订单号、买家 ID、卖家 ID、商品 ID、成交价格、数量、状态、创建时间、支付时间、收货地址。订单号不要用数据库自增 ID,因为自增 ID 容易被遍历,而且联调时日志里看到订单号10086你根本不知道是哪笔。更常见的做法是用时间戳 + 随机数生成字符串订单号,代码写起来也不复杂。在 MyBatis 的插入语句里用useGeneratedKeys="true"取回自增 ID 用于后续逻辑,但对外展示的订单号必须是业务生成的那串。
3.3 数据脚本的导入时序:先插分类再插商品,外键约束会教你做人
这一节讲一个很多人忽略的问题:数据库执行顺序。如果你的 .sql 脚本里有外键约束,那么插入数据的顺序必须严格遵循从父表到子表的顺序,否则 MySql 会直接报Cannot add or update a child row: a foreign key constraint fails。对于闲置物品交易项目来说,就是先插分类表,再插用户表,然后插商品表,最后插订单表。
有一种情况特别折磨人:网上找的 .sql 脚本里,商品表的外键直接引用了用户表的 id,但用户表的数据在商品表之后插入,这时你执行整个脚本就会在中途失败。解决方案有两个,要么手动调整 INSERT 语句的顺序,要么先禁用外键检查再执行:
SET FOREIGN_KEY_CHECKS = 0; -- 在这里执行整个 .sql 脚本 SET FOREIGN_KEY_CHECKS = 1;这个操作在 Navicat 里可以直接选“运行 SQL 文件”,它会自动处理外键顺序问题,但在命令行里你需要自己加这两句。另外,如果商品表要支持用户下架商品后订单仍然可查,外键设计上订单表关联的商品 ID 不应该带级联删除,而是只做逻辑删除(加一个deleted字段)。否则用户删除商品记录,订单表的外键会连带把订单也删掉,这在真实场景里是严重事故,做毕业设计也不会加分。
4. 微信小程序端:登录态、商品列表、发布页面和数据请求,四块必须手写清楚的代码
4.1 小程序端目录结构和 wx.request 封装:从 app.js 到 utils 的常规做法
微信小程序端的工程结构一般由微信开发者工具创建,但毕业设计项目里的代码通常会包含几个固定模块。前端页面至少要有这几块:首页(分类 + 商品列表)、发布页(表单 + 图片上传)、详情页、聊天或留言页、个人中心、订单列表。这些页面在pages目录下每个对应一个文件夹,里面是.wxml、.wxss、.js、.json四件套。
与后端通信的代码不要散落在每个页面里直接写wx.request,因为一旦后端接口地址要改,你得把所有页面逐个翻出来改,太容易漏。常规做法是在utils/request.js里封装一个公共请求方法,统一处理 baseURL、超时时间和错误提示。下面这段是这类项目里最常见的封装写法:
// utils/request.js const BASE_URL = 'http://localhost:8080'; function request(path, method = 'GET', data = {}) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + path, method: method, data: data, header: { 'Content-Type': 'application/json' }, timeout: 10000, success: (res) => { if (res.statusCode === 200) { resolve(res.data); } else if (res.statusCode === 401) { wx.showToast({ title: '登录已过期', icon: 'none' }); wx.navigateTo({ url: '/pages/login/login' }); reject(res); } else { wx.showToast({ title: '请求失败', icon: 'none' }); reject(res); } }, fail: (err) => { wx.showToast({ title: '网络异常', icon: 'none' }); reject(err); } }); }); } module.exports = { request, BASE_URL };注意这里的BASE_URL在真机调试时需要改成你的电脑局域网 IP,比如http://192.168.1.105:8080,不能用localhost。原因是手机上的小程序请求你电脑上的 Tomcat,localhost 指向的是手机自己。在微信开发者工具里勾选“不校验合法域名”后,本地开发可以不配置 HTTPS 证书,但真机预览时这个开关不生效,你需要在小程序后台把 request 合法域名加上,或者继续用开发者工具里的真机调试模式。
4.2 登录与 openid 换 session:不要每次都调 wx.login
常见的小程序登录实现,是页面加载后直接wx.login拿 code,然后传给后端,后端拿 code 换 openid。但很多初学者会犯一个错误:在onLoad里每次进页面都调用wx.login,导致后端每收到一个请求就重新生成一次登录态。正确做法是首次登录后将后端返回的 session 或 token 存到wx.setStorageSync,后续请求在 header 里带上这个 token,后端根据 token 识别用户,而不是每次都重新走微信登录流程。
用户表里的 openid 字段在后端代码中作为唯一业务主键使用。用户首次登录成功后,后端向用户表执行 INSERT,如果 openid 已存在则 UPDATE 最近登录时间。这一逻辑用 MyBatis 的SelectKey或ON DUPLICATE KEY UPDATE都能实现。放在毕业设计里,讲清楚这段逻辑,比单纯贴代码更能让答辩老师满意。
4.3 首页商品列表:`` 渲染和上拉加载更多的三个参数
商品列表页的 WXML 部分没什么难度,核心都在 JS 里的数据处理和分页参数。你要在 data 里维护三个关键值:pageNum(当前页码)、pageSize(每页数量)、hasMore(是否还有更多数据)。每次请求后端时,带上这三个参数,后端用 MyBatis 的LIMIT offset, size做分页,返回一个带总条数的 JSON。
小程序端实现“上拉加载更多”靠onReachBottom生命周期函数。下面这一段是列表请求的模板:
// pages/index/index.js const { request } = require('../../utils/request'); Page({ data: { goodsList: [], pageNum: 1, pageSize: 10, hasMore: true, categoryId: 0 }, onLoad() { this.loadGoods(true); }, onReachBottom() { if (this.data.hasMore) { this.loadGoods(false); } }, loadGoods(reset) { const pageNum = reset ? 1 : this.data.pageNum; request('/goods/list', 'GET', { pageNum, pageSize: this.data.pageSize, categoryId: this.data.categoryId }).then((res) => { const list = reset ? res.data.list : this.data.goodsList.concat(res.data.list); this.setData({ goodsList: list, pageNum: pageNum + 1, hasMore: res.data.list.length >= this.data.pageSize }); }); } });分页有一个容易忽略的边界:如果后端返回的 list 长度小于 pageSize,hasMore必须设为 false,否则用户滑到底部时会继续发请求,每次返回 0 条数据,白耗流量和等待时间。另外,下拉刷新时记得把pageNum重置为 1,否则列表会从第 2 页开始叠加,出现数据重复和漏数据。这个 bug 非常隐蔽,我见过不止一个项目在联调时出现“下拉刷新后第一页商品被重复展示”的现象。
4.4 图片上传:wx.chooseMedia 到 wx.uploadFile,后端要配虚拟目录
发布闲置物品时,用户需要上传商品图片。小程序端用wx.chooseMedia选择图片,然后用wx.uploadFile上传到后端的接口。上传接口不能用前面封装的request方法,因为wx.uploadFile走的是 multipart 表单格式。后端需要用一个能接收MultipartFile的接口来接文件,然后保存到服务器本地目录,并把访问路径返回给前端。前端拿到路径后,再把这个路径塞进商品表单一起提交。
上传路径的配置有一个血泪教训:图片保存的目录如果放在 IDEA 的工作目录下,重启 Tomcat 后图片可能显示 404。更稳妥的是在 Tomcat 的conf/server.xml的 Host 节点下配置虚拟目录映射,把上传目录映射成一个/upload的访问路径。这样图片文件不会随着项目重新部署而丢失。如果是做毕业设计,你也可以把图片直接存到项目 webapp 下的 upload 目录里,但要在 .gitignore 里排除这个目录,否则源码打包时会把一堆测试图片也带进去。
5. 联调避坑:小程序连不上后端、图片 404、MySql 时区和 SSL 报错的 5 条实战排查记录
5.1 现象:小程序 request 请求一直转圈,控制台报request:fail,但后端接口用浏览器能访问
这是一个典型的跨域之外的网络连通问题。首先确认后端 Tomcat 启动时监听的端口,默认 8080。然后检查小程序工具右上角的“详情 -> 本地设置”里是否勾选了“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”。开发者工具有时更新后这个选项会被重置。其次,把BASE_URL从https://改成http://,并检查电脑防火墙是否拦截了 8080 端口的入站连接。Windows 上运行 Tomcat 第一次启动时,系统会弹出防火墙授权对话框,很多人直接点了取消,结果后面所有请求都失败。解决路径是:控制面板 -> Windows Defender 防火墙 -> 允许应用通过防火墙 -> 添加 Tomcat,或者临时关掉防火墙测试联通性。
还有一种情况:后端接口在浏览器里直接访问没问题,但小程序里就是失败。打开开发者工具的 Network 面板看具体报错。如果错误码是ENETUNREACH,说明你的电脑和小程序模拟器之间的网络隔离有问题,常见于公司或学校局域网开了 AP 隔离。这时换成手机真机调试并连接同一个 Wi-Fi,通常能绕过模拟器的网络限制。
5.2 现象:MySql 8.0 启动后控制台抛The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized
这个报错看起来像中文乱码,实际是 MySql 8.0 驱动要求明确指定时区,而服务器默认时区无法被驱动识别。解决方式是在 jdbc.properties 连接串里追加serverTimezone=Asia/Shanghai,前面已经提过。但如果你的 MySql 装在海外 VPS 上,Asia/Shanghai不一定被系统时区数据库支持,更通用的写法是serverTimezone=GMT%2B8(%2B 是 + 的 URL 编码)。改完后重启 Tomcat 并重新测试数据库连接。这个问题在mysql-connector-java5.1.47 之前的版本里基本不出现,换用 8.0 版驱动后高频出现,所以网上搜mysql ssl连接错误或mysql 时区报错找到的大多是同一个答案。
5.3 现象:商品图片上传成功,详情页能拿到路径,但<image>标签显示空白
这个问题的原因一般不在后端,而在小程序端地址拼接。后端返回的路径如果是/upload/goods/xxx.jpg,这是相对路径。小程序端的<image>标签里的 src 如果直接填这个相对路径,它会去小程序的静态资源目录找,自然找不到。正确做法是把BASE_URL和相对路径拼成完整 URL:src="{{BASE_URL + goods.imageUrl}}"。可以在app.js的globalData里维护一个baseUrl,所有页面从getApp().globalData.baseUrl取值。
另外还要确认后端返回的图片路径字段名和前端渲染时用的字段名一致。由于 SSM 项目的实体类字段命名习惯不一致,有的返回image,有的返回imageUrl,小程序端取不到值时会渲染空白,控制台不报错,特别难查。遇到这种情况,打开 Network 面板看后端接口的实际返回 JSON,逐字段对照前端绑定。
5.4 现象:发布商品时提示“该用户不存在”或“登录态失效”,但刚刚还能登录
SSM 项目里常见的登录态实现是后端拦截器检查 session 里的用户 ID。小程序端请求列表页、详情页通常不需要登录,但发布、下单、收藏这些接口需要。前端代码为了省事,可能把用户 ID 直接写死在请求参数里,比如userId: 1。后端接收后去用户表查,发现用户 ID 不存在,就会报这个错。
解决方式分两层。第一层,后端拦截器里对需要登录的接口做统一校验,没有有效 session 直接返回 401,前端统一跳登录页。第二层,小程序端每次启动时调用wx.checkSession检查登录态是否过期,过期则重新走wx.login。很多现成的源码包在这块做得很潦草,直接把userId写死在全局变量里,换成另一个微信号测试就翻车。你在本地改代码时,优先把“获取当前登录用户”抽成一个公共方法,不要在业务页面里硬编码用户 ID。
5.5 现象:商品列表明明有数据,但小程序里只渲染前几条,滑到底部后不再触发加载
这个问题 90% 是onReachBottom没有触发,而不是后端数据问题。onReachBottom触发依赖页面的可滚动区域是页面本身,而不是某一个内部 scroll-view。如果在 WXML 里写了scroll-view并且设置了固定高度,页面整体没有向下滚动的空间,onReachBottom永远不会触发。要么去掉 scroll-view 改用页面默认滚动,要么在 scroll-view 上绑定bindscrolltolower。两种方式的效果一样,但触发函数名不同,混用则列表永远加载不出第二页。如果你一定要用 scroll-view 实现自定义导航栏吸顶,记得给页面根节点设置height: 100%,并给 scroll-view 设置flex: 1,否则会出现滚动区域高度塌陷,同样表现为无法触底加载。
6. 从能跑到能答辩:写清验证用例、订单状态流转说明,顺手加一个日期筛选
这章不写大段代码,聊两个实际技巧。先说验证用例。毕业论文和答辩时,老师最反感的是“功能能点,但说不出哪里测过”。你在交付前,至少要跑通一组手工用例:未登录用户进入商品列表并尝试收藏,弹出登录引导;登录后切换分类筛选,列表无重复数据;发布一件商品,图片上传成功且详情页能展示;下单后卖家端订单状态从待付款变为待发货,买家确认收货后状态变为已完成;用户退出登录后访问个人中心,被拦截回登录页。把这些结果截图放进论文的“系统测试”章节,比写一千字测试理论更有说服力。
第二个技巧是给商品列表加一个时间筛选。虽然这属于功能扩展,但能直接体现你对 SQL 的掌握程度。在后端 Service 里加两个参数startDate和endDate,对应的 MyBatis 动态 SQL 用<if>标签拼接条件:
<select id="selectGoodsByCondition" resultType="com.xxx.entity.Goods"> SELECT * FROM t_goods WHERE deleted = 0 <if test="startDate != null"> AND create_time >= #{startDate} </if> <if test="endDate != null"> AND create_time <= #{endDate} </if> ORDER BY create_time DESC </select>这里注意一个小细节:#{endDate}的边界值用<=,用户选“到 6 月 15 日”,那 6 月 15 日当天的数据应该包含进来。如果写成<就会少一天数据,属于边界条件没想清楚,答辩时被问到很容易卡壳。你可以在代码里把 endDate 自动加一天,或者 SQL 里用< DATE_ADD(#{endDate}, INTERVAL 1 DAY),二选一即可。
最后说一句自我习惯。我每次交付这种毕业设计项目,都会先把数据库的导出脚本重新执行一遍,用全新的空库跑整个业务流程,确保前端、后端、数据库三者之间没有隐藏的环境依赖。很多项目在开发机上跑得好好的,换一台电脑就崩,原因就是数据库里残留了手工插入的测试数据或临时表。做毕业设计也一样:交付的 .sql 脚本必须能在一个干净的 MySql 实例上跑通,否则导师拿到的就是个“在你电脑上才能运行”的成果,这在答辩时是致命的。希望你做完这套项目后也能保持这个习惯,至少能让自己少一次半夜改 bug 的经历。希望帮到你。
本文还有配套的精品资源,点击获取