1. 项目概述与整体设计思路
1.1 核心需求解析
餐厅内部管理系统这个选题,在计算机毕业设计里属于典型的“中规中矩但五脏俱全”的类型。它不像电商系统那样业务链路冗长,也不像纯粹的后台管理系统那样枯燥乏味,恰好卡在一个既能展示技术深度、又不会让开发周期失控的位置上。
标题里提到的Spring Boot是当前Java后端开发的事实标准,毕业生选它作为技术底座,一方面是因为社区资料丰富,遇到问题搜得到答案;另一方面是Spring Boot的自动配置机制能大幅缩减代码量,让项目在有限时间内更快成型。餐厅内部管理系统的核心需求其实很简单:把餐厅日常运营中的人工记录搬到线上,包括菜品信息维护、开台点餐、订单结算、员工排班、进货库存等。做到这些,系统就有了实际的业务价值,而不只是CRUD的堆砌。
很多同学拿到这类题目,第一反应就是“做一个后台管理页面”,然后一味堆功能。我在实际带毕设的过程中见过不少这样的半成品——权限控制形同虚设,业务逻辑之间相互割裂,数据库设计连外键关系都没理清楚。这种项目看起来页面不少,但答辩时老师一追问业务闭环就露馅了。
1.2 技术选型与系统架构
这个项目最适合采用前后端分离或服务端渲染两种方案中的一种。考虑到毕设的验收重点往往在后端逻辑和数据库设计上,我建议用Spring Boot + Thymeleaf(或FreeMarker)的服务端渲染模式,把前端复杂度降到最低,把精力集中在核心业务实现上。
当然,如果你对Vue比较熟,也可以采用前后端分离,前端用Vue 3 + Element Plus,后端用Spring Boot + MyBatis-Plus。两条路都走得通,关键是别中途换方案。
这里给出一个我在实际中验证过的推荐技术栈组合:
| 层次 | 技术选型 | 说明 |
|---|---|---|
| 后端框架 | Spring Boot 2.7.x | 稳定且资料丰富,JDK 8或11均可 |
| ORM框架 | MyBatis-Plus 3.5.x | 内置CRUD方法,减少重复代码 |
| 权限认证 | Sa-Token 或 Spring Security + JWT | 看个人熟悉程度,入门推荐Sa-Token |
| 前端渲染 | Thymeleaf + Bootstrap 5 | 服务端渲染,简单直接 |
| 数据库 | MySQL 8.0 | 主流稳定,安装配置简单 |
| 构建工具 | Maven | 比Gradle更适合新手 |
| 项目打包 | JAR包 + 内置Tomcat | 部署省心,复制即运行 |
系统架构上,整个项目按三个层次组织:Controller层负责接收请求和参数校验,Service层封装核心业务逻辑,Mapper层对接数据库操作。再加上一个common包存放公共类(统一返回结果、异常处理、工具类),一个config包存放配置类。这种分层方式几乎是行业标准,答辩时老师看着也熟悉。
2. 核心功能模块拆解
2.1 菜品管理模块
菜品管理是餐厅系统的地基模块,它要解决的核心问题只有一个:菜单上的菜品增减、价格变动、上下架状态如何高效维护。
这个模块建议包含菜品名称、分类、单价、图片、描述、是否推荐、是否售罄等字段。分类可以用一张独立的菜品分类表来管理,比如凉菜、热菜、汤品、主食、饮品这些类别。分类表和菜品表之间是一对多关系,建表时在菜品表中用一个categoryId字段引用分类表主键即可。
这里有一个很多同学容易忽略的点:菜品状态字段。数据库里务必加一个status字段(0=停售,1=在售),不要让“删除”直接体现在主流程中。道理很简单,餐厅的实际运营场景中,菜品只会下架不会物理删除;如果某天菜品停售,你把它从表里删掉了,历史订单里关联的菜品数据就全乱了。所以,用逻辑删除或状态字段才是符合真实需求的做法。
菜品图片的处理也值得多说一句。不要把图片以base64编码直接存数据库,这种操作会让数据库表体积迅速膨胀,严重拖慢查询效率。正确做法是图片上传后保存到服务器磁盘或对象存储,数据库里只存图片路径。上传接口可以直接用Spring Boot的MultipartFile接收文件,配合一个简单的文件存储工具类就能搞定。
2.2 餐桌与订台管理
餐桌管理模块看起来简单,但它是餐厅业务中非常能体现“内部管理”特点的功能。
数据库里餐桌表的核心字段包括桌号、座位数、餐桌状态(空闲/已预订/就餐中)、所在区域(大厅/包间)。状态流转遵循一条明确的业务线:空闲状态下的餐桌可以被顾客预订或直接开台,预订成功后变成“已预订”,顾客到店入座后转为“就餐中”,结账完成并清台后回到“空闲”。
我开始做这个模块时犯过一个典型的错误:只在餐桌表里维护一个状态字段,所有操作直接改这个字段的值。后来在业务流程中加入订单表、预订表之后才发现,这种设计缺乏状态变更的审计能力——如果某个餐桌被误操作改成“就餐中”,你根本不知道是谁在什么时候改的,也没有办法追溯操作前是什么状态。
更合理的设计是引入一张table_status_log表,记录每一次餐桌状态变更的来源操作(开台、换桌、并桌、清台)、操作人、操作时间和变更前后状态。这张表在答辩时讲出来,是一个不小的加分项,因为它证明你思考过实际运营中“操作留痕”的需求。
2.3 点餐与订单管理
订单模块是整个系统里业务逻辑最密集的地方,也是答辩时老师提问的重灾区。
一张完整的订单要回答“谁点的、点了什么、多少钱、怎么支付的、桌号是多少”这些核心问题。为了实现这套描述,数据库至少需要两张表:order主表和order_item明细表。主表存订单编号、餐桌ID、顾客人数、总金额、订单状态、下单时间、支付方式等字段;明细表存订单关联的菜品ID、菜品名称(快照)、单价(快照)、数量、小计金额。
订单状态建议定义成这样:待支付 → 已支付/制作中 → 已完成 → 已退款。实际业务中还可以继续细分“进行中”和“已完成”,但状态别设计得太碎,否则前端状态映射会让你崩溃。
一个特别容易踩坑的点是菜品价格的快照问题。假设顾客A中午点了一份“宫保鸡丁”,单价是28元;下午餐厅把这道菜价格改成了32元。如果没有价格快照,查询之前的历史订单时就会显示32元,这显然不对。所以在我的设计中,order_item表里的菜品名称和单价必须在下单那一刻从菜品表里复制过来,而不是通过菜品ID实时关联菜品表。这是订单系统设计里很经典的一个原则:明细数据要做快照,不能依赖实时查询。
2.4 会员与员工管理
会员管理的核心是储值和积分。储值功能的技术要点是资金流水记录——每笔充值、每笔消费扣款,都要在member_account_log表里留下记录。积分逻辑相对简单,可以按消费金额的一定比例(比如每消费1元得1积分)累积,积分可以在结算时抵扣现金。
员工管理模块包含账号、姓名、手机号、角色、排班等字段。角色建议用ROLE_ADMIN(管理员)和ROLE_STAFF(普通员工)区分,管理员拥有系统全部权限,普通员工只能操作点餐、结账等前台功能,不能进入菜单管理、员工管理等后台设置模块。
在员工密码的处理上,有一点需要特别强调:绝对不能明文存储密码。用BCryptPasswordEncoder做哈希加密,Spring Security本身就提供了这个工具类,直接在配置类里注入Bean就能用。很多同学嫌麻烦直接明文保存,这在答辩时一旦被问到就是一个明显的安全硬伤。密码加密的成本极低,演示效果却很好,没有理由不做。
2.5 进货与库存管理
进货管理这个模块在餐厅内部管理系统里属于容易被忽视、但真正体现“系统完整性”的部分。前厅的订单、后厨的食材消耗、仓库的库存变化,这三者应该构成一条完整的数据链路。
食材表记录每种原材料当前的库存总量、安全库存阈值和计量单位。每次新增进货单,库存数量对应增加;每次菜品出餐,库存按配料比例扣减。当库存数量低于安全阈值时,系统在进货管理页面对该食材进行高亮提示,提醒管理员需要补货。
在实际操作里,我建议库存扣减采用下单即扣减的策略,而不是结账后再扣减。这样做的好处是避免超卖——顾客下单的同时食材就锁定了,如果顾客取消订单,再把库存加回来。这个策略在原材料的实时监控上非常关键,尤其是热门食材,等结账再扣减很可能出现已经没货还在接单的尴尬情况。
3. 数据库设计与关键技术点解析
3.1 核心表结构与关系设计
数据库设计是毕业设计评分中占比最大的一部分,也是最能体现专业功底的地方。我建议至少设计以下九张核心表:
| 表名 | 用途 | 关键字段 |
|---|---|---|
| category | 菜品分类 | id, name, sort |
| dish | 菜品 | id, category_id, name, price, image, status |
| table_info | 餐桌信息 | id, table_no, seat_count, status, area |
| member | 会员 | id, phone, name, balance, points |
| orders | 订单主表 | id, order_no, table_id, member_id, total_amount, status |
| order_item | 订单明细 | id, order_id, dish_id, dish_name, dish_price, quantity |
| employee | 员工 | id, username, password, name, role, phone |
| stock_item | 库存食材 | id, name, unit, quantity, alert_threshold |
| stock_in | 进货记录 | id, stock_item_id, quantity, supplier, create_time |
需要理解的是菜品表和订单明细表的关系。菜品价格和名称可能随时变化,而订单明细表需要保留下单那一刻的准确信息,所以订单明细表里同时存在dish_id和冗余的dish_name、dish_price字段,这正是我之前提到的快照设计。桌面显示的餐桌信息表与订单主表关联,通过table_id查询当前在该桌的订单号,就能判断餐桌状态是否被占用。
关于主键的命名统一问题,我见过不少项目每个表的主键字段名都不一样(有的叫id,有的叫order_id,有的叫menu_id),这会让MyBatis-Plus的默认映射规则失效,最后不得不写大量Xml配置来指定字段对应关系。最省心的做法是全部统一命名为主键字段id,业务字段名用蛇形命名法,并在实体类上使用@TableField注解映射下划线到驼峰命名。
3.2 安全验证与统一异常处理
餐厅内部管理系统的安全体系,最容易做出的亮点有两个:登录认证和接口防刷。
登录认证我推荐使用Sa-Token作为权限框架,它相对于Spring Security最大的优势是API简单,尤其是登录、退出、权限验证这些高频操作,几行代码就能搞定。核心思路是用户登录成功后获取一个Token,后续请求在请求头中携带Token,Sa-Token通过拦截器校验Token是否有效。做过一次这个流程后,你会对“无状态认证”有很直观的理解。
统一异常处理的实现分成两层。第一层是使用@RestControllerAdvice定义一个全局异常处理器,把业务异常(比如菜品已售罄、餐桌已被预订)和系统异常(比如参数错误、空指针)分别映射到不同的HTTP状态码和统一返回结构。第二层是自定义一个业务异常类BizException,在Service层遇到预期内的业务问题时,主动抛出这个异常,由全局处理器捕获并返回给前端。
这样设计的直接收益是Controller层代码非常干净——不需要每个接口都写try-catch,业务逻辑里只需要关心正常流程。全局返回结构建议统一为{code, message, data}这个三段式格式,前端可以非常统一地处理成功与失败场景。
3.3 分页查询与条件检索
餐厅管理系统几乎所有列表页面都需要分页。菜品列表、订单列表、进货记录、员工列表,统统是典型的表格分页场景。
用MyBatis-Plus操作分页,第一件事是配置分页插件PaginationInnerInterceptor。配置完成后,Service层只需要构造一个Page对象和一个LambdaQueryWrapper查询条件构造器,就能执行分页查询,返回的结果集里自动包含总记录数、当前页数据、总页数等分页元数据。
条件检索的实现重点在查询条件构造器上。比如订单列表支持按状态筛选、按餐桌号筛选、按时间段筛选,这时候用LambdaQueryWrapper逐层拼接条件即可。这里有一个要注意的地方:时间段筛选包含了起始时间是否包含当天零点、结束时间是否需要加23:59:59的问题,最好提供一个统一的日期处理工具类来处理。否则,日期边界条件很容易导致数据统计偏差。
3.4 报表统计与数据可视化
报表统计是餐厅管理系统区别于普通CRUD项目的重要加分项。设计得当的统计功能,能让答辩时老师的印象分上一个台阶。
我认为最值得做的三个统计维度是:每日营业额趋势、菜品销量排行、时段客流分布。每日营业额趋势可以通过对orders表按日期分组并SUM总金额实现;菜品销量排行可以基于order_item表按菜品分组并SUM数量实现;时段客流分布则需要统计每个小时段产生的订单量。
为了性能考虑,不建议在首页每次都直接对整张订单表做全量聚合。可以增加一张daily_report汇总表,每次订单状态变更为“已完成”时,通过事务同时更新当日汇总数据。这样首页大屏展示时,只需要查这一张小小的汇总表,响应速度飞快。这是典型的“以空间换时间”思路,在真实的企业系统中非常常见。
图表展示层面,前端可以使用ECharts来画折线图和柱状图,非常简单。后端接口返回按日期排序的数据列表,前端直接绑定渲染即可。
4. 实操过程与核心环节实现
4.1 项目初始化与依赖配置
项目创建我是从Spring Initializr开始的,选择Maven工程,Java版本选8或11,Spring Boot版本选2.7.x。为什么不用Spring Boot 3.x?因为3.x要求JDK 17以上,而且部分兼容性插件还没有完全跟上,对毕业设计而言,2.7.x的稳定性和资料丰富度都要高很多。如果你已经装了JDK 17,也可以用3.x,但记得选择对应的依赖版本,别混用。
核心依赖加入spring-boot-starter-web(Web支持)、mybatis-plus-boot-starter(ORM)、mysql-connector-j(数据库驱动)、lombok(简化实体类)、sa-token-spring-boot-starter(权限认证)。Pom文件里BOM的管理方式能帮你规避版本冲突,建议直接依赖spring-boot-starter-parent作为父工程。
配置文件我习惯使用application.yml,核心配置项包含数据库连接地址、用户名、密码、MyBatis-Plus的日志输出和驼峰映射开关、端口号。数据库连接池推荐使用HikariCP,它是Spring Boot默认接入的,性能表现好,基本不需要额外调整参数。
初始化完成后的第一件事,就是写一个HelloController测试接口,确认项目能够正常启动和响应。这一步看似简单,但能一次性排查环境变量、Maven仓库、端口占用等基础问题。千万别跳过,直接写业务代码然后一口气启动调试,那是效率最低的做法。
4.2 实体类、Mapper层与业务层搭建
实体类开发是数据层的基础,用Lombok的@Data注解省去手写Getter/Setter的重复代码。每个实体类都要使用@TableName注解明确指定对应的数据库表名,避免MyBatis-Plus默认规则将实体类名映射到错误表名。字段映射上,@TableField可以区分哪些字段需要自动填充(如创建时间、更新时间)。
MyBatis-Plus的Mapper层继承BaseMapper<T>,默认就有selectById、insert、updateById、deleteById这些方法,基本满足单表CRUD的需求。多表联查的场景,可以在Mapper接口中自定义方法并书写XML,但建议优先考虑在Service层用多次单表查询加组合的方式处理。对毕设而言,关联查询的复杂度和可维护性都要再三权衡,避免在XML里写超长SQL导致调试困难。
Service层的接口设计建议遵循IService模式和ServiceImpl基类的写法。例如EmployeeService继承IService<Employee>,EmployeeServiceImpl继承ServiceImpl<EmployeeMapper, Employee>实现接口。这种模式下,MyBatis-Plus提供了一整套泛型CRUD方法,后端业务开发速度能快很多。
4.3 登录认证与角色权限落地
登录认证的完整流程是这样的:
前端提交用户名和密码到/api/auth/login,后端Service接收参数后,通过用户名从数据库查出员工记录,用BCryptPasswordEncoder的matches方法比对密文密码。比对成功,则调用Sa-Token的StpUtil.login(employeeId)方法完成登录,这个方法内部会自动生成一个Token值,并通过StpUtil.getTokenInfo().getTokenValue()取出来返回给前端。前端后续所有请求都在请求头里携带这个Token。
Sa-Token对权限控制提供了非常简洁的注解方案。在需要管理员权限的接口上添加@SaCheckRole("ROLE_ADMIN")注解,在需要登录状态才能访问的接口上添加@SaCheckLogin注解。拦截器方面,注册Sa-Token的拦截器到Spring MVC配置中,路径匹配设置为/**,这样所有请求都会被拦截并验证登录状态。
这里有一个真实际问题:有时候你明明登录成功了,但后续请求仍然提示未登录。绝大多数情况下是因为前端请求没有携带Token或者携带方式不对。需要检查前端请求拦截器是否正确地从本地存储中取出Token并放到了请求头satoken字段里。
4.4 点餐流程的完整实现逻辑
点餐流程是餐厅系统的核心业务链,它的完整时序大体是:顾客扫码入座 → 选择菜品加入购物车 → 提交订单 → 生成待支付订单 → 支付成功后通知后厨 → 后厨出餐 → 顾客用餐完成 → 结账清台。
Service实现上,创建订单方法带上@Transactional事务注解,逻辑分为以下几步:
校验餐桌状态是否允许开台,校验菜品是否在售且库存充足,计算订单总金额(遍历购物车,逐个按菜品价格乘以数量累加,再次强调这里用的是菜品表的当前价格,并且下单成功后写入订单明细的快照),生成订单编号(可以用时间戳加随机数,保证全局唯一),插入订单主表和明细表,更新餐桌状态为就餐中,扣减库存并判断是否触发预警阈值。
这段逻辑里有几个边界情况非常考验代码健壮性:一个购物车里有多道菜,其中一道刚好售罄,该如何处理。我建议整单失败,并返回明确的菜品名称提示,而不是部分成功部分失败。判断库存的逻辑放在事务开始前,防止并发情况下出现超卖。
4.5 财务管理模块的实现
财务管理的核心是收入统计与对账功能,要搞清楚每天收了多少钱、有几个订单、客单价是多少。
一个实用的实现方案是增加一个财务流水表finance_record,记录每笔收入或退款的时间、金额、关联订单号、收支类型。当订单支付成功时,同时写入一条收入流水;当订单发生退款时,写入一条支出流水。这样财务模块的聚合查询只需要基于流水表做分组统计,逻辑非常干净。
日报表功能按天汇总总流水金额、订单数、退款数、实收金额这几个核心指标,页面呈现可以用一个简单的列表或一个小型柱状图。需要注意的是,金额字段在数据库中推荐使用DECIMAL(10,2)类型,避免使用double或float,因为浮点数在累计求和时会有精度损失——这是非常常见的低级错误,但一旦发生,对账时永远对不上。
4.6 项目打包部署与答辩演示准备
毕业设计最终要能现场演示,部署环节不能出岔子。最稳妥的方式是打包成JAR文件直接运行,流程是:在application.yml中配置生产环境的数据库连接,确认端口未被占用,然后执行mvn clean package命令,在target目录下生成可执行的JAR包,最后用java -jar target/xxx.jar启动项目。
很多同学在这个环节忽略了静态资源的路径。如果项目用了本地上传菜品图片,默认会存到当前运行目录下的某个文件夹。用JAR方式启动时,当前目录通常与开发时不同,图片路径可能会失效。我建议在配置文件中显式指定一个绝对路径来存储上传文件,或者在启动命令中固定工作目录。
答辩演示还有一个小技巧:准备一份独立的演示数据,包括至少20个菜品、5张餐桌、3名员工、若干件会员与订单记录,并且确保演示数据能呈现出“有账单、有统计数据”的效果。我见过不少同学现场演示时系统空空如也,连图表都画不出折线,这样的展示效果很难拿到高分。
5. 常见问题与排查技巧实录
5.1 环境与启动类问题
启动报错是开发期最频繁的问题,我整理了最常见的几个错误类型,每一项都是我实际开发中踩过的坑:
| 错误现象 | 根本原因 | 解决方案 |
|---|---|---|
| 启动提示端口被占用 | 8080端口被其他进程占用 | 修改server.port配置或netstat -ano查PID后结束进程 |
| ClassNotFoundException: driver | MySQL驱动版本与JDK不兼容 | 确认使用com.mysql.cj.jdbc.Driver,驱动版本与MySQL版本匹配 |
| Unknown database | 数据库未创建 | 先在MySQL中执行CREATE DATABASE语句,注意字符集选utf8mb4 |
| table doesn't exist | 表结构与实体类映射不一致 | 核对@TableName注解与实际表名,核对大小写敏感性 |
| 中文乱码 | 连接串未指定字符集 | jdbcUrl追加?useUnicode=true&characterEncoding=utf8 |
5.2 逻辑与数据类问题排查
开发过程中最常见也最难排查的,是下单后库存没有扣减、订单状态没有变化这类逻辑Bug。排查思路要按照“从一张表到另一张表”的方式逐层推进:先确认提交订单的请求参数是否正确,接着确认Controller层是否被正确调用,再检查Service层方法是否真的执行到了扣减库存的那一行(可以打日志确认),最后检查数据库里的数据到底是没更新还是更新后被覆盖了。
一个容易被忽略的点是MyBatis-Plus的自动填充拦截器如果配置了创建时间字段的自动填充,但是插入时并没有给实体类对应属性赋值,那么数据写入后创建时间可能为空。这类问题不会让服务直接报错,但会在查询统计时造成很多莫名其妙的结果。
5.3 性能优化与前端对接经验
毕设项目的性能优化我总结为三个字:别过度。核心优化就做两个:数据库常用查询字段建立索引,分页查询务必使用MyBatis-Plus的分页插件。不要一开始就引入Redis缓存或者消息队列,这些技术用在这样规模的项目里属于过度设计,答辩时很容易被老师反问“你为什么要用这个技术”。
前后端对接经验倒是非常重要,特别是跨域问题。前端和后端分离部署时,后端接口需要开启CORS支持。在Spring Boot里配置一个实现WebMvcConfigurer的配置类,添加addCorsMappings方法,允许前端域名的跨域请求,通常也就十几行代码的事。
还有一个非常实战的小细节:联调时把application.yml中MyBatis-Plus的日志配置打开(configuration.log-impl: org.apache.ibatis.logging.stdout.StdOutImpl),这样每次执行的SQL语句都会打印到控制台。前端说“这个接口没数据”,你一眼就能看到SQL是否多了一个条件、where条件是否拼错。这个排查方式效率极高。
6. 项目答辩要点与论文写作拆解
6.1 答辩时容易被追问的考点
答辩环节老师主要考核“是不是你自己做的”和“你到底理解了多少”。基于过往答辩经验,下面几个问题被问到的概率最大:
数据库为什么这么设计?回答要点在于强调表之间的关联关系、订单明快照设计防止价格变动、状态字段替代物理删除确保数据可追溯。权限是怎么控制的?回答要点是Sa-Token的认证流程,Token生成、校验、拦截器注册,以及BCrypt密码加密原理。事务是怎么控制的?回答要点是Spring的@Transactional注解机制,何时回滚、如何保证订单、库存、餐桌状态的一致性。遇到并发场景怎么办?回答要点可以先讲悲观锁和乐观锁的概念区别,然后说明项目落地用了哪种(比如库存扣减用乐观锁,通过版本号或条件更新实现)。
6.2 论文结构与写作节奏建议
论文写作我有几个建议,能让整个流程更顺畅。需求分析章节里面不要只用文字描述业务,配合用例图能更好地呈现系统角色与功能边界。数据库设计章节要完整展示E-R图和每张表的字段说明,这部分内容有对应关系,写起来很快。系统实现章节不要大段贴代码,每个模块挑一到两个核心方法,配上关键代码片段和解释,这样更符合老师的阅读习惯。测试部分建议采用表格化的测试用例描述,把输入、预期结果、实际结果列清楚。
在有系统原型或者核心功能写完后再动笔,论文和代码同步推进,效率会高很多。
7. 项目扩展方向与个人经验总结
如果做完了基础功能还有富余时间,可以考虑以下扩展方向,它们能显著提升系统的完整度与答辩的含金量:引入WebSocket实现订单实时推送,后厨大屏随时显示新订单;接入支付宝沙箱或微信支付沙箱完成真实支付流程闭环;增加打印机小票输出的模拟模块,完善餐厅收银环节;用ECharts做营业额趋势分析,配合定时任务生成每日经营数据汇总。
我个人在多年做这类项目的过程中的体会是,一个毕业设计项目最关键的并不是技术栈有多新,而是链路完整性。从登录开始,到下单、支付、后厨出餐、库存扣减、每日财务汇总,整条链能闭环跑通,并且你在任何一个环节都能讲清楚“为什么这么设计”,这已经足以撑起一篇优秀的毕业设计了。如果你正在做这个选题,先把核心链路的数据库表和Service逻辑理清楚,再去修饰页面细节和配置项,这样永远不会出现临近提交却连项目都跑不起来的窘境。