简介:这是一套面向计算机相关专业学生与初学者的软件工程课程设计实战资源,完整实现基于Spring Boot后端、Vue.js后台管理系统与微信小程序前端的餐馆自助点餐系统,覆盖服务端开发、前后端分离架构及小程序落地全流程,适用于课程设计、毕业设计、项目实训与技术进阶学习。资源包共976个文件,含256个Java源码(含Controller、Service、Mapper等分层结构)、47个Vue组件、102个JS脚本、80个SVG图标及配套配置文件(properties、yml、sql等),整体压缩包仅5.17MB,轻量易部署。已有187人下载学习,代码经实际运行验证,答辩平均分达96分,附带详细注释、README说明文档及模块化目录结构(含api接口层、菜单权限管理、代码生成器Generator、消息服务MessageService等核心类),便于理解业务逻辑与二次开发。
1. 为什么一个餐馆点餐系统要同时用 Spring Boot、Vue 和微信小程序?
这不是堆技术的炫技项目,而是真实餐饮场景下对「多端协同」的刚性需求:堂食顾客扫桌码打开微信小程序快速点单,后厨人员在内网浏览器里用 Vue 管理订单状态,老板手机 App(或 PC 端)通过 Spring Boot 提供的 REST API 查看实时营收报表。三端数据同源、状态同步、权限隔离——这正是该课程设计的核心价值。它跳出了单页面应用或纯小程序的局限,直面企业级系统中「前端多形态 + 后端强管控」的典型矛盾。Spring Boot 负责统一身份认证、订单事务管理、数据库连接池与接口幂等性;Vue 构建响应式后台管理界面,支持动态菜单、权限路由和表格导出;微信小程序则利用原生组件(如wx.chooseAddress、wx.requestPayment)完成扫码下单、地址选择与支付闭环。整套代码不是 Demo 级玩具,而是按软件工程规范组织的可维护系统:包结构遵循 Spring Boot 四层架构(controller → service → mapper → entity),Vue 工程采用模块化路由+Pinia 状态管理,小程序目录严格区分pages/、components/与utils/。文档说明覆盖环境准备、数据库初始化脚本、前后端联调要点及关键注释解读——所有内容都指向一个目标:让本科生能真正跑通、理解、修改并扩展它。
2. 搭建 Spring Boot 后端服务:从数据库建模到 REST 接口交付
2.1 数据库设计与 MyBatis-Plus 集成策略
餐馆点餐系统核心实体包括user(顾客/管理员)、restaurant(门店)、menu_item(菜品)、order_master(主订单)、order_detail(订单明细)和dish_category(菜品分类)。采用 MySQL 8.0,字符集设为utf8mb4,避免微信昵称中的 emoji 存储异常。建表时特别注意字段约束:order_master.status使用 tinyint(1) 表示「待接单(0)、已接单(1)、制作中(2)、已完成(3)、已取消(4)」,而非字符串枚举,降低传输体积与校验开销;menu_item.price定义为 decimal(10,2),杜绝浮点数精度问题。
提示:
application.yml中必须配置mybatis-plus.configuration.map-underscore-to-camel-case: true,否则order_detail表字段dish_name无法自动映射到 Java 实体类的dishName属性。
使用 MyBatis-Plus 的@TableName和@TableId(type = IdType.ASSIGN_ID)注解简化 CRUD,避免手写 XML 映射文件。例如OrderMasterMapper继承BaseMapper<OrderMaster>后,仅需一行代码即可查询今日全部未完成订单:
// 查询今日未完成订单(含关联用户信息) List<OrderMaster> todayOrders = orderMasterMapper.selectList( new QueryWrapper<OrderMaster>() .eq("status", 0) .ge("create_time", LocalDate.now().atStartOfDay()) );该语句生成的 SQL 自动包含 LEFT JOIN 关联user表,前提是OrderMaster实体中定义了@TableField(exist = false)的User user字段,并在OrderMasterMapper.xml中补充<resultMap>映射逻辑——这是课程设计中常被忽略但实际必需的细节。
2.2 Spring Security 权限控制与微信登录集成
系统需区分三类角色:ROLE_CUSTOMER(小程序端用户)、ROLE_STAFF(后厨/服务员)、ROLE_ADMIN(系统管理员)。Spring Security 配置不采用硬编码角色判断,而是基于@PreAuthorize("hasRole('STAFF')")注解实现方法级鉴权。关键在于微信登录凭证校验流程:
- 小程序调用
wx.login()获取临时 code; - 前端将 code 发送至
/api/wx/login接口; - Spring Boot 后端用该 code 向微信服务器请求
openid和session_key; - 校验成功后生成 JWT Token 并返回,Token payload 中嵌入
openid和role字段。
JWT 签名密钥必须从application.yml外部注入,禁止硬编码:
jwt: secret: ${JWT_SECRET:default_secret_key_for_dev} expiration: 86400验证 Token 时,拦截器需提取Authorization: Bearer <token>头,解析后调用userDetailsService.loadUserByUsername(openid)加载用户详情。若用户首次登录,需自动创建User记录并分配默认角色ROLE_CUSTOMER——这部分逻辑封装在WxLoginService中,避免 Controller 层臃肿。
2.3 REST 接口设计与参数校验实践
所有接口遵循 RESTful 规范,路径层级清晰:POST /api/orders创建订单,GET /api/orders/{id}查询单个订单,PUT /api/orders/{id}/status修改订单状态。关键参数必须启用 JSR-303 校验:
@PostMapping("/orders") public Result<OrderMaster> createOrder(@Valid @RequestBody OrderDTO orderDTO) { // ... }其中OrderDTO包含嵌套校验:
public class OrderDTO { @NotEmpty(message = "收货地址不能为空") private String address; @NotNull(message = "订单明细不能为空") @Size(min = 1, message = "至少选择一道菜") private List<OrderDetailDTO> details; @Min(value = 1, message = "份数不能小于1") private Integer quantity; }校验失败时,全局异常处理器GlobalExceptionHandler捕获MethodArgumentNotValidException,统一返回{"code": 400, "message": "收货地址不能为空"}格式错误信息,前端可直接绑定到表单控件。
| 接口路径 | HTTP 方法 | 用途 | 关键参数示例 |
|---|---|---|---|
/api/menus?category=热销 | GET | 分页获取菜品列表 | page=1,size=10,category=热销 |
/api/orders/{id}/pay | POST | 发起微信支付 | payAmount=28.50,notifyUrl=/api/wx/pay/callback |
/api/statistics/daily | GET | 查询日营业统计 | date=2024-06-15 |
3. Vue 后台管理系统:从路由权限到订单状态可视化
3.1 基于 Pinia 的订单状态状态机管理
Vue 3 项目使用 Pinia 替代 Vuex,核心状态orderStore定义如下:
// stores/order.js export const useOrderStore = defineStore('order', () => { const orders = ref([]) const loading = ref(false) const statusMap = { 0: { text: '待接单', color: '#ff9c00' }, 1: { text: '已接单', color: '#1890ff' }, 2: { text: '制作中', color: '#52c418' }, 3: { text: '已完成', color: '#722ed1' }, 4: { text: '已取消', color: '#f5222d' } } const fetchOrders = async (status = null) => { loading.value = true try { const res = await api.get('/api/orders', { params: { status } }) orders.value = res.data } finally { loading.value = false } } return { orders, loading, statusMap, fetchOrders } })组件中通过const orderStore = useOrderStore()调用fetchOrders(0)即可加载待处理订单。statusMap不仅用于渲染标签颜色,还驱动按钮显隐逻辑:当status === 0时显示「接单」按钮,status === 1时显示「开始制作」按钮——避免前端硬编码状态流转规则,降低维护成本。
3.2 动态路由与菜单权限控制
菜单栏数据来自后端接口/api/menu,返回 JSON 结构:
[ { "path": "/dashboard", "name": "Dashboard", "title": "仪表盘", "icon": "HomeOutlined" }, { "path": "/orders", "name": "Orders", "title": "订单管理", "icon": "ShoppingCartOutlined", "roles": ["STAFF", "ADMIN"] } ]路由守卫router.beforeEach中,根据用户角色过滤菜单项,并动态添加路由:
router.addRoute({ path: item.path, name: item.name, component: () => import(`@/views/${item.component}.vue`), meta: { title: item.title, icon: item.icon } })若用户无STAFF角色,访问/orders时触发next({ path: '/403' }),跳转至无权限页面。这种「后端返回菜单 + 前端动态注册」模式,比静态路由配置更适应角色频繁变更的业务场景。
3.3 ECharts 订单趋势图与分页表格优化
订单统计页集成 ECharts 5.x,绘制近 7 日订单量折线图。关键配置项:
option = { tooltip: { trigger: 'axis' }, xAxis: { type: 'category', data: dateList }, // ['6/9', '6/10', ...] yAxis: { type: 'value' }, series: [{ name: '订单数量', type: 'line', data: countList, // [12, 15, 8, ...] smooth: true, areaStyle: { opacity: 0.1 } }] }表格组件使用el-table,开启v-loading="loading"和@sort-change排序事件。为提升大数据量渲染性能,启用虚拟滚动(virtual-scroll),并在el-table-column中设置min-width="120"避免列宽自适应导致布局抖动。分页参数currentPage和pageSize与fetchOrders方法联动,确保翻页时重新请求对应页数据。
4. 微信小程序端:从扫码点餐到支付闭环实现
4.1 扫码点餐流程与页面栈管理
小程序首页index.wxml放置wx.scanCode按钮,点击后调用:
wx.scanCode({ success: (res) => { const tableId = res.result.split('_')[1] // 解析 "table_001" 获取桌号 wx.navigateTo({ url: `/pages/order/order?tableId=${tableId}` }) } })order页面通过onLoad获取tableId,并立即请求/api/menus?tableId=001获取该桌专属菜单(含桌号绑定的优惠活动)。关键点在于页面栈管理:用户选菜后进入confirm页面确认订单,此时若点击「返回」应跳转回order而非index,因此wx.navigateTo必须使用相对路径:
wx.navigateTo({ url: '../confirm/confirm' }) // 而非 '/pages/confirm/confirm'避免因页面栈混乱导致onShow生命周期失效。
4.2 微信支付接口调用与回调处理
支付流程严格遵循微信官方文档:
- 小程序端调用
wx.requestPayment前,先向后端请求统一下单接口/api/wx/unifiedorder; - 后端生成
prepay_id并签名,返回timeStamp、nonceStr、package、signType、paySign五要素; - 小程序传入五要素调用
wx.requestPayment; - 支付成功后,微信服务器异步通知后端
/api/wx/pay/callback地址。
小程序端代码需捕获支付结果:
wx.requestPayment({ timeStamp: res.timeStamp, nonceStr: res.nonceStr, package: res.package, signType: res.signType, paySign: res.paySign, success: (res) => { wx.showToast({ title: '支付成功', icon: 'success' }) setTimeout(() => wx.switchTab({ url: '/pages/index/index' }), 1500) }, fail: (err) => { if (err.errMsg.includes('requestPayment:fail cancel')) { wx.showToast({ title: '用户取消支付', icon: 'none' }) } else { wx.showToast({ title: '支付失败', icon: 'error' }) } } })注意:
wx.requestPayment的fail回调中,errMsg为'requestPayment:fail cancel'表示用户主动取消,不应记录为支付异常;而'requestPayment:fail network error'才需重试。
4.3 小程序性能优化与加载页定制
首屏白屏时间需控制在 500ms 内。措施包括:
- 使用
wx.setStorageSync缓存菜单数据,onLoad时优先读取缓存,再发起网络请求更新; - 图片资源压缩至 100KB 以内,
<image>组件设置lazy-load属性; app.json中配置"lazyCodeLoading": "requiredComponents",按需加载自定义组件。
修改刚进入的加载页面:在app.js的onLaunch中设置wx.showLoading({ title: '加载中...' }),onShow中隐藏;更精细的控制是在pages/index/index.js的onLoad中:
onLoad() { wx.showNavigationBarLoading() this.fetchData().finally(() => wx.hideNavigationBarLoading()) }同时在app.wxss中覆盖默认 loading 样式:
.loading-text { font-size: 14px; color: #666; }5. 全链路调试与常见问题排查技巧
5.1 Burp Suite 抓取小程序请求的实操要点
小程序运行在微信客户端沙箱中,无法直接使用 Chrome DevTools。正确抓包流程:
- 手机与电脑连同一 WiFi,电脑开启 Burp Suite Proxy 监听
0.0.0.0:8080; - 手机 WiFi 设置代理为电脑 IP + 8080 端口;
- 微信「发现」→「小程序」→ 右上角「…」→「设置」→ 关闭「HTTPS 证书验证」(仅测试环境);
- 在 Burp Suite 中安装 CA 证书(访问
http://burp下载并手动安装); - 启动小程序,Burp 即可捕获
https://your-domain.com/api/orders等请求。
提示:若 Burp 无法捕获,检查微信是否启用了「安全保护」开关(设置 → 通用 → 发现页管理 → 关闭「安全保护」);生产环境严禁关闭此开关,调试完成后务必恢复。
5.2 Spring Boot Actuator 安全加固与健康检查
课程设计默认暴露/actuator/health,但未禁用危险端点如/actuator/env。必须在application.yml中显式配置:
management: endpoints: web: exposure: include: health,info,metrics,prometheus # exclude: env,beans,configprops # 禁用敏感端点 endpoint: health: show-details: when_authorized配合 Spring Security,限制/actuator/**仅允许ROLE_ADMIN访问:
http.authorizeHttpRequests(authz -> authz .requestMatchers("/actuator/**").hasRole("ADMIN") .anyRequest().authenticated() );验证健康状态:curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/actuator/health返回{"status":"UP","components":{"db":{"status":"UP"}}}表示数据库连接正常。
5.3 Vue 打包后布局异常的定位方法
npm run build后部署到 Nginx,若出现按钮错位、字体缩放异常,按以下顺序排查:
- 检查
vue.config.js中publicPath是否为./(相对路径)而非/(绝对路径),避免静态资源 404; - 查看浏览器开发者工具 Network 标签,确认
chunk-vendors.js和app.js加载成功; - 在
main.js开头添加console.log('Vue app mounted'),验证 JS 是否执行; - 检查 CSS 文件是否被 CDN 缓存旧版本,强制刷新(Ctrl+F5)或清除浏览器缓存;
- 若使用
flex布局异常,检查父容器是否遗漏display: flex,或子元素flex: 1未生效——此时在 Chrome 中右键「检查元素」,查看 Computed Styles 面板确认最终样式计算值。
最后,验证微信小程序真机调试:在开发者工具中勾选「真机调试」,手机微信扫码后,控制台会同步输出console.log信息,可实时观察wx.request返回数据结构是否与后端文档一致。若data字段为空,重点检查 Spring Boot 接口是否返回@ResponseBody对象,以及@RestController类是否被 Spring 扫描到(确认@SpringBootApplication所在包路径覆盖 Controller 层)。
本文还有配套的精品资源,点击获取