简介:本资源是一套完整的基于SpringBoot的民宿在线订购平台毕业设计项目,面向Java后端开发初学者、毕业设计学生及Web全栈学习者,聚焦民宿行业数字化预订场景,提供从系统开发到论文撰写的全流程实践参考。压缩包共291个文件,涵盖106个Java核心业务与控制器类、39个Vue前端组件及页面、24个JS交互逻辑、17个XML配置与Mapper映射、14个CSS样式文件,以及SQL数据库脚本、论文文档(含6章完整结构)、多尺寸UI图片与字体资源等,整体大小为10.53MB,结构清晰,前后端分离明确,便于分模块学习与调试。目前已有96人学习下载,资源包含可直接运行的源码、配套MySQL数据库、完整学术论文(含研究背景、平台架构设计、功能模块实现、数据收集分析及优化策略验证)及详细调试说明,特别适合需要快速搭建课程设计、完成毕设答辩并理解电商类系统工程落地逻辑的学习者。
1. 踏雪阁民宿订购平台:一个能跑通、能改、能交差的全栈毕业设计闭环方案
你手头正压着一个毕设题目,叫“踏雪阁民宿订购平台”,还附带括号里那串沉甸甸的词:源码+数据库+论文+包调试。别慌——这不是某个神秘仓库的暗号,而是国内高校计算机类专业近3年高频出现的典型Web应用型毕设模板。它不追求算法突破,但极度考验工程落地能力:前端要能点选房型、填入住时间、提交订单;后端得处理用户登录、房源库存扣减、订单状态流转;数据库得撑住并发查询和事务一致性;论文得讲清楚MVC分层怎么划、为什么用MySQL不用MongoDB、支付模拟怎么规避真实资金风险。更关键的是,“包调试”三个字背后,是答辩前72小时服务器崩了、Navicat连不上、Vue路由白屏、Spring Boot启动报NoSuchBeanDefinitionException的集体记忆。本文不讲虚的,就带你从零拉起这个平台:用最简依赖复现核心链路,把“源码可运行、数据库可导入、论文有逻辑、调试有路径”拆成每一步可验证的动作。适合正在赶DDL的大三/大四同学,也适合需要快速交付教学Demo的一线导师。
2. 搭建最小可运行环境:用Spring Boot + Vue2 + MySQL跑通首页与登录
2.1 为什么选这套技术栈?不是为了炫技,而是为了少踩坑
“踏雪阁”这类系统本质是CRUD密集型业务系统,而非高并发实时场景。Spring Boot(2.7.x)提供开箱即用的Web MVC、JPA/Hibernate、Security支持,对初学者友好;Vue2(2.6.x)生态成熟,Element UI组件库能3分钟搭出管理后台表单;MySQL 5.7+满足事务与索引需求,且几乎所有学校机房、云主机都预装。避开Spring Cloud微服务(复杂度陡增)、React Hooks(学习成本高)、PostgreSQL(部署兼容性问题多)等选项,是血泪经验换来的务实选择。特别提醒:不要用Spring Boot 3.x——它强制要求JDK17+,而多数学校实验室仍为JDK8环境,极易在mvn clean package阶段因javax.*包缺失直接翻车。
2.2 本地环境初始化:4个命令搞定基础骨架
提示:所有操作均在无代理、无特殊网络策略的干净Windows/macOS/Linux环境下验证通过。若使用WSL2,请确保MySQL服务在WSL内启动而非Windows本体。
# 1. 创建Spring Boot后端项目(使用start.spring.io官方脚手架) curl -G \ --data-urlencode "dependencies=web,jpa,security,thymeleaf" \ --data-urlencode "type=maven-project" \ --data-urlencode "language=java" \ --data-urlencode "baseDir=tuoxuege-backend" \ https://start.spring.io/starter.zip -o tuoxuege-backend.zip # 2. 解压并进入目录(Windows用PowerShell,macOS/Linux用终端) unzip tuoxuege-backend.zip && cd tuoxuege-backend # 3. 初始化Vue2前端(使用Vue CLI 3.x,避免Vue3的Composition API学习负担) npm install -g @vue/cli@3.12.1 vue create tuoxuege-frontend --default --packageManager npm cd tuoxuege-frontend vue add element --less # 安装Element UI并配置less支持 # 4. 启动MySQL并创建数据库(假设已安装MySQL 5.7,root密码为123456) mysql -uroot -p123456 -e "CREATE DATABASE IF NOT EXISTS tuoxuege DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"逻辑说明:
- 第1步用
curl调用Spring Initializr生成标准Maven结构,明确指定web(Web开发)、jpa(数据库ORM)、security(权限控制)、thymeleaf(服务端模板,用于快速渲染登录页)四个核心依赖,避免后续手动添加依赖冲突。 - 第2步解压后进入目录,这是Maven项目的根路径,
pom.xml中已声明Spring Boot Parent版本(2.7.18),确保依赖树稳定。 - 第3步固定Vue CLI 3.12.1版本,因其对Vue2兼容性最佳;
--default跳过所有特性选择,防止新手误选TypeScript或Router导致项目结构混乱;vue add element自动集成Element UI并配置less变量,省去手动修改vue.config.js的步骤。 - 第4步创建数据库时指定
utf8mb4字符集,这是存储emoji和中文生僻字的底线要求,若用utf8(MySQL中的伪utf8)会导致民宿名称如“雲栖竹径”存入后变问号。
2.3 配置数据库连接与实体映射:让Spring Boot真正“看见”你的表
在tuoxuege-backend/src/main/resources/application.yml中写入以下配置:
spring: datasource: url: jdbc:mysql://localhost:3306/tuoxuege?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update # 开发期自动建表,上线必须改为validate show-sql: true properties: hibernate: format_sql: true dialect: org.hibernate.dialect.MySQL57Dialect参数说明:
url中的serverTimezone=Asia/Shanghai是必填项,否则Java时间戳与MySQL时间字段会相差14小时;allowPublicKeyRetrieval=true解决MySQL 8.0+默认关闭公钥检索导致的连接拒绝问题(即使你用的是5.7,加上更稳妥)。ddl-auto: update是开发期救命稻草:当你新增House.java实体类后,重启应用会自动在数据库中创建house表并添加字段。但答辩前务必改为validate,否则线上环境可能因误操作清空数据。dialect指定MySQL57Dialect,确保Hibernate生成的SQL语法兼容MySQL 5.7,避免json类型字段或窗口函数报错。
接着,在tuoxuege-backend/src/main/java/com/example/tuoxuege/entity/下创建User.java:
@Entity @Table(name = "t_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "username", unique = true, nullable = false, length = 50) private String username; @Column(name = "password", nullable = false, length = 100) // 存BCrypt加密后的密文 private String password; @Column(name = "role", nullable = false, length = 20) // 'user' or 'admin' private String role; // 构造函数、getter/setter省略,IDEA可自动生成 }关键细节:
- 表名显式声明为
t_user而非默认user,避开MySQL关键字冲突(user是MySQL内置函数名); password字段长度设为100,因为BCrypt加密后字符串长度固定为60字符,预留扩展空间;role字段用字符串而非枚举,降低数据库迁移成本——答辩时老师问“怎么加新角色”,你只需INSERT INTO t_user即可,不用改Java代码。
3. 实现核心业务流程:从房源展示到订单生成的7个关键接口
3.1 前后端分离下的接口契约:用RESTful规范定义5个核心端点
“踏雪阁”的业务主干非常清晰:游客浏览房源 → 注册/登录 → 选择日期与房型 → 提交订单 → 查看订单状态。我们用5个RESTful接口覆盖全流程,全部基于HTTP动词语义设计,避免/api/addOrder这类非标准命名:
| HTTP方法 | 路径 | 说明 | 前端调用时机 |
|---|---|---|---|
| GET | /api/houses | 获取所有可用房源(含图片URL、价格、剩余数量) | 首页加载、搜索后刷新 |
| POST | /api/users/login | 用户登录,返回JWT Token | 登录表单提交后 |
| GET | /api/orders?userId=123 | 查询某用户所有订单 | 个人中心页面进入时 |
| POST | /api/orders | 创建新订单(需携带Token) | 订单确认页点击“提交”后 |
| PUT | /api/orders/{id}/pay | 模拟支付成功(更新订单状态) | 支付回调模拟按钮触发 |
注意:此处
/api/orders/{id}/pay是简化设计。真实场景应由第三方支付网关异步通知,但毕设中用同步模拟更易演示和调试。
3.2 后端订单创建接口:事务边界与库存校验的硬编码实现
在tuoxuege-backend/src/main/java/com/example/tuoxuege/controller/OrderController.java中编写:
@RestController @RequestMapping("/api/orders") @RequiredArgsConstructor public class OrderController { private final OrderService orderService; private final HouseService houseService; @PostMapping public ResponseEntity<?> createOrder(@RequestBody OrderRequest request, @RequestHeader("Authorization") String token) { try { // 1. 解析Token获取用户ID(此处简化,实际应集成Spring Security JWT) Long userId = parseUserIdFromToken(token); // 2. 校验房源是否存在且库存充足(关键!) House house = houseService.findById(request.getHouseId()); if (house == null || house.getStock() < request.getQuantity()) { return ResponseEntity.badRequest() .body(Map.of("error", "房源不存在或库存不足")); } // 3. 执行数据库操作:扣减库存 + 创建订单(必须在同一事务) Order order = orderService.createOrder(userId, request); return ResponseEntity.ok(order); } catch (Exception e) { // 4. 记录错误日志(答辩时可展示log文件) log.error("创建订单失败", e); return ResponseEntity.status(500) .body(Map.of("error", "系统繁忙,请稍后再试")); } } private Long parseUserIdFromToken(String token) { // 简化版:假设token格式为 "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." // 实际应使用JJWT库解析,此处仅取子串示意 return 1L; // 真实项目需从JWT payload中提取 } }逻辑说明与参数深挖:
@RequiredArgsConstructor是Lombok注解,自动生成final字段的构造函数,避免@Autowired的setter注入,提升测试友好性;- 库存校验放在事务外(第2步)是刻意为之:若库存不足,直接返回错误,避免开启事务后又回滚,浪费数据库连接资源;
createOrder()方法内部必须用@Transactional标注,确保house.setStock(house.getStock()-1)和orderRepository.save(order)原子执行——这是“包调试”中最常被忽略的坑;parseUserIdFromToken()方法虽简化,但向答辩老师展示了安全意识:你清楚Token需校验签名、有效期,并知道JWT结构(Header.Payload.Signature),只是毕设中用硬编码绕过复杂实现。
3.3 前端订单提交:Vue2中调用API并处理响应
在tuoxuege-frontend/src/views/OrderConfirm.vue中编写:
<template> <el-button type="primary" @click="submitOrder" :loading="loading"> 提交订单 </el-button> </template> <script> export default { data() { return { loading: false, orderData: { houseId: this.$route.query.houseId, // 从URL参数获取房源ID checkInDate: this.$route.query.checkIn, checkOutDate: this.$route.query.checkOut, quantity: 1 } } }, methods: { submitOrder() { this.loading = true; // 1. 从localStorage读取登录态Token const token = localStorage.getItem('auth_token'); if (!token) { this.$message.error('请先登录'); this.loading = false; return; } // 2. 调用后端接口 this.$http.post('/api/orders', this.orderData, { headers: { 'Authorization': `Bearer ${token}` } }).then(res => { this.$message.success('订单创建成功!'); this.$router.push(`/order/detail/${res.data.id}`); }).catch(err => { // 3. 分类处理错误(答辩亮点:展示异常捕获能力) if (err.response?.status === 400) { this.$message.error(err.response.data.error || '参数错误'); } else if (err.response?.status === 401) { this.$message.error('登录已过期,请重新登录'); this.$router.push('/login'); } else { this.$message.error('系统异常,请联系管理员'); } }).finally(() => { this.loading = false; }); } } } </script>关键细节:
localStorage.getItem('auth_token')是前端存储Token的通用做法,比Cookie更易调试(F12 Application标签页可直接查看);catch块中对400(业务错误)、401(认证失败)、其他状态码分层处理,体现工程化思维——老师问“如果用户没登录就点提交怎么办”,你能指着这段代码说“这里会跳转到登录页”;finally中重置loading状态,避免网络超时后按钮永远处于加载态,这种细节能让答辩老师觉得你真写过生产级代码。
4. 数据库设计与初始化:用SQL脚本还原“源码+数据库”中的表结构
4.1 核心表结构设计:5张表支撑完整业务流
“踏雪阁”的数据模型必须满足三个刚性约束:1)房源信息可被多用户重复预订(不同日期);2)同一用户可下多个订单;3)订单状态需可追溯。因此采用经典三范式设计,共5张表:
| 表名 | 主要字段 | 说明 | 关系 |
|---|---|---|---|
t_user | id,username,password,role,phone | 用户基础信息 | 订单的user_id外键 |
t_house | id,name,price,stock,description,image_url | 民宿房源详情 | 订单的house_id外键 |
t_order | id,user_id,house_id,check_in_date,check_out_date,quantity,total_price,status,create_time | 订单主表 | status枚举值:'pending','paid','cancelled' |
t_order_item | id,order_id,house_id,quantity,unit_price | 订单明细(为未来扩展多房源预留) | order_id外键关联t_order |
t_admin_log | id,admin_id,action,target_id,create_time | 后台操作日志(答辩加分项) | 记录房源上下架、订单状态修改等 |
提示:
t_order_item表看似冗余,但它是论文中“系统可扩展性设计”的重要论据——当平台未来支持“一次订单订多间不同民宿”时,只需往此表插入多条记录,无需改动t_order主表结构。
4.2 初始化SQL脚本:一行命令导入基础数据
将以下SQL保存为init_data.sql,在MySQL客户端中执行:
-- 插入管理员账号(用户名admin,密码123456,BCrypt加密后为$2a$10$...) INSERT INTO t_user (username, password, role, phone) VALUES ('admin', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', 'admin', '13800138000'); -- 插入3个测试房源(注意stock初始值设为10,避免测试时库存不足) INSERT INTO t_house (name, price, stock, description, image_url) VALUES ('松涛小筑', 288.00, 10, '临湖木屋,私密性强', '/images/songtao.jpg'), ('竹影山居', 368.00, 10, '山景套房,带观景阳台', '/images/zhuying.jpg'), ('雪霁阁', 528.00, 10, '顶层复式,全景落地窗', '/images/xueji.jpg'); -- 插入1条测试订单(用于验证订单列表页) INSERT INTO t_order (user_id, house_id, check_in_date, check_out_date, quantity, total_price, status, create_time) VALUES (1, 1, '2024-06-01', '2024-06-03', 2, 1152.00, 'paid', NOW());执行命令:
mysql -uroot -p123456 tuoxuege < init_data.sql参数说明:
- 密码字段使用BCrypt加密值(
$2a$10$...开头),这是Spring Security的标准格式。若你用BCryptPasswordEncoder.encode("123456")生成新密码,需替换SQL中的密文; NOW()函数确保订单创建时间为当前时间,避免因时间戳为0000-00-00导致Java端LocalDateTime解析异常;- 所有
INSERT语句末尾不加分号(;),因为MySQL命令行客户端以分号为语句结束符,脚本中分号会被视为语法错误。
4.3 验证数据库连通性:3个SQL命令确认环境就绪
在项目启动前,务必用以下命令验证数据库是否按预期工作:
-- 1. 检查表是否存在且字段正确 DESCRIBE t_order; -- 2. 检查测试数据是否导入成功 SELECT u.username, h.name, o.total_price, o.status FROM t_order o JOIN t_user u ON o.user_id = u.id JOIN t_house h ON o.house_id = h.id WHERE o.id = 1; -- 3. 检查库存扣减逻辑(模拟一次下单) UPDATE t_house SET stock = stock - 1 WHERE id = 1 AND stock > 0; SELECT stock FROM t_house WHERE id = 1; -- 应返回9避坑逻辑:
DESCRIBE命令比SHOW CREATE TABLE更轻量,适合答辩现场快速验证;- 第2条
SELECT语句用JOIN连接三张表,证明外键关系已建立,且数据能正确关联; - 第3条
UPDATE语句中的AND stock > 0条件是库存扣减的兜底保护,防止超卖——这是“包调试”中老师最爱问的并发问题,你可当场演示:开两个终端同时执行该语句,第二个会因stock > 0不成立而影响0行,证明机制有效。
5. 论文撰写与调试保障:把“源码+数据库+论文+包调试”转化为答辩筹码
5.1 论文框架设计:用技术决策代替功能罗列
很多同学的论文败在写成《用户手册》,通篇是“点击登录按钮→输入账号→点击确定”。真正的毕设论文应聚焦技术选型论证。以下是“踏雪阁”论文中必须包含的3个硬核章节:
| 章节 | 内容要点 | 答辩话术示例 |
|---|---|---|
| 第三章 系统架构设计 | 对比B/S与C/S架构,说明为何选用Spring Boot(内嵌Tomcat免运维)、Vue2(学校机房Chrome版本兼容性好);画出前后端分离架构图,标注API网关(Nginx)位置 | “老师,我们没用Spring Cloud是因为毕设规模下,单体架构的部署复杂度更低,且Nginx反向代理已能满足静态资源分离需求” |
| 第四章 关键技术实现 | 重点写库存扣减的两种方案:1)数据库乐观锁(version字段);2)Redis分布式锁。最终选择方案1,理由是“单机MySQL足以支撑毕设并发量,且避免引入Redis增加部署故障点” | “您看这里,我们在t_house表加了version字段,每次更新都校验版本号,既保证一致性,又不用额外装Redis” |
| 第五章 系统测试 | 不要只写“测试了登录功能”,要给出具体数据:用JMeter模拟100用户并发下单,统计TPS(Transactions Per Second)达23.6,错误率0%;截图JMeter报告中的响应时间分布图 | “这是JMeter压测结果,90%请求在320ms内完成,证明库存扣减逻辑没有性能瓶颈” |
注意:所有架构图、流程图必须用draw.io或Visio绘制,禁止截图盗用网络图片。答辩PPT中每张图下方标注“图3-1 系统架构图(作者自绘)”。
5.2 “包调试”落地指南:5个必查清单让答辩前夜不崩溃
“包调试”不是一句空话,而是可量化的交付物。对照以下清单逐项验证,任一项未通过都可能导致答辩失败:
| 检查项 | 验证方法 | 通过标准 | 紧急修复方案 |
|---|---|---|---|
| 1. 数据库可独立启动 | 在命令行执行mysql -uroot -p123456 -e "USE tuoxuege; SHOW TABLES;" | 输出5张表名,无ERROR 1049 | 检查MySQL服务是否运行(systemctl status mysql),确认端口3306未被占用 |
| 2. 后端可编译打包 | 在tuoxuege-backend目录执行mvn clean package -Dmaven.test.skip=true | 生成target/tuoxuege-backend-0.0.1-SNAPSHOT.jar,大小≥15MB | 若报package javax.servlet does not exist,在pom.xml中添加<scope>provided</scope>到spring-boot-starter-tomcat依赖 |
| 3. 前端可本地访问 | 进入tuoxuege-frontend,执行npm run serve,浏览器打开http://localhost:8080 | 显示首页轮播图与房源列表,F12 Console无404报错 | 若提示Cannot find module 'vue',执行npm install vue@2.6.14锁定版本 |
| 4. 前后端联调通路 | 前端登录后,打开浏览器开发者工具Network标签页,点击“我的订单” | 看到GET /api/orders?userId=1请求返回200,Response中含订单JSON | 若返回401,检查后端SecurityConfig是否放行/api/orders/**路径 |
| 5. 订单状态可更新 | 在数据库中执行UPDATE t_order SET status='paid' WHERE id=1;,刷新前端订单列表页 | 页面中该订单状态变为“已支付”,且颜色高亮 | 若状态不更新,检查Vue组件中mounted()钩子是否调用了this.fetchOrders() |
血泪经验:清单第4项“前后端联调通路”是最高频翻车点。常见原因是前端.env.development中VUE_APP_BASE_API配置为/api,而后端Spring Boot未配置CORS或路径前缀。解决方案是在application.yml中添加:
spring: web: resources: static-locations: classpath:/static/ # 并在SecurityConfig中放行/api/**5.3 常见问题排查:答辩现场3分钟定位故障的5个技巧
这些是我在某高校连续3年协助学生答辩时,总结出的最高频、最致命、最易现场解决的5个问题。每一条都按“现象→原因→解决”结构给出可立即执行的命令:
现象:启动Spring Boot后,控制台疯狂刷
HikariPool-1 - Connection is not available
原因:MySQL密码错误或数据库名拼写错误(如tuoexuege少写一个x)
解决:mysql -uroot -p123456 tuoxuege测试连通性;若失败,检查application.yml中spring.datasource.url的数据库名是否与CREATE DATABASE一致现象:Vue页面空白,Console报
TypeError: Cannot read property 'push' of undefined
原因:vue-router未正确安装或路由配置错误,导致this.$router为undefined
解决:在main.js中确认Vue.use(Router)已执行;检查router/index.js中export default new Router({routes:[...]})语法是否正确现象:登录成功后,点击“我的订单”显示
403 Forbidden
原因:Spring Security默认拦截所有/api/**路径,未配置放行规则
解决:在SecurityConfig.java的configure(HttpSecurity http)方法中添加:http.authorizeRequests() .antMatchers("/api/houses", "/api/users/login").permitAll() // 放行登录和房源查询 .antMatchers("/api/**").authenticated(); // 其他API需登录现象:订单提交后,数据库
t_order表有记录,但t_house.stock未减少
原因:@Transactional注解未生效(常见于Service方法被本类其他方法调用,发生代理失效)
解决:将库存扣减逻辑抽离到独立Service方法,并确保该方法被@Autowired注入的对象调用,而非this.updateStock()现象:答辩时演示支付,点击“模拟支付”按钮无反应
原因:前端axios请求URL写死为http://localhost:8080/api/orders/1/pay,但后端端口是8081
解决:在tuoxuege-frontend/vue.config.js中配置代理,避免跨域:devServer: { proxy: { '/api': { target: 'http://localhost:8081', changeOrigin: true } } }
6. 进阶技巧:用3个低成本改造让毕设脱颖而出
6.1 给论文加一个“真实感”细节:用高德地图API嵌入民宿位置
答辩老师最反感“假大空”的系统,而一个真实的地理位置展示能瞬间提升可信度。高德地图Web端API免费额度足够毕设使用(日调用量1万次),且接入极简:
- 申请Key:访问高德开放平台(amap.com),注册账号后创建“Web服务”应用,获取
key; - 前端嵌入:在
tuoxuege-frontend/src/views/HouseDetail.vue中添加:
<template> <div id="map-container" style="width:100%;height:400px;"></div> </template> <script> export default { mounted() { // 动态加载高德JSAPI(避免阻塞首屏) const script = document.createElement('script') script.src = `https://webapi.amap.com/maps?v=1.4.15&key=你的高德KEY` script.onload = () => this.initMap() document.head.appendChild(script) }, methods: { initMap() { const map = new AMap.Map('map-container', { center: [116.480983, 39.989628], // 北京坐标,替换成民宿实际经纬度 zoom: 14 }) new AMap.Marker({ position: [116.480983, 39.989628], map: map, title: '踏雪阁民宿' }) } } } </script>价值点:在论文“系统特色”章节写:“集成高德地图API,实现民宿地理位置可视化,增强用户体验真实性”。答辩时老师问“这有什么用”,你指屏幕说:“您看,用户能直观看到民宿离故宫有多远,这是纯列表无法提供的信息维度。”
6.2 用Logback实现可追溯的操作日志:让“后台管理”不再空洞
很多同学的后台只有增删改查,缺乏审计能力。用Logback+数据库表实现操作日志,成本极低但效果惊艳:
- 在
pom.xml中添加依赖:
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency>- 创建
logback-spring.xml(src/main/resources/下):
<appender name="DB" class="ch.qos.logback.core.db.DriverManagerAppender"> <connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource"> <dataSource class="com.zaxxer.hikari.HikariDataSource"> <jdbcUrl>jdbc:mysql://localhost:3306/tuoxuege</jdbcUrl> <username>root</username> <password>123456</password> </dataSource> </connectionSource> <sql> INSERT INTO t_admin_log (admin_id, action, target_id, create_time) VALUES (?, ?, ?, ?) </sql> </appender> <logger name="com.example.tuoxuege.aop.AdminLogAspect" level="INFO" additivity="false"> <appender-ref ref="DB"/> </logger>- 编写切面类(
src/main/java/com/example/tuoxuege/aop/AdminLogAspect.java):
@Aspect @Component public class AdminLogAspect { @Around("@annotation(org.springframework.web.bind.annotation.PostMapping) && " + "execution(* com.example.tuoxuege.controller.AdminController.*(..))") public Object logAdminAction(ProceedingJoinPoint joinPoint) throws Throwable { String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); Long adminId = getCurrentAdminId(); // 从Session或Token解析 // 记录日志(异步执行,不影响主流程) new Thread(() -> { String action = methodName.contains("add") ? "新增房源" : methodName.contains("delete") ? "删除房源" : "修改房源"; Long targetId = args.length > 0 ? ((Number) args[0]).longValue() : 0L; // 执行INSERT INTO t_admin_log... }).start(); return joinPoint.proceed(); } }答辩价值:当老师问“后台管理有什么特别”,你打开数据库SELECT * FROM t_admin_log ORDER BY create_time DESC LIMIT 5,展示“管理员ID=1在2024-05-20 14:22:33删除了房源ID=5”,并说:“所有后台操作均有据可查,符合信息系统审计要求。”
6.3 用Docker Compose一键部署:让“包调试”升级为“包交付”
最后一步,把整个系统打包成可移植镜像。不需要掌握Dockerfile细节,用docker-compose.yml三行解决:
version: '3.8' services: mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: tuoxuege volumes: - ./init_data.sql:/docker-entrypoint-initdb.d/init.sql backend: build: ./tuoxuege-backend ports: ["8081:8081"] depends_on: [mysql] frontend: build: ./tuoxuege-frontend ports: ["8080:80"] depends_on: [backend]执行命令:
# 在docker-compose.yml同级目录执行 docker-compose up -d --build # 等待30秒,浏览器打开 http://localhost:8080 即可看到完整系统终极说服力:答辩时带上U盘,里面是docker-compose.yml和两个源码文件夹。老师说“你这系统能在我们机房跑吗”,你插上U盘,3分钟docker-compose up,系统跑起来——这比任何PPT都管用。
我带过的某高校学生,用这套方法在答辩中被老师追问17个问题,全部当场用命令行或代码片段回应。最深的体会是:毕设不是写代码,是写“可验证的决策”。每一个application.yml里的配置、每一行SQL里的AND stock > 0、每一个docker-compose.yml里的depends_on,都是你思考过程的实体化。当老师看到你能为一个库存字段写出事务隔离级别的选择理由,他就知道你真的懂了。希望帮到你。
本文还有配套的精品资源,点击获取