
每到毕业季找我聊Java毕设项目的人就多了起来而“基于Spring Boot的汽车维修保养服务信息系统”绝对是咨询量靠前的那一档。这个项目不复杂但业务链条很完整——从客户建档、车辆信息登记到维修工单流转、保养到期提醒、配件库存管理最后再到结算统计基本把一个真实汽修门店的日常运营装进了一个Web系统里。对做毕设的同学来说它最大的价值在于技术栈主流Spring Boot MyBatis Plus MySQL业务规模适中既有常规CRUD展示又有业务流程和定时任务能够撑起一篇完整的毕业设计论文。今天这篇文章我不打算只给你贴源码截图而是把这个项目彻底拆开讲清楚为什么这么设计、核心模块怎么落地、拿到手之后怎么跑起来、调试时最容易卡在哪一步、答辩时怎么讲才不像在背稿。源码和文档是交付物但这些背后的思路和坑才是真正值钱的东西。1. 项目核心价值与整体设计思路1.1 维修保养行业到底需要什么系统先别急着聊技术从业务说起。中小型汽修门店的日常管理长期处于一种“半纸质化”的状态客户信息写在笔记本上车辆保养记录靠翻纸质工单库存配件数量靠脑子记到期该保养的车主靠微信挨个通知。这些做法不是不能用而是当门店积累了几百个客户、几十辆车在库、每个月上百张工单之后效率会断崖式下跌。汽车维修保养服务信息系统本质上就是给这类门店做一套数字化的管理后台。它要解决的核心问题有三个第一客户和车辆档案的统一管理让员工能随时查出一辆车的历史维修保养记录第二维修工单的生命周期控制从开单、派工、维修、完工到结算每一步都有状态记录第三配件库存和财务统计的联动避免配件卖超了、库存空了还不知道。很多同学看到这类项目会觉得“不就是几个增删改查页面吗”这个判断既对也不对。单看每个功能确实就是CRUD但当这些CRUD被业务逻辑串起来之后就会出现一些值得写进论文里的设计点比如维修工单的状态流转、保养提醒的定时任务、库存扣减与工单结算的事务一致性。这些都是答辩时能讲出深度的素材。1.2 系统功能模块全景拆解一套标准的汽车维修保养服务信息系统我的划分方式是七大功能模块正好对应七类使用场景。这里面既有面向客户的数据也有面向员工和后端管理员的业务流。功能模块核心功能点对应数据表面向角色客户管理新增客户、会员等级、联系记录customer前台、管理员车辆管理车辆档案、维保历史、多车关联vehicle前台、技师预约接车在线预约保养/维修、前台接车登记appointment客户、前台维修工单开单、派工、进度跟踪、完工结算repair_order / repair_item前台、技师保养提醒按里程/时间自动生成提醒任务notice / vehicle系统自动配件库存入库、出库、库存预警、收发记录inventory / stock_record库管统计报表收入统计、工单量、热门项目排行聚合查询管理员这些模块之间的数据关系也不复杂核心链路是客户挂车辆车辆挂工单工单挂维修项目维修项目可能涉及配件出库出库记录反过来联动库存表。这条链路串起来就是一个典型的主从表 关联查询的业务模型。1.3 为什么这个选题适合做Java毕设我自己经手过的Spring Boot毕设项目里维修保养这类选题属于“性价比”很高的那一档。原因有三点。第一业务复杂度适中。它比单纯的图书管理、学生管理系统难一些因为涉及多实体关联和状态流转但又比电商、秒杀这类高并发项目简单得多适合本科阶段独立完成。第二技术覆盖点完整。Spring Boot全家桶能用到Web开发、MyBatis持久层、MySQL数据库设计、定时任务、权限拦截、文件上传等常见技术点论文里的“技术路线”一章可以写得很充实答辩时也有东西可讲。第三可扩展空间大。这个系统想加功能非常容易比如接微信推送提醒、接ECharts数据可视化大屏、接入支付宝模拟结算每一个都能成为项目亮点。后文我会专门说几个值得做的扩展方向。2. 技术选型与工程架构解析2.1 版本选型Spring Boot 2.7还是3.x技术选型的第一件事是定版本这一步坑最多。现在网上大量现成教程和开源项目基于Spring Boot 2.x而Spring Boot 3.x虽然已经非常成熟但它有两个很大的变化一是强制要求JDK 17及以上二是把原来的javax命名空间整体迁移到了jakarta。这意味着老代码直接使用会报包找不到、注入失败等一系列问题。对于毕业设计这种一定要“稳”的场景我的建议是默认使用Spring Boot 2.7.18 JDK 1.8的组合。理由很朴素JDK 8是最普及的运行环境java -version不会在电脑上翻车网上能搜到的参考资料最多遇到问题谷歌一搜一大把MyBatis Plus、Thymeleaf等框架对2.x的兼容性验证最充分。现在热词里大家都在搜“springboot版本太高”怎么办其实就是升到3.x之后发现依赖冲突和API变了。如果你的课题没有明确要求使用最新版本不要为了图新而选择3.x这不是技术落后而是工程上的稳重要求。MyBatis Plus选用3.5.x版本它自带分页插件、逻辑删除、自动填充这些实用特性配置起来也比原生MyBatis省事很多。MySQL建议8.0如果本地用的是5.7也能兼容但驱动类名注意统一写成com.mysql.cj.jdbc.Driver。2.2 项目目录结构与分层设计思路拿到工程源码之后第一件事不要急着跑而是先看目录结构。标准的Spring Boot项目按职责分层每一层各司其职这是答辩时必被问到的点。car-maintenance/ ├── src/main/java/com/car/maintenance/ │ ├── config/ # 配置类分页插件、跨域、拦截器 │ │ ├── MybatisPlusConfig.java │ │ ├── WebConfig.java │ │ └── CorsConfig.java │ ├── common/ # 通用返回结果、统一异常、工具类 │ │ ├── Result.java │ │ ├── PageResult.java │ │ └── GlobalExceptionHandler.java │ ├── controller/ # 控制层接收请求返回JSON │ ├── service/ # 业务层事务、状态流转、业务规则 │ │ └── impl/ │ ├── mapper/ # 数据访问层接口 XML │ ├── entity/ # 数据库实体类 │ ├── dto/ # 接收前端参数的传输对象 │ └── utils/ ├── src/main/resources/ │ ├── mapper/ # MyBatis XML文件 │ ├── templates/ # Thymeleaf模板页面 │ ├── static/ # CSS、JS、图片 │ ├── application.yml # 核心配置 │ └── sql/init.sql # 建库建表脚本 └── pom.xml这样的分层对应的是“请求进controllercontroller调serviceservice调mappermapper操作数据库”的标准调用链。好处是职责清晰后续做事务管理、加缓存、换实现类都不需要改动上层调用代码。答辩时如果被问到“为什么要分层”你可以从解耦和可维护性两个角度答单一职责可独立测试业务逻辑不散落在Controller里。2.3 MyBatis Plus在项目里的正确用法MyBatis Plus并不是一个新框架它是在MyBatis基础上封装的增强工具简化了单表CRUD。在维修保养这种关系型业务里它的正确打开方式有这么几个点。第一主键策略。实体类的主键字段加TableId(type IdType.AUTO)配合数据库自增主键使用避免手动指定ID。第二逻辑删除。给需要保留历史数据的表增加deleted字段实体字段标注TableLogic然后在application.yml里配置逻辑删除的全局值。这样所有删除操作都变成update语句维修工单、客户档案这类数据即使“删除”了也能追溯。第三自动填充。create_time和update_time这两个字段几乎每张表都有用TableField(fill FieldFill.INSERT)配合MetaObjectHandler实现插入和更新时自动填充省去每个Service里手工set时间的重复代码。第四分页插件。定义一个MybatisPlusInterceptorBean并添加PaginationInnerInterceptor否则Page对象查询时total永远为0。这个坑很常见后面我会在问题排查节单独说。另外多说一句很多人搜“MyBatis Plus根据Java实体类生成建表SQL”这里其实有个概念混淆。MyBatis Plus本身的设计方向是“根据表生成实体”而不是反过来根据实体生成表。正宗的建表方式是把resources/sql/init.sql里的DDL脚本在数据库客户端里执行如果你确实想从实体自动建表那是JPA的ddl-auto干的事但这类项目一般不会把建表交给ORM。所以最稳妥的做法是我交付的源码里已经带好了完整的建库建表脚本你只需要导入执行即可。2.4 前端方案Thymeleaf一体化还是Vue前后端分离这个项目的界面展示有两种常见形态选择哪一种会影响整个工程结构。第一种是Thymeleaf服务端渲染方案前端页面用Bootstrap jQuery搭建放在templates目录下。这种方案最大的好处是部署简单打包出一个jar包直接跑不需要额外启动前端服务也不需要处理跨域问题非常适合毕设演示环境关键时刻不容易出幺蛾子。第二种是Vue3 Element Plus前后端分离方案后端只提供JSON接口。它的界面更精致交互更现代也能体现“前后端分离”的技术点但是工程量明显增大要处理跨域、构建部署等额外环节。对于时间紧、且没有强制要求的同学我不建议在毕设阶段强行上这种架构。所以我默认推荐Thymeleaf一体化方案。这不是技术保守而是工程决策毕业设计的核心评价标准是完整度、正确性和业务深度把精力花在业务逻辑和数据设计上比花在前端框架搭建上划算得多。当然如果你有定制需求想要Vue版本前端部分可以换成Vue工程后端提供Restful接口这也是我经常帮学生定制时做的调整。3. 从零到一的搭建实操流程3.1 数据库设计核心表结构与字段规划数据库设计是整个项目的基石网上很多源码跑不起来问题往往不在代码而在表结构不完整、导入脚本有误。我这套项目里总共设计了9张核心表这里把最重要的几张表的结构和设计意图写清楚。-- 客户表 CREATE TABLE customer ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, name varchar(50) NOT NULL COMMENT 客户姓名, phone varchar(20) NOT NULL COMMENT 手机号, gender tinyint DEFAULT 0 COMMENT 性别 0未知 1男 2女, address varchar(255) DEFAULT NULL COMMENT 联系地址, member_level tinyint DEFAULT 0 COMMENT 会员等级 0普通 1银卡 2金卡, create_time datetime DEFAULT NULL, update_time datetime DEFAULT NULL, deleted tinyint DEFAULT 0, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT客户信息表;-- 维修工单表 CREATE TABLE repair_order ( id bigint NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 工单编号 如WO20250601001, customer_id bigint NOT NULL COMMENT 客户ID, vehicle_id bigint NOT NULL COMMENT 车辆ID, technician_id bigint DEFAULT NULL COMMENT 技师ID, status tinyint NOT NULL DEFAULT 0 COMMENT 状态 0待派工 1维修中 2待结算 3已完成 4已取消, total_amount decimal(10,2) DEFAULT 0.00 COMMENT 总金额, check_remark varchar(500) DEFAULT NULL COMMENT 接车检查备注, create_time datetime DEFAULT NULL, update_time datetime DEFAULT NULL, deleted tinyint DEFAULT 0, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT维修工单表;设计时要注意的点金额字段用decimal(10,2)不要用float否则浮点精度问题会让你在结算时吃大亏凡是会作为查询条件的字段比如customer_id、vehicle_id、status都要建普通索引所有业务表都带create_time、update_time、deleted三个通用字段这是后面做自动填充和逻辑删除的基础工单号不能依赖数据库自增ID直接在页面展示一般会用日期随机数生成可读性和唯一性都有保障。3.2 从零创建工程依赖清单与配置文件详解如果你是打算在自己电脑上重新搭一遍这个项目不要手写pom.xml里的版本号直接去Spring Initializr网站选依赖生成骨架IDEA自带的Spring Initializr也行用阿里云镜像地址可以加速依赖下载。需要选的依赖有Spring Web、Thymeleaf、Lombok、MySQL Driver、Validation。MyBatis Plus因为是第三方框架需要自行在pom.xml中引入starter依赖。dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version /dependency工程创建好之后核心配置文件application.yml要按下面的思路去写每一个配置项背后都是一个容易踩的坑server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/car_maintenance?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: root thymeleaf: cache: false jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0数据库URL里必须带上serverTimezoneAsia/Shanghai否则高版本MySQL驱动连接会报时区错误characterEncodingutf8保证中文不乱码allowPublicKeyRetrievaltrue是为了解决MySQL 8.0驱动在非SSL连接时偶尔报的Public Key Retrieval not allowed问题。map-underscore-to-camel-case: true这个配置让数据库字段create_time自动映射到Java属性createTime省去一大堆TableField注解。3.3 逆向生成还是手写Mapper表结构设计完毕、工程骨架搭好之后接下来要创建实体类、Mapper接口、Service和Controller。这一步有一个很省力的选择使用MyBatis Plus的代码生成器AutoGenerator它可以直接读取数据库表结构自动生成全部实体和基础CRUD代码。我用这套流程时通常会按以下步骤走第一步在数据库中执行init.sql确认所有表都建成功第二步配置AutoGenerator的数据库连接信息、包名、输出目录第三步运行生成器指定要生成的表名第四步在生成结果的基础上手工改造。需要手工重写的主要是Service里的业务逻辑比如维修工单的状态变更不能只是简单update而要校验前置状态保养提醒不能只查一条数据而要批量扫描并生成提醒记录。生成器能帮你节省70%的重复代码时间但不能替你写业务。如果你不愿意用代码生成器手抄一下entity和mapper也就多花一两个小时个人建议后者其实更利于答辩讲清楚每个类的来龙去脉。这个见仁见智。3.4 核心业务实现工单状态流转与保养提醒维修工单是这个项目最有价值的业务模块它不是一个简单的增删改查而是有状态机逻辑的。状态定义一般是待派工、维修中、待结算、已完成、已取消。每一次状态变更都对应一个动作前台接车开单进入待派工技师确认接单后变成维修中完工填写维修项目金额后变成待结算财务收款后变成已完成如果客户取消或者异常情况则进入已取消。这里有一个很重要的开发习惯就是不要暴露原始的update接口给前端。比如不能写一个通用接口让前端传一个status字段就更新库而是应该拆成几个语义明确的接口比如assignOrder、startRepair、completeRepair、settleOrder。每个接口内部做前置校验再更新状态。这样有三个好处业务逻辑清晰、答辩好讲、接口不容易被乱调用。保养提醒模块则是用Spring Boot的定时任务实现。在启动类上加EnableScheduling然后在专门的定时任务类里写一个方法使用Scheduled(cron 0 0 8 * * ?)表示每天早上8点执行。Component public class MaintainRemindTask { Scheduled(cron 0 0 8 * * ?) public void checkMaintainDue() { // 查询所有车辆 ListVehicle vehicles vehicleService.list(); for (Vehicle v : vehicles) { boolean needRemind false; // 按时间判断距离上次保养超过6个月 if (v.getLastMaintainTime() ! null v.getLastMaintainTime().before(LocalDateTime.now().minusMonths(6))) { needRemind true; } // 按里程判断当前里程 - 上次保养里程 5000 if (v.getMileage() - v.getMaintainMileage() 5000) { needRemind true; } if (needRemind) { // 生成提醒记录关联客户ID noticeService.addRemind(v.getCustomerId(), v.getId(), 您的车辆 v.getPlateNo() 该保养了); } } } }这段逻辑虽然简单但能很自然地引出“主被动业务”的讨论哪些数据是靠用户操作产生的哪些是系统主动计算产生的这就是信息系统的价值所在。4. 拿到源码之后运行调试与部署演示全流程4.1 本地环境三步启动法很多同学从网上下载了源码第一反应是双击运行结果一堆红色报错立刻心态崩了。按下面三步走基本能避免八成问题。第一步核对环境。JDK必须是1.8或11Maven必须是3.6以上。在命令行里执行java -version和mvn -v确认版本然后检查IDEA里的Project SDK设置和Maven配置确保指向了正确的本地仓库。第二步导入数据库。打开Navicat或者命令行客户端创建一个名为car_maintenance的数据库然后选择运行SQL文件执行项目里resources/sql/init.sql。执行成功后应该能看到9张表以及预置的管理员账号数据。这一步很多人会漏掉或者只创建了数据库却没导入表导致启动时直接报“Table doesn arm exist”。第三步修改配置并启动。打开application.yml把数据库用户名密码改成你自己本机的确认URL里的库名和你刚才建的库名一致然后运行主启动类MaintenanceApplication。启动日志中出现“Started MaintenanceApplication”字样就说明启动成功了。浏览器访问http://localhost:8080默认账号一般预置admin初始密码123456。4.2 拿到源码后必须要改的默认配置交付源码时我为方便学生直接跑通默认配置往往是开发环境最简配置但你在自己电脑上调试时有几个位置是必须先动的。数据库密码是第一要改的如果你本机密码不是root不改的话连接必然报Access denied。端口号第二要改的默认8080如果被占用了改成8081或其他不常用端口即可。还有日志路径如果你项目里配置了logging.file记得同步改成本机存在的目录否则日志写不进去会一直告警但不影响运行。最后是预置数据。init.sql里如果没有预置管理员账号项目启动后你是无法登录页面的需要手动插入一条用户记录注意密码字段要按项目里配置的加密方式写入是BCrypt还是MD5加盐看代码里的PasswordEncoder实现。如果项目用的是简单的MD5那写SQL时可以直接插值如果用的是BCrypt必须先生成加密串再插入。4.3 Maven打包与答辩演示的准备到答辩前两天强烈建议你在本地把打包流程走一遍确认mvn clean package能顺利打出jar包。注意打包时默认会执行测试如果你单元测试没有全部通过可以加-Dmaven.test.skiptrue跳过测试。mvn clean package -Dmaven.test.skiptrue java -jar target/car-maintenance-0.0.1-SNAPSHOT.jar打包成功后你的演示环境就可以脱离IDEA独立运行这在答辩现场非常关键。有同学在答辩时电脑开了IDEA、数据库、浏览器一堆窗口现场演示一紧张IDEA突然弹个Update提示框页面就切不过去。直接把jar包放在桌面双击运行或者命令行启动浏览器访问干净利落。演示之前我建议你在系统里提前录入一套完整的数据一个客户张三、一辆车“京A12345”、一张维修工单、一条保养提醒记录。答辩时从客户列表点开车辆从车辆点开历史工单再切到统计页面展示生成好的图表这条演示链路顺畅且完整比现场现创建数据要稳妥得多。5. 常见问题排查与避坑指南5.1 启动阶段高频报错速查表报错信息可能原因解决方案Access denied for user数据库密码错误检查application.yml用户名密码Unknown database数据库没创建或库名不对CREATE DATABASE car_maintenance检查URL库名Table doesnt existSQL脚本没导入或导入库选错重新执行init.sql确认导入到目标库Port 8080 was already in use端口被占用改server.port或用netstat查占用进程Consider defining a bean of type XxxMapperMapper接口没扫描到启动类加MapperScan或每个Mapper加MapperInvalid bound statement (not found)XML没编译或namespace不匹配清理target目录重新打包检查XML路径Unsupported class file major versionJDK版本和SpringBoot要求不符统一使用JDK 1.8或11检查IDEA设置启动阶段最容易导致心态崩溃的通常是Mapper相关报错。这类问题的核心是MyBatis在启动时需要扫描到所有Mapper接口和对应的XML文件一旦接口scan不到或者XML的namespace和接口全限定名不一致依赖注入时就会报找不到Bean。解决方法是检查启动类有没有MapperScan(com.car.maintenance.mapper)以及mapper-locations配置是否覆盖了XML目录。5.2 运行阶段的功能性Bug项目跑起来之后最常见的几个功能性Bug分别是分页total始终为0、日期格式渲染不对、定时任务不执行、事务不生效。这四类问题我把判断技巧和解决办法一次性说清。分页不生效90%的情况是没配分页插件。MyBatis Plus的Page对象虽然查出了当前页数据但如果没有PaginationInnerInterceptortotal就一直是0。在MybatisPlusConfig里加一个拦截器即可。日期格式不对Java端明朝的LocalDateTime返回到前端变成“2025-06-01T10:30:00”这种带T的格式。不要为每个字段加注解在application.yml里统一配置Jackson的date-format和time-zone如果是前端页面用Thymeleaf渲染还可以借用#temporals工具类格式化。定时任务不执行判断逻辑很简单——启动类上有没有EnableScheduling。没加这个注解所有的Scheduled方法都不会被触发。另外cron表达式建议用在线生成工具写别自己凭感觉数位。事务不生效在Service类的方法上加了Transactional却发现异常时数据没回滚。原因往往是方法被同类内部调用代理失效。要保持事务只标注在Controller直接调用的入口方法上不要在Service内部互相调用的事务方法上再调自己的事务方法。5.3 答辩时的常见技术追问与应对话术答辩环节老师大概率不会为难你但会拿几个高频技术问题试探你到底有没有真正写过代码。下面这几个问题我建议你提前准备。第一个MyBatis Plus和MyBatis的区别是什么。标准回答是MyBatis是原生持久层框架需要手写SQL和映射配置MyBatis Plus是增强工具内置通用CRUD方法、分页插件、逻辑删除、代码生成器单表操作无需写SQL复杂SQL仍然支持XML手写。第二个Spring Boot的自动配置原理是什么。你要能说出SpringBootApplication实际上是由EnableAutoConfiguration、ComponentScan、SpringBootConfiguration组合而成自动配置会扫描META-INF/spring.factories文件里的配置类按照条件注解生效。第三个项目里哪里用了事务。这个问题要落到你的实际代码上比如维修工单结算时要同时修改工单状态、扣减配件库存、插入结算记录这三个操作必须处于同一个事务里任何一个失败都要整体回滚。把这段代码打开指着Transactional注解回答比空谈概念有效一百倍。第四个系统的性能瓶颈在哪如果客户量提升怎么办。可以坦白说目前是针对中小门店的单体应用并发量提升时可以引入Redis做热点缓存比如库存数据、客户列表数据库层面增加索引优化慢查询有更大量级再考虑微服务拆分。这个回答既谦虚又展示了思考深度。5.4 交付源码后我建议你做的三件事最后作为交付后的建议我希望你不要只满足于“跑起来能交差”。一个能从良的毕设项目还可以再做三件事提升完成度。第一件事把统计报表模块补上。哪怕只是用ECharts画两个收入趋势折线图和保养项目占比饼图整个项目的视觉完成度和“信息系统”的感觉都会立刻上一个层次。这个功能也适合放进论文的“系统实现亮点”章节。第二件事把权限控制做细。现在很多毕设系统只要登录就能访问所有页面这是硬伤。用Spring Boot的拦截器或者直接引入Sa-Token框架把角色权限拆成管理员、前台、技师、库管四类不同身份登录看到不同的菜单页面和接口都做权限校验。这一点写进论文的“系统设计”里非常加分。第三件事给项目写一个README。内容包括项目简介、技术栈、启动步骤、默认账号、功能清单、目录结构。答辩老师拷走你的代码时第一眼看的就是README一个清晰的README会让你在老师心里的印象分直接上一个台阶。我在实际带项目时最深的体会是很多问题不是技术难度的问题而是流程不规范导致的。版本不统一、配置不对齐、数据没初始化这些肉眼都能查得出来的问题却消耗了同学们最多的调试时间。所以这篇文章与其说是在介绍某一个项目不如说是在分享一套做Spring Boot毕设的标准作业流程——先从业务把表设计清楚再搭工程配环境然后分模块实现最后统一测试打包。按照这个顺序来你收获的不只是一个能交差的系统和一篇论文而是一套以后进企业做真实项目也能直接用的方法论。最后再分享一个小技巧如果你拿到了源码先把init.sql从头到尾读一遍再动手改代码。读懂建表脚本你就能明白这个系统为什么这么设计也就能在答辩被问到“这个字段为什么这么设计”的时候给出有理有据的回答。这个习惯比任何代码都值钱。