又到了一年两度的毕设季节,后台私信里一大半都是同一个问题:Spring Boot 项目到底怎么做。说实话,“基于 Spring Boot 的校园闲置物品租赁系统”这个题,在我带过的学生项目里出现频率相当高,属于典型的“性价比选手”——业务场景贴近学生生活、功能好拆解、技术栈主流、答辩时又有故事可讲。但它也不是那种随便抄个开源项目就能糊弄过去的题:租赁流程的订单状态管理、物品发布与审核、用户权限控制,这几个点如果没想清楚就急着写代码,后期会反复返工。
这篇文章我就以这个项目为主线,把我实际带项目时的完整思路、核心实现、安装部署流程,以及写文档、准备答辩的心得全部梳理一遍。项目本身不复杂,但我会重点讲清楚“为什么这样做”,还会把容易踩坑的地方单独列出来。不管你是准备拿这个题目做毕业设计,还是刚学完 Spring Boot 想找个完整项目练手,这份内容都能让你少走不少弯路。
1. 项目整体设计与技术选型
1.1 业务场景与核心功能
校园闲置物品租赁,说白了就是把学生手里那些“用不上但扔了可惜”的东西盘活。我接触过的实际场景里,主力物品是这些:自行车、相机镜头、专业课教材、游戏机、正装礼服,甚至还有一些小家电。这些物品的特点是单价相对较高、使用频率低、学生之间又有天然的信任基础——都在一个校区,出了问题跑得了和尚跑不了庙。
所以这个系统的核心业务流程就要解决三个问题:卖家怎么把闲置物品展示出来、买家怎么找到并租下物品、交易过程中双方怎么保障权益。我给出的模块划分是这样的:
- 用户端:注册登录、物品浏览与搜索、发布闲置、发起租赁、订单支付确认(简化版)、订单管理、个人资料管理
- 管理端:用户管理、物品审核与下架、租赁订单查看与干预、系统公告发布、数据统计
这里我特别强调一个点:闲置物品不是上架就能租的,得有一个“管理员审核”环节。很多同学觉得这步是多余的,直接做“发布即上架”会省很多事。但从实际业务角度看,如果没有审核,广告、违规物品、重复信息会直接淹没真实物品。从毕设答辩角度看,多一个审核环节,你的系统就多了一个角色、多了一层权限控制,技术亮点和业务完整性都能提上去。利大于弊,值得做。
1.2 为什么选 Spring Boot + MyBatis-Plus + MySQL
这个技术组合在Java毕设里算是“标准答案”了,但我还是想说说每个组件在项目里具体承担什么职责,免得你只是听说过名字就往上堆。
Spring Boot负责把整个应用的骨架搭起来。它最实用的地方是自动配置和 starter 机制——引入一个依赖,框架自动帮你把对应的组件初始化好,你只需要写业务代码。比如引入spring-boot-starter-web,内嵌 Tomcat、MVC 配置、JSON 序列化这些都备好了;引入mybatis-plus-boot-starter,数据源和 MyBatis 的组装也不用你操心。相比传统 SSM 时代那一堆 XML 配置,Spring Boot 对新手友好太多了。
MyBatis-Plus选它的核心理由是开发效率。它是 MyBatis 的增强工具,内置了通用的增删改查方法,单表操作根本不用写 SQL,直接调baseMapper.selectPage、baseMapper.insert就行。一个物品表、用户表、订单表的基础 CRUD 代码量能省掉一半以上。而且它支持分页插件、条件构造器QueryWrapper,写复杂查询的时候比手拼 SQL 直观得多。
MySQL这边不用多说,关系型数据模型天然适合租赁系统这类结构化业务数据。我建库的时候统一用 utf8mb4 字符集,因为商品描述里经常出现 emoji、特殊符号,utf8mb4 才能完整存储。存储引擎选 InnoDB,支持事务,租赁订单这种涉及资金和状态变更的数据必须有事务兜底。
1.3 前端方案的选择建议
关于前端,我知道这个问题一定有人纠结。我给你的建议很直接:如果想快速把系统跑通、把精力集中在后端上,用 Thymeleaf 模板引擎 + Bootstrap + jQuery 是最稳妥的方案。Spring Boot 对 Thymeleaf 的支持很成熟,页面直接写在templates目录下,Controller 返回视图名就能渲染,前后端不用联动调试,一个人就能搞定。
如果你已经学了 Vue,或者想给简历上加一个“前后端分离”的项目经验,那可以用 Vue 3 + Element Plus + Axios,后端只提供 JSON 接口。这个方案看着高级,但代价是工作量明显增加:跨域处理、Token 传递、异步渲染、打包部署,每一步都会消耗时间。我的建议是:预留充足时间、有一定前端基础,就上前后端分离;时间紧、求稳,就 Thymeleaf。不要两头摇摆,做毕设最忌讳中途换技术栈。
2. 数据库设计与核心模型构建
2.1 核心表结构的设计思路
数据库设计是这个项目最先要打好的地基。我见过太多项目代码写到一半发现表结构不合理,又回头改表,连带改实体类、改 Mapper、改页面,工作量翻倍。所以我会先花一整天时间把表设计反复推演清楚再动工。
这个项目我最终设计了6张核心表:
user用户表:id、username、password、nickname、phone、avatar、role(0用户 1管理员)、status、create_timecategory物品分类表:id、name、sort、create_timeitem物品表:id、user_id、category_id、title、description、price_per_day、deposit、images、status(0待审核 1上架 2已下架 3已租出)、view_count、create_timerental_order租赁订单表:id、order_no、item_id、lessee_id(承租方)、lessor_id(出租方)、start_date、end_date、total_amount、deposit、status(0待支付 1租赁中 2待归还 3已完成 4已取消 5申请归还)、create_timemessage留言表:id、item_id、from_user_id、to_user_id、content、create_timenotice公告表:id、title、content、create_time
有一点要提醒:物品表里的images字段我设计的是 varchar 类型,多张图片用逗号分隔存储,例如url1,url2,url3。这种做法在规范化的数据库设计课里可能不够“正统”,但在实际项目里非常实用——减少关联查询、读取快、实现简单。你要在文档里被别人问起为什么这么设计,答一句“图片查询频率高、数量有限、逗号分隔可以避免多次 IO”就完全能站住脚。
2.2 租赁订单状态机设计
订单状态是这个系统里业务逻辑最复杂的部分,也是答辩时老师最喜欢追问的地方。我按实际租赁流程把它拆成了6个状态:
| 状态值 | 含义 | 说明 |
|---|---|---|
| 0 | 待支付 | 买家发起租赁申请,生成订单,等待支付 |
| 1 | 租赁中 | 买家支付,卖家确认,租期开始计算 |
| 2 | 待归还 | 买家点击“申请归还”,等待卖家确认 |
| 3 | 已完成 | 卖家确认归还,订单结束 |
| 4 | 已取消 | 买家支付前取消订单,或超时未支付自动取消 |
| 5 | 已拒绝 | 卖家不同意出租,订单终止 |
这个状态机的流转规则是这样的:0 → 1(支付成功)→ 2(申请归还)→ 3(确认归还),其中 0 可以回到 4,0 可以跳到 5。我在代码里没有用复杂的状态机框架,就写了一个OrderStatusUtil工具类,专门负责校验状态流转是否合法。比如判断当前状态是 1(租赁中),才允许走“申请归还”;状态不是 0 就不允许支付。这种轻量级的状态校验对毕设项目来说完全够用,而且代码可读性比引入状态机框架好很多。
这里有个容易忽略的小细节:订单编号order_no要用时间戳 + 随机数生成,别用数据库自增主键直接当业务编号展示给用户。原因有两个,一是订单号会暴露系统的真实订单量,这既不好看也不安全;二是后续对接支付、对账,业务号与主键分离会更灵活。我用的格式是yyyyMMddHHmmss + 4位随机数,实测下来并发场景下基本不会重复。
2.3 表单校验与数据字典设计
数据库层面的规范差不多后,一个影响开发体验的细节是数据字典的统一。比如物品状态的枚举值,我在表里用的是 0 到 3 的数字,前端页面总不能直接显示“0”吧?所以我在项目里建了一个ItemStatusEnum,把数字和中文描述映射起来:
public enum ItemStatusEnum { PENDING(0, "待审核"), ON_SALE(1, "上架中"), OFF_SHELF(2, "已下架"), RENTED(3, "已租出"); private final Integer code; private final String desc; ItemStatusEnum(Integer code, String desc) { this.code = code; this.desc = desc; } public static String getDescByCode(Integer code) { for (ItemStatusEnum itemStatusEnum : values()) { if (itemStatusEnum.getCode().equals(code)) { return itemStatusEnum.getDesc(); } } return "未知状态"; } public Integer getCode() { return code; } public String getDesc() { return desc; } }后端返回给前端的数据里,除了放状态值,再附带一个状态描述字段,前端直接渲染描述,不用在页面上写一大堆 if 判断。这个习惯在文档、答辩演示的时候观感也特别好,说明你有“数据字典”和“枚举语义化”的意识。
3. 后端核心代码实现详解
3.1 四层架构与项目目录组织
Spring Boot 项目里常说的四层架构,就是 Controller(控制层)、Service(业务层)、Mapper(持久层)、Entity(实体层)。有同学会把它和“架构设计”这种高大上的词挂钩,其实它就是告诉你:写代码要分层,每层各司其职,别把业务逻辑全堆在 Controller 里。
我建的项目目录结构是这样的,你可以直接照抄:
com.campus.rental ├── common // 公共类:返回结果、常量、异常处理 │ ├── Result.java │ ├── ResultCode.java │ ├── BusinessException.java │ └── GlobalExceptionHandler.java ├── config // 配置类:MyBatis-Plus分页、拦截器、跨域 ├── controller // 控制层:接收请求、参数校验、返回结果 ├── entity // 实体层:与数据库表对应的JavaBean ├── mapper // 持久层:MyBatis-Plus的BaseMapper接口 ├── service // 业务层:接口 + 实现类 │ ├── ItemService.java │ └── impl │ └── ItemServiceImpl.java └── utils // 工具类:JWT工具、文件上传工具等这个结构有几个好处。第一,嵌套层次少,从入口到数据库一目了然,刚接手项目的人十分钟就能看懂。第二,每层之间单向依赖,Controller依赖Service接口,Service依赖Mapper接口,实现类细节被藏在接口后面,改实现不影响上层。第三,答辩时老师问“你项目怎么分层的”,你对着目录就能讲得头头是道,每个层作用、请求怎么流转、每一层做什么校验,这些全都是送分题。
3.2 统一返回结果与全局异常处理
我特别建议大家在一开始就把“统一返回结果”这件事做了,因为我见过很多项目是每个接口自己返回 Map 或者直接返回实体类,到前端取数据的时候五花八门,后期维护想哭。
我定义了一个Result<T>泛型类,结构就三个字段:code(状态码)、message(提示信息)、data(业务数据)。所有接口不管成功失败,都返回这个格式:
public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success() { return new Result<>(ResultCode.SUCCESS.getCode(), "操作成功", null); } public static <T> Result<T> success(T data) { return new Result<>(ResultCode.SUCCESS.getCode(), "操作成功", data); } public static <T> Result<T> error(String message) { return new Result<>(ResultCode.ERROR.getCode(), message, null); } public static <T> Result<T> error(Integer code, String message) { return new Result<>(code, message, null); } }然后是全局异常处理。Spring Boot 提供了@RestControllerAdvice注解,可以拦截所有 Controller 抛出的异常并统一处理。我在这里面写了三个@ExceptionHandler:一个处理业务异常BusinessException,一个处理参数校验异常MethodArgumentNotValidException,一个兜底处理Exception。这么做的好处是:Service 层发现业务不合法(比如“物品已被租出”“订单状态不允许支付”)时,直接throw new BusinessException("物品已被租出")就行,不用在每个接口里写 try-catch,异常信息能统一格式、统一状态码返回给前端。
3.3 用户认证与权限控制
登录认证我推荐用 JWT,也就是 JSON Web Token。它的工作流程是:用户登录成功后,后端生成一个包含用户 id、角色等信息的 Token 返回给前端;前端在后续请求的 Header 里带上这个 Token;后端通过拦截器解析 Token,拿到当前登录用户的信息。
用 JWT 而不是传统 Session 的核心原因是它是无状态的,服务端不需要保存登录状态,水平扩展的时候不需要考虑 Session 同步问题。虽然毕设项目一般没有高并发场景,但“无状态认证”这个点在简历上和答辩里都是个可以展开讲的亮点。
后端拦截器做权限控制,核心代码是这样的:
public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录、注册等不需要认证的接口 if (request.getRequestURI().contains("/user/login") || request.getRequestURI().contains("/user/register")) { return true; } // 从Header中获取Token String token = request.getHeader("Authorization"); if (StringUtils.hasText(token)) { try { // 解析Token,把用户信息放进request上下文 Claims claims = JwtUtil.parseToken(token.replace("Bearer ", "")); request.setAttribute("userId", claims.get("userId")); request.setAttribute("userRole", claims.get("role")); return true; } catch (Exception e) { // Token无效或过期 } } response.setStatus(HttpStatus.UNAUTHORIZED.value()); return false; } }管理员功能的校验也在这里做:判断当前用户角色是否为 1,如果不是就直接返回“无权限访问”。我用的是拦截器 + 自定义注解@RequireAdmin的组合,在需要管理员权限的接口上打一个注解,代码会更整洁。
3.4 租赁订单业务逻辑的实现要点
租赁订单是系统里最核心的业务,我把下单流程完整写一遍。用户在前端选好物品、选定租赁起始日期,点“立即租赁”,后端做这几件事:
@Override @Transactional(rollbackFor = Exception.class) public Result<String> createOrder(RentalOrderCreateDTO dto, Long userId) { // 1. 校验物品存在且状态为上架中 Item item = itemMapper.selectById(dto.getItemId()); if (item == null || !ItemStatusEnum.ON_SALE.getCode().equals(item.getStatus())) { throw new BusinessException("物品不存在或不可租赁"); } // 2. 校验租赁时间合法(开始时间不能早于今天,结束时间不能早于开始时间) if (dto.getStartDate().isBefore(LocalDate.now()) || dto.getEndDate().isBefore(dto.getStartDate())) { throw new BusinessException("租赁日期不合法"); } // 3. 校验物品在所选时间段内没有被其他订单占用 long conflictCount = rentalOrderMapper.selectCount(new QueryWrapper<RentalOrder>() .eq("item_id", dto.getItemId()) .in("status", Arrays.asList(0, 1, 2)) // 待支付、租赁中、待归还 .and(wrapper -> wrapper .le("start_date", dto.getEndDate()) .ge("end_date", dto.getStartDate()))); if (conflictCount > 0) { throw new BusinessException("该物品在所选时间段已被预订"); } // 4. 计算租金(按天计算) long days = ChronoUnit.DAYS.between(dto.getStartDate(), dto.getEndDate()); BigDecimal totalAmount = item.getPricePerDay() .multiply(BigDecimal.valueOf(days)); // 5. 生成订单并修改物品状态为已租出 RentalOrder order = new RentalOrder(); order.setOrderNo(generateOrderNo()); order.setItemId(item.getId()); order.setLesseeId(userId); order.setLessorId(item.getUserId()); order.setStartDate(dto.getStartDate()); order.setEndDate(dto.getEndDate()); order.setTotalAmount(totalAmount); order.setDeposit(item.getDeposit()); order.setStatus(RentalOrderStatus.PENDING_PAYMENT.getCode()); rentalOrderMapper.insert(order); item.setStatus(ItemStatusEnum.RENTED.getCode()); itemMapper.updateById(item); return Result.success(order.getOrderNo()); }这里我用了@Transactional事务注解,因为生成订单和修改物品状态是两个数据库操作,必须保证“同生共死”,否则会出现订单生成了但物品状态没改的脏数据。时间冲突校验我用了查重逻辑:凡是待支付、租赁中、待归还状态的订单,只要它的租期区间和新的租期区间有重叠,就算冲突。这个查询是租赁系统业务正确性的关键,也是答辩时可以重点讲的一个点。
3.5 文件上传与图片存储
物品图片上传是必做的功能。spring-boot-starter-web已经封装好了文件上传能力,我只要写一个配置(设置单个文件大小限制)和 Controller 接收MultipartFile就行。
存储路径我建议这样规划:在项目的resources/static/upload/目录下按“日期”建文件夹存放,比如upload/2025-05-20/xxx.jpg。后端把文件保存后,返回给前端一个可直接访问的图片 URL。这里有个容易踩的坑:如果你用了自定义的WebMvcConfigurer拦截静态资源,一定要把/upload/**这个路径放行,否则图片加载不出来。
我实际带项目时还遇到过中文文件名乱码、图片尺寸过大等问题,处理方式是:保存文件名一律用 UUID 重命名,后缀保留原始格式,这样既避免乱码也避免重名覆盖;上传前判断文件大小和类型,图片只允许 jpg、png、gif 这三种格式,单个文件限制在 5MB 以内。
4. 安装调试、打包部署与常见问题
4.1 本地开发环境搭建
我在指导项目的时候,最怕听到的话是“我环境都配好了,就是项目跑不起来”。环境问题看着琐碎,但排查起来特别浪费时间。这里我把标准配置列出来,照着做基本一次通过:
| 组件 | 版本建议 | 说明 |
|---|---|---|
| JDK | 1.8 或 11 | Spring Boot 2.x 都兼容,JDK 8 最稳 |
| Maven | 3.6+ | 管理依赖,IDEA 自带也可 |
| MySQL | 5.7 或 8.0 | 5.7 资料多,8.0 性能好,均可 |
| IDEA | 2022 及以上 | 社区版即可,不用破解 |
| Navicat 或 DataGrip | 任意 | 数据库可视化工具,非必须,SQL 命令行也行 |
JDK 安装有一个特别容易被坑的点:环境变量JAVA_HOME的路径不能有中文和空格。我之前见过一位学生的电脑用户名是中文,导致 Tomcat 启动时 JDK 路径解析失败,报错报得莫名其妙,最后只能换一个纯英文路径的 JDK 重装一遍才解决。如果你遇到这种问题,别暴躁,先检查路径。
Maven 依赖下载慢的问题也很好解决:在 Maven 的settings.xml里配置阿里云镜像仓库,把mirror指向https://maven.aliyun.com/repository/public,下载速度能快几十倍。这一步强烈建议提前配置,否则初次拉 Spring Boot 全家桶依赖的时候,等项目启动可能已经过完一个午休时间了。
4.2 项目导入与启动过程
IDEA 里导入项目的步骤比较固定:File → New → Project from Existing Sources,选择项目根的pom.xml,等着 Maven 把依赖下载完,千万别中途中断。依赖下载完成后,项目的 JDK 设置也要确认一下,打开 Project Structure 看 Project SDK 是否选到本机安装的 JDK。
然后是配置文件application.yml,数据库连接这里是最容易出问题的环节:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/campus_rental?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的数据库密码 servlet: multipart: max-file-size: 5MB max-request-size: 20MB mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0如果 MySQL 是 8.0 以上版本,driver-class-name必须写com.mysql.cj.jdbc.Driver,这是新版驱动的类名;老版本项目里常用的com.mysql.jdbc.Driver在 8.0 环境下会直接报ClassNotFoundException。serverTimezone=Asia/Shanghai这个参数也得加上,不然时间字段在存取的时候会差 8 个小时。
MyBatis-Plus 里那个log-impl配置是日志输出,启动后控制台能直接看到每条 SQL,调试查数据的时候非常有用。我第一次跑一个列表查询怎么都查不出数据,就是靠这行配置看了真实 SQL,发现是条件拼接多了个空串判断,一分钟就定位了。
4.3 启动报错的排查思路
Spring Boot 项目启动报错,90% 集中在三种情况。我按出现的频率排序,你排查的时候也按这个顺序来:
第一种,端口被占用。报错信息里有Port 8080 was already in use。处理方式很简单,找出占用进程杀掉,或者把server.port改成一个不常用的端口比如 8088。
第二种,数据库连接失败。报错信息通常是Cannot create PoolableConnectionFactory或者各种Communications link failure。检查三件事:MySQL 服务有没有启动、数据库名campus_rental存不存在、用户名密码对不对。最后这个看起来蠢,但实际情况是很多人把密码写在配置文件里时带了多余的空格,或者密码里有@这种特殊符号没做处理。
第三种,依赖版本冲突。报错信息里一堆NoClassDefFoundError或者BeanDefinitionStoreException,最常见的场景是 Spring Boot 版本和 MyBatis-Plus 版本不兼容。我这边验证过比较稳的搭配是 Spring Boot 2.7.x + MyBatis-Plus 3.5.x,你如果用了 Spring Boot 3.x,那就要配套用 MyBatis-Plus 3.5.3 以上的版本,因为 Spring Boot 3 是基于 Jakarta EE 的,很多包名都变了。
4.4 打包与部署经验
毕设项目一般有两种交付要求:一种是只要求能在 IDEA 里跑起来,另一种要求能生产一份可执行的 jar 包部署到服务器上。
如果要求打包部署,那就用 Maven 的 package 命令。打开 IDEA 右侧 Maven 面板,双击package,看到BUILD SUCCESS后,target目录下就会生成一个可执行的 jar 包。命令行运行java -jar campus-rental-0.0.1-SNAPSHOT.jar,只要本机能访问到 MySQL,项目就能跑起来。
这里有三个坑我替你踩过了:第一,打包前检查pom.xml里有没有加spring-boot-maven-plugin插件,不加这个插件打出的 jar 包不能直接运行;第二,如果用的是前后端分离项目,前端资源要先npm run build生成 dist 目录,再把静态文件拷贝到后端resources/static下一起打包,不然部署到服务器上页面是空的;第三,服务器上的 MySQL 数据库要提前把建表 SQL 执行一遍,千万别指望 jar 包能自动建表,项目里没有接 Flyway 之类的工具的话,表不存在就是启动即报错。
4.5 常见问题速查表
我把这些年经常遇到的问题整理成一张速查表,你可以直接收藏,遇到问题先来这里比对一下:
| 排查场景 | 典型报错或现象 | 处理方式 |
|---|---|---|
| 启动时端口被占 | Port 8080 was already in use | 改server.port或杀掉占用进程 |
| MySQL 连接失败 | Cannot create PoolableConnectionFactory | 检查 MySQL 服务、库名、账号密码 |
| 驱动类找不到 | ClassNotFoundException: com.mysql.jdbc.Driver | MySQL 8.0 改为com.mysql.cj.jdbc.Driver |
| 中文乱码 | 数据库数据乱码/页面乱码 | 统一 utf8mb4 字符集,连接串加characterEncoding=utf8 |
| 图片上传后无法访问 | 图片 404 | 静态资源拦截配置放行/upload/**路径 |
| 查询结果缺失字段 | 数据库有数据但查出来是 null | 加map-underscore-to-camel-case: true开启驼峰映射 |
| 打包后无法运行 | 没有主清单属性 | pom.xml添加spring-boot-maven-plugin |
| 跨域请求被拦截 | Access to XMLHttpRequest has been blocked by CORS | 配置CorsFilter或@CrossOrigin注解 |
5. 代码讲解与文档报告的组织思路
5.1 答辩时代码怎么讲
这个项目的代码量在一万行左右,答辩时不可能每一行都讲。老师的核心想知道的是:这系统是不是你自己做的、你清不清楚每个模块的原理、你遇到问题有没有排查能力。所以我的建议是:挑三条主线讲透,比面面俱到强得多。
第一条主线是请求流转路径。你拿起任意一个完整功能,比如“用户浏览物品列表”,从浏览器发起请求开始,到 Controller 接收参数、Service 处理业务、Mapper 查询数据库、结果组装返回,一条线走下来。讲的时候突出“分层设计”的思路,各层之间职责是怎么区分的,为什么这么分。
第二条主线是权限控制。先演示普通用户访问管理员接口被拦截的效果,再切到管理员账号访问同样的接口成功。讲的时候重点说 JWT 的构成、拦截器的工作原理、Token 的校验流程。这条线技术含量高,老师基本都会往这里面问。
第三条主线是租赁订单状态流转。拿一个真实订单从创建到完成的完整生命周期来说,配合数据库里的状态字段变化截图,把每一步业务规则讲清楚。这条线体现的是你对业务场景的理解深度,非常加分。
带上 id、角色等信息的 Token 返回给前端;前端在后续请求的 Header 里带上这个 Token;后端通过拦截器解析 Token,拿到当前登录用户的信息。
5.2 毕业设计论文的结构安排
论文的框架大体上是固定的,学校一般会给模板,但在内容填充上我有些心得可以分享。论文的章节通常这样分布:
- 第一章绪论:写研究背景和意义、国内外研究现状。写现状的时候不要空泛地抄别人的话,可以具体写“目前校园内的闲置物品处理多依赖 QQ 群、跳蚤市场,信息分散且缺乏交易担保”,这样更有真实感
- 第二章相关技术介绍:写 Spring Boot、MyBatis-Plus、MySQL、JWT 这些你用到的技术。这里要注意,每个技术写清楚“它是什么、为什么适合本项目”,不要大段复制官方文档,查重过不了
- 第三章需求分析:先画功能用例图,再分角色说明功能需求,最后补充非功能需求(性能、安全、易用性)
- 第四章系统设计:数据库设计(主要表和字段说明,附上 E-R 图)、系统架构设计(分层结构图)、核心流程设计(租赁流程图、权限验证流程图)
- 第五章系统实现:按功能模块逐个展示页面截图和核心代码片段,并配简要说明。页面截图配核心代码,这个组合是论文里最占篇幅也最直观的内容
- 第六章系统测试:写功能测试用例表、测试结果、性能测试简单数据
- 第七章总结与展望:总结系统完成的功能,再提几点未来的改进方向,比如接入真实支付、增加信用评价体系、基于推荐算法的物品推荐等
E-R 图我建议用 Draw.io 画,免费而且画出来比较干净。画的时候不需要把字段全部列出来,只要画出主要实体、关键属性、实体间的关联关系(一对一、一对多、多对多)就够了。流程图也可以用 Draw.io,状态机流转图等都可以画,答辩时放 PPT 里非常直观。
5.3 项目如何做二次亮点扩展
如果时间允许,我强烈建议在基础上加一两个加分功能。这样在答辩时你可以多一个亮点,也能避开“功能太简单”的评价。我推荐几个工作量和亮点都合适的扩展方向:
一个是数据分析可视化。管理员后台引入 ECharts,做一个简单的数据统计页面:按分类统计物品数量、按月份统计订单量趋势、展示热租物品 Top5。数据来源就是 order 表和时间字段,一个聚合查询就能拿到,但呈现效果非常直观,展示“数据分析能力”比很多花哨功能都管用。
另一个是消息通知。当物品被下单、订单状态变更时,给相关用户站内信通知或者邮件通知。用 Spring Boot 的异步事件@Async+ 邮件服务就能实现,代码量不大,但体现的是“用户体验”和“架构设计”的考量。
还有一个是操作日志。用 AOP 切面记录用户的关键操作(登录、下单、发布物品等)到一张日志表,管理员可以查看。这个功能体现了你对“系统安全”的理解,技术上用到 Spring AOP,也很有讲头。
6. 写在最后:几点掏心窝的建议
带过这么多毕设项目,我最想跟大家说的一句话是:毕设项目的核心目标不是“做出一个多完美的商业产品”,而是“把学校里学到的知识和技能,完整体验地串起来”。所以真正重要的是投入的过程,是你在动手过程中踩过的坑、翻过的源码、查过的资料,这些才是答辩时你能脱口而出的底气。
具体到时间规划上,我建议不要把所有事情拖到最后一个月。合理的节奏是:第一周完成需求分析和数据库设计,第二周到第三周完成后端主要功能,第四周做前端页面和联调,第五周整理测试用例并开始写论文,最后一周准备答辩 PPT 和演示环境。当然这个计划会按实际进度有出入,但大致框架不要偏。
另外,在演示之前一定要留出时间做一次完整预演。把项目从零启动跑一遍,测试数据准备充分,页面切换的每个按钮都点一遍。我遇到过太多次演示环节翻车的情况——要么数据库没启动、要么演示账号密码忘了、要么图片加载不出来。提前演练一遍,这些问题都是可以提前杜绝的。如果你在这个项目的实现过程中遇到具体的技术卡点,欢迎在评论区把报错信息发出来,我看到后会整理成问答形式更新在后续的文章里。