SpringBoot汽车维修管理系统毕设:从数据库设计到答辩完整指南
2026/9/15 21:35:14 网站建设 项目流程

又到了一年一度的毕业设计季,群里隔三差五就有人问"Java毕设做什么题目好""SpringBoot的项目有没有参考"。如果你点进了这篇文章,大概率正在为《基于SpringBoot的汽车维修管理系统设计与实现》这个题目发愁,或者准备选类似的题目。这个题目的好处在于业务场景够接地气:维修工单、客户车辆、配件库存、结算单,这些功能模块逻辑清晰,不涉及复杂的算法,但又能把Web开发的核心知识点串起来,用来做毕业论文刚刚好。

这篇文章不打算给你贴整段代码,而是把我在做这个系统时完整的设计思路、数据库建模过程、后端实现细节、前后端联调踩的坑,还有论文写作和答辩准备的要点,一次性讲清楚。哪怕你之前只是跟着教程敲过几个demo,照着这个思路走,也能把这个毕设稳稳落地。

1. 项目整体设计与技术选型

1.1 为什么选SpringBoot而不是SSM

先说选型。你这个题目既然叫“基于SpringBoot”,那技术栈基本就锁定了,但选SpringBoot本身也是有道理的,不是图省事。前几年毕业设计流行SSM(Spring + SpringMVC + MyBatis),你去看那些模板论文,光是spring-context.xml、spring-mvc.xml、mybatis-config.xml这些配置文件就能写好几页。SpringBoot把这一堆配置全干掉了,通过自动配置加约定优于配置,把常用组件都给你准备好了。什么意思呢?就是你加一个spring-boot-starter-web依赖,引入之后它自动帮你配置好内嵌Tomcat和SpringMVC,打完jar包直接java -jar就能跑,不用再去装一个Tomcat单独部署。

我做这个项目之前也纠结过,要不要用传统SSM给论文凑点篇幅?后来想明白了,论文的核心是系统功能,不是配置文件的堆砌。SpringBoot能让你把精力集中在业务代码上,少花大量的时间在处理XML上,这才是毕设该有的状态。而且SpringBoot本身也是当前企业里Java后端的主流框架,答辩的时候老师问起来,你回答“选SpringBoot是因为它的自动配置机制、内嵌服务器和丰富的starter生态,能快速搭建健壮的应用”这一句话,比你在SSM里讲了五分钟配置文件有说服力多了。

1.2 技术栈选型对比

确定了SpringBoot之后,其他技术选型也要逐个过一遍。下面这个表是我当时对比后确定的最终方案,你可以直接抄这个配置,也可以根据自己情况微调。

技术组件推荐选型理由
服务端框架SpringBoot 2.7.x稳定、资料多、JDK8兼容,不建议上来选3.x
ORM框架MyBatis-Plus单表CRUD不用写SQL,节省大量时间
数据库MySQL 5.7或8.0免费、通用、学校机房基本都有
登录鉴权JWT无状态、前后端分离友好,比Session好解释
前端框架Vue 2 + Element UI上手快、组件美化程度不错,配后台很合适
构建工具Maven没什么好说的,SpringBoot官方默认就是Maven
开发工具IDEA + Navicat社区版IDEA够用,Navicat看数据方便

这里要特别说一句,SpringBoot版本别一上来就选最新的。我当时看到SpringBoot 3.x出来了,也想追新,结果发现它要求JDK17起步,而且部分第三方starter的兼容性还没有完全跟上。毕业论文场景最怕的是“环境折腾半天跑不起来”,所以老老实实选2.7.x配JDK8,是最稳的组合。等以后工作了爱折腾新版本随便折腾,毕设阶段求稳比求新重要。

另外,为什么不用Spring Data JPA?JPA确实很好用,但很多人学完就忘,答辩的时候老师问“这个字段映射是怎么做的”“懒加载和N+1问题怎么解决”容易答不上来。MyBatis-Plus走的是MyBatis的路子,SQL由你自己控制,老师问起来更好说,而且它自带的代码生成器基本能帮你把实体类、Mapper、Service、Controller一次性生成完,对毕设来说非常友好。

1.3 功能模块规划

技术栈定下来之后,先把功能模块画清楚。我当时按照汽车维修门店的真实场景,把系统拆成了下面六个模块:

  • 系统登录与用户管理:管理员、前台接待员、维修技师三种角色,支持不同角色的权限控制。
  • 客户信息管理:维护客户基本资料,包括姓名、电话、地址、身份证号等。
  • 车辆信息管理:一个客户名下可以绑定多辆车,记录车牌号、品牌型号、车架号(VIN)、发动机号、当前里程等。
  • 维修工单管理:核心模块,创建工单以后要能维护维修项目、添加使用配件、记录故障描述、更新维修状态,最后生成结算单。
  • 配件库存管理:配件的入库、出库、库存预警、历史出入库记录。
  • 数据统计与报表:统计每天的维修收入、工单数量、热门维修项目排行等,用简单的图表展示。

模块不用贪多。有的同学喜欢加一堆花里胡哨的功能,什么在线预约、保养提醒、会员卡充值,这些你如果时间充裕可以加,但要是论文写不完、系统跑不通,那加再多功能也是给自己挖坑。把上面这六个模块做出完整闭环,论文和答辩的素材就已经很充足了。

2. 数据库设计与核心业务模型

2.1 数据表设计思路

数据库设计是论文里的重头戏,也是系统能不能跑通的关键。我当时画完E-R图之后,梳理出来一张总览表,核心的表大概是这些:

表名用途核心字段
sys_user系统用户username, password, real_name, role
customer客户信息name, phone, address, id_card
car_info车辆信息customer_id, plate_number, brand, model, vin, mileage
repair_order维修工单主表order_no, customer_id, car_id, status, symptom, worker_id, total_amount
repair_order_item工单维修项目明细表order_id, item_name, labor_hours, labor_fee
parts配件表part_no, name, brand, spec, stock, warning_stock, price
part_usage_record配件出库记录表order_id, part_id, quantity, unit_price, total_price
settlement结算单表order_id, part_fee, labor_fee, total_amount, real_amount, pay_method, status

这里面最关键的是repair_order表,我单独说一下。主键我用的自增Long型,order_no是手动生成的业务单号,格式类似"WO20240515001",这样客户和员工看到单号就知道是几号的第几单,比直接用自增ID给人看舒服得多。status字段用int类型存状态码,配合代码里的枚举类来做状态流转控制,这个后面会详细讲。

还有一个细节值得注意:客户和车辆是一对多关系,一辆车只属于一个客户,但一个客户可以有多辆车。所以car_info表里放customer_id做外键。工单和车辆也是关联的,repair_order表里同时存customer_id和car_id。为什么不只用car_id反查客户?因为工单需要冗余客户ID,方便在客户信息被修改或者某些极端情况下,历史工单依然能查到当时的客户归属。数据库设计里冗余是一把双刃剑,但在这种业务场景下,存一个冗余字段换取查询的方便,是完全划算的。

2.2 维修工单状态机设计

维修工单是整个系统的灵魂,它的状态流转一定不能乱跳。我见过很多同学用一堆if else到处改状态,最后改到逻辑自己都看不懂。我的做法是用枚举把状态定义清楚,在Service层统一控制流转规则,不允许任意跳转。

public enum RepairOrderStatus { WAITING(0, "待接单"), REPAIRING(1, "维修中"), PENDING_SETTLEMENT(2, "待结算"), COMPLETED(3, "已完成"), CANCELLED(4, "已取消"); private final int code; private final String desc; RepairOrderStatus(int code, String desc) { this.code = code; this.desc = desc; } // getter... }

状态流转的规则就这几条:待接单可以变成维修中,也可以变成已取消;维修中只能变成待结算;待结算变成已完成;已取消之后不能再动。这几条看起来简单,但你要在代码里兜住它,我就封装了一个changeStatus方法,只有传过来的当前状态和下一个状态符合流转规则时才放行,否则直接抛异常。

这一步不光是代码层面的健壮性,还是论文里可以画状态图的好材料。你在论文里放一张状态流转图,再配上这段说明,评审老师一眼就知道你是认真设计了业务逻辑的,不是随便堆功能。

2.3 表结构的几个关键细节

数据库这块我再补几个实际操作中的经验。

第一个是密码存储问题。sys_user的password字段千万别明文存储,用BCrypt哈希之后存进去。SpringSecurity里自带BCryptPasswordEncoder,但有些同学没接Security可能觉得不方便。其实用jBCrypt这个库很简单,几行代码就能做哈希校验。答辩的时候你说一句“用户密码没有明文存储,用BCrypt做了不可逆加密”,这是很明显的加分点。

第二个是金额字段类型。money相关的字段用decimal类型,不要用float和double。后端用BigDecimal接收,避免浮点数精度丢失。我之前写代码图省事用double,结果算配件费用的时候出现8.999999这种值,排查了大半天才发现是精度问题,教训太深了。

第三个是时间字段。create_time和update_time建议直接让MyBatis-Plus自动填充,用@TableField(fill = FieldFill.INSERT)配合MetaObjectHandler在插入和更新时自动写入当前时间,省得每写一条SQL还要手动set时间。

第四个是逻辑删除。repair_order和customer表不要物理删除,加一个deleted字段,用MyBatis-Plus的逻辑删除能力,查询的时候自动带上deleted=0条件。这样历史数据都还在,论文里解释数据可追溯性时也可以说道。注意要在yaml里配置全局逻辑删除字段名,并且在字段上加@TableLogic注解。

3. 后端核心实现与关键技术点

3.1 项目初始化和公共代码搭建

后端代码我是分这么几层写的:Controller接收请求、Service处理业务、Mapper处理数据库交互,再加上统一的DTO、VO对象和异常处理。项目初始化直接用IDEA的Spring Initializr生成,选择Java 8、SpringBoot 2.7.x,依赖勾上Spring Web、MySQL Driver、Lombok,然后手动加入MyBatis-Plus和JWT相关依赖。

<pom关键依赖参考这里:>

<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency>

项目起步最值得花时间的就是把公共代码写好,因为后面所有模块都在用。我优先写了三个东西:

第一个是统一返回结果对象Result。所有接口的返回值都包装成Result ,结构是code、message、data三个字段,成功时code为200,业务异常时code为统一约定的错误码。这样前后端对接非常清晰,前端axios响应拦截器只要判断code来不是200,就统一弹出后端返回的错误信息,不用每个接口单独处理。

第二个是全局异常处理。在类上标注@RestControllerAdvice,里面用@ExceptionHandler分别处理业务异常、参数校验异常和兜底的Exception。有了它之后,Controller里不需要写try catch,业务出错了就throw一个自定义的BusinessException,全局处理器会统一捕获并转成Result返回给前端。这代码写完之后整个项目的容错性一下子就上来了。

第三个是Controller层的参数校验。使用spring-boot-starter-validation里的@Validated和@NotBlank这些注解,在DTO字段上做非空、长度校验。RequestBody接收的时候自动完成参数检查,不合法就直接抛MethodArgumentNotValidException,再由全局异常处理器转成清晰的错误提示。这一套下来,写业务接口的时候非常丝滑。

3.2 登录鉴权(JWT方案)

登录鉴权是这个系统里答辩必问的一个模块,你得把它吃透。我的方案是:用户提交用户名密码,后端查询数据库,用BCrypt校验密码,校验通过后生成JWT令牌返回给前端,前端每次请求在请求头里带上Authorization: Bearer ,后端通过拦截器解析token获取用户信息。

生成Token的代码核心逻辑大致是这样的:

public String generateToken(Long userId, String username, String role) { return Jwts.builder() .setSubject(String.valueOf(userId)) .claim("username", username) .claim("role", role) .setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); }

解析的时候用Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token),拿到Claims之后就可以获取userId和角色信息。我在拦截器里做了这样的处理:先放行登录接口,其他接口统一从Header里取token,校验不过就返回401,校验通过就把userId放到request attribute里,后续Controller和Service里随时取用。

这里有个很关键的细节,JWT工具类里那个secretKey千万别写死在代码里,至少放到application.yml配置里。答辩的时候老师可能会问“token泄露了怎么办”,你回答“token设置了24小时过期时间,并且可以在系统里做用户状态控制,如果用户被禁用,下次请求就会因为用户状态校验失败而被拒绝”,这样你就把无状态token和用户的强制失效机制做了一个结合,算是比较圆满的答案。

角色权限方面,我没上SpringSecurity那一套复杂的东西,因为自己手写的拦截器足够用了。管理员、接待员、技师三种角色,通过注解或者在拦截器里判断role来实现接口级别的访问控制。毕设阶段的接口权限其实不需要做得特别细,主要是页面按钮级别的控制,管理员能看到所有菜单,接待员和技师只能看到被授权的菜单,这个放在前端路由守卫里做更高效。

3.3 MyBatis-Plus实战要点

MyBatis-Plus在这个项目里帮我省了非常多的时间,主要体现在三个方面。

第一是BaseMapper提供的通用CRUD。实体类写好后,Mapper接口直接继承BaseMapper ,不用写任何方法,selectById、insert、updateById、deleteById这些就全都有了。删除操作配合@TableLogic做逻辑删除,自动帮你在Update或Delete的时候改成逻辑删除语句。

第二是条件构造器QueryWrapper和LambdaQueryWrapper。复杂查询条件通过它来组装,不需要写一堆@Select注解。例如维修工单列表要支持按状态筛选、按车牌号模糊搜索、按时间范围查询,直接用LambdaQueryWrapper就能构造出来:

public IPage<RepairOrderVO> queryRepairOrderPage(RepairOrderQueryDTO dto) { Page<RepairOrder> page = new Page<>(dto.getCurrent(), dto.getSize()); LambdaQueryWrapper<RepairOrder> wrapper = new LambdaQueryWrapper<RepairOrder>() .eq(StringUtils.hasText(dto.getStatus()), RepairOrder::getStatus, dto.getStatus()) .ge(dto.getStartDate() != null, RepairOrder::getCreatedTime, dto.getStartDate()) .le(dto.getEndDate() != null, RepairOrder::getCreatedTime, dto.getEndDate()) .orderByDesc(RepairOrder::getCreatedTime); return baseMapper.selectPage(page, wrapper); }

第三是分页插件。MyBatis-Plus的分页效果是物理分页,原理是拦截器在SQL末尾拼上LIMIT,我自己不需要在SQL里写Limit。使用前配置一个分页插件,这样Service里直接传Page对象进去,返回IPage就能拿到总记录数和当前页数据了。

需要注意的是,如果你要写一些多表关联查询,比如工单列表要把客户名、车牌号带出来,这种还是得自己写SQL。我的做法是写一个VO类,然后在Mapper接口里自定义一个selectRepairOrderPage方法,用@Select注解写多表联查SQL。MyBatis-Plus只适合单表CRUD和简单查询,复杂查询别硬刚,老老实实写SQL反而更直观。

还有个大坑必须提醒你:实体类的驼峰命名和下划线字段映射。我的application.yml里是这样配置的:

mybatis-plus: configuration: map-underscore-to-camel-case: true

这样就自动把数据库里的plate_number映射到实体类的plateNumber字段,不需要额外写resultMap。

3.4 维修工单核心流程与事务控制

维修工单创建是整个系统里最复杂的业务操作,逻辑上做这么多事:根据前端传来的客户ID、车辆ID、维修项目列表、配件ID和数量,先创建工单主记录,再一条条保存维修项目明细,配件出库要扣减库存,同时生成一条配件出库记录,最后还要统计所有费用计算总金额。在创建过程中任何一步出了问题,前面的数据都不能留在数据库里。这靠的就是Spring的@Transactional注解。

我在创建工单的Service方法上标注了@Transactional(rollbackFor = Exception.class),这个方法内部所有数据库操作都在同一个事务里,要么全部成功,要么全部回滚。rollbackFor设为Exception.class是关键,否则默认情况下运行时异常才回滚,一般异常不一定触发。

配件库存扣减的代码是业务里最容易出Bug的,我当时的写法是这样的:

for (PartUsageDTO item : dto.getParts()) { Parts part = partsMapper.selectById(item.getPartId()); if (part == null) { throw new BusinessException("配件不存在:" + item.getPartId()); } if (part.getStock() < item.getQuantity()) { throw new BusinessException("配件库存不足:" + part.getName()); } // 扣减库存 partsMapper.reduceStock(part.getId(), item.getQuantity()); // 记录出库明细 partUsageRecordMapper.insert(new PartUsageRecord(...)); }

这段代码有两个细节:扣减库存用的是Update语句,不是先查出来改了再更新,避免并发下数据不一致;库存不足的判断放在扣减之前,并抛出业务异常触发事务回滚。你要是想更严谨,扣减库存的Update语句本身就是原子操作,可以写成UPDATE parts SET stock = stock - #{quantity} WHERE id = #{id} AND stock >= #{quantity},返回影响行数为0就说明库存不足。这是并发安全的标准写法,能够很大程度避免多人同时操作时超卖的问题。

维修工单的状态查询、接单、完成维修、结算,每一个状态变更都要加上currentStatus校验。比如接单操作,前端传工单ID和当前状态,后端Service里先根据ID查出来,判断当前状态是不是WAITING,如果已经被别人接单改成REPAIRING了,就直接提示“工单状态已变化,请刷新后重试”。这样至少保证状态流转不会被重复操作搞乱。如果还想更极致一点,可以在repair_order表加一个version乐观锁字段,用MyBatis-Plus的@Version实现乐观锁,答辩的时候说这个是并发控制的优化点,也是加分项。

4. 前端页面与联调要点

4.1 后台管理页面搭建

前端这块如果你的论文要求不高,我建议直接用Vue 2加Element UI来做,不要自己写CSS布局,会把自己耗死。我的做法是在码云上找一个开源的Vue后台管理模板(比如vue-element-admin的简化版),把登录页改成自己的、菜单改成自己这几个模块就行。这样页面美观程度一下子就有了,省下的时间全部用来写后端逻辑和论文。

页面整体结构就是左边侧边栏菜单、顶部导航条、中间内容区。路由按功能模块拆分:登录页、首页工作台、客户管理、车辆管理、维修工单、配件管理、结算记录、系统用户管理。配合菜单权限,不同角色登录后显示的菜单不一样。具体实现就是登录成功后把用户角色存到store里,然后动态注册路由,或者直接v-if控制菜单项。

维修工单列表页是功能最丰富的页面。表格展示工单号、车牌号、客户名、状态、总金额、创建时间,顶部放筛选条件(状态、日期范围、车牌号搜索),操作列放接单、维修完成、结算、查看详情这些按钮,根据工单状态动态显示可见的按钮。这个交互设计在论文的功能测试章节可以详细描述,老师看着也舒服。

维修工单详情页可以做成一个抽屉或者弹窗,里面分成几个区块:车辆信息、客户信息、故障描述、维修项目列表、配件使用列表、费用统计。项目列表允许动态添加行,每加一个维修项目就重算一次总金额。这个动态列表的思路是给一个table数据数组,点添加就push一行,删除就splice,最后提交时把整个数组传给后端。

4.2 接口联调与跨域问题

前端项目一般是npm run dev跑在8080端口,SpringBoot默认后台在8080端口,如果你两个端口一样那肯定起冲突,我当时的做法是前端跑8080端口,SpringBoot在application.yml里改成9090端口,这样也是平时开发的常见做法:

server: port: 9090

前后端端口不同,就肯定有跨域问题。解决跨域有两种常见方案:后端加全局CORS配置,或者前端用代理。我当时两种都用了,开发环境用前端Vue的proxy代理比较方便,生产环境部署时后端加CORS兜底。

后端加CORS的配置很简单,新建一个配置类实现WebMvcConfigurer,重写addCorsMappings方法:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

如果前后端分离部署,允许携带凭证信息时allowedOriginPatterns要写成具体的前端域名,不能写*配合allowCredentials(true),这会有冲突,当时折腾了很久。

axios封装方面,我统一在src/utils/request.js里创建了一个axios实例,baseURL指向/business-api或者直接用Vue_APP_BASE_URL环境变量,请求拦截器里加上token,响应拦截器里统一处理Result结构,如果code不等于200就调用Element UI的Message组件弹出错误信息。这套封装做好之后,后面写每个页面接口都省力很多。

联调过程中最常见的坑就是字段名对不上。后端返回的字段是createdTime,前端写成了createTime,一查接口半天才发现是字段名拼写不一致。所以前后端最好先把接口文档对一下字段,或者直接用Swagger/knife4j自动生成接口文档。我在项目里集成了knife4j,访问/doc.html就能看到所有接口的调试页面,答辩的时候现场演示接口调试效果也很有说服力。

5. 论文写作与答辩准备

5.1 论文章节安排与写作重点

系统做完之后,论文的撰写是另一场硬仗。我记得我的论文一共写了七章,这个结构比较标准,你可以直接参考,也能套用到其他软件的论文里:

  • 第一章 绪论:介绍汽车维修行业背景、国内外信息化现状、研究意义和主要研究内容。这块不用写太长,重点说清楚为什么需要维修管理系统。
  • 第二章 相关技术介绍:SpringBoot、MyBatis-Plus、Vue、MySQL、JWT。每项技术写个两段就够,重点从“为什么用它”的角度写,别大段复制百度百科。
  • 第三章 系统分析:可行性分析(技术、经济、操作三个维度)、业务流程分析、功能性需求和非功能性需求、用例图、用例描述表。
  • 第四章 系统设计:系统总体架构图、功能模块结构图、E-R图、数据库表结构设计。
  • 第五章 系统实现:按功能模块逐个贴页面截图和核心代码,配上功能和实现逻辑说明。
  • 第六章 系统测试:测试环境、典型测试用例表格、部分测试结果截图、测试结论。
  • 第七章 总结与展望:总结做的内容,提一下不足和后续优化方向。

写论文最忌讳的是大段贴代码。评审老师基本不看你的代码,他要看的是你为了标明实现了这个功能,贴一小段关键代码并配上说明文字,这样就可以了。每张图、每个表格都要有编号和标题,规范看起来才像是认真写的。

章节之间要有逻辑连接,从行业背景推导出系统目标,从需求分析推导出模块划分,从模块设计推导出数据库设计,从设计实践推导出实现结果。评审的时候评委最爱问的一句话是“你这里为什么这么设计”,你要保证论文里对每一个关键设计都给出了理由,理由不一定要多高大上,但要自圆其说。

5.2 答辩高频问题与应对

答辩的时候老师问的问题往往不是特别深,但经常围绕几个点来问,我总结下来集中在这几类:

第一个高频问题必然是“SpringBoot的自动配置原理”。这个问题你一定要能说清楚。一个简单好记的思路是:SpringBoot在启动时通过@SpringBootApplication里的@EnableAutoConfiguration注解,去加载META-INF/spring.factories文件里列出的所有自动配置类,每个配置类上都有@ConditionalOnClass、@ConditionalOnProperty之类条件注解,满足条件就生效,加载对应的Bean到Spring容器里。比如引入了spring-boot-starter-web,WebMvcAutoConfiguration就会自动配置DispatcherServlet。你能说到这个程度,老师基本不会追问。

第二个是“MyBatis-Plus和MyBatis有什么区别”。回答思路是:MyBatis-Plus完全兼容MyBatis,在它基础上增强了很多功能,比如通用的BaseMapper提供单表CRUD、条件构造器、分页插件、逻辑删除、自动填充等。对于单表操作不用写SQL,复杂查询自己写SQL也不受影响。这就是你选它的核心理由。

第三个是“登录是如何鉴权的”。这个问题我在前面讲过,把你的流程讲清楚就能过:登录成功返回JWT,前端每次请求在Header带token,后端拦截器解析token,成功就把用户信息放到request上下文里,Controller里可以获取用户ID和角色来校验权限。再补充一下BCrypt加密和token有效期,就非常完整了。

第四个是“工单状态并发问题怎么保证的”,或者“库存扣减并发超卖怎么解决”。这个问题考察的是你对业务并发场景有没有考虑过。你就说数据库的原子更新SQL plus乐观锁方案,然后举一个实际例子来解释,老师会认为你真的做过系统。

答辩的时候有两点要特别注意:第一,自己系统代码里的核心部分一定要能说清楚,即使代码是你参考别人的,也要把模块的逻辑关系融会贯通了再说,不要一被追问就慌;第二,尽量准备一台笔记本现场演示系统,跑不通也要提前准备截图。只有讲才会显得你是实干出来的。

6. 避坑指南与效率技巧

6.1 实战中踩过的坑

做这个系统过程中踩过的坑挺多的,我把几个最典型、也最影响进度的记录在这里,给正在做项目的同学一个提醒。

第一个是Maven依赖下载慢的问题。没有配置镜像前,首次构建项目可能要等十几二十分钟,有的包还总下载失败。解决方法是把settings.xml里的中央仓库镜像换成阿里云镜像,这样速度会快很多。如果你已经建好了工程,也可以在pom.xml里的 标签里加mirror仓库配置。

第二个是MySQL8的驱动和时区问题。用MySQL8时,driverClassName要写成com.mysql.cj.jdbc.Driver,url里必须拼上serverTimezone=Asia/Shanghai,否则会因为服务器时区设置不一致报错。MySQL5.7用的驱动还是com.mysql.jdbc.Driver,两套写法容易混,我当时就踩了驱动类名不匹配的坑。

第三个是LocalDateTime在JSON序列化的问题。SpringBoot默认用Jackson序列化,LocalDateTime默认会变成数组格式或者ISO格式,前端显示非常难看。我在application.yml里做了全局配置:

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8

并且在属性上用@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")做了兜底,这样所有接口返回的时间格式就统一了。

第四个是Long型主键传给前端精度丢失问题。这个真的是偶发问题,前端拿到的ID和数据库里的ID不完全一致,因为Java Long的精度超过了JavaScript Number的安全整数范围,导致调用详情接口时ID不对。解决方案是在ID字段上标注@JsonSerialize(using = ToStringSerializer.class),把Long转成字符串返回给前端,前端就能原样保存并在后续请求中传递了。

6.2 提升开发效率的几个技巧

毕设的时间管理也很重要,这几个技巧是我后来复盘觉得最提效的,分享给你。

第一是使用MyBatis-Plus的代码生成器。用MyBatis-Plus Generator可以根据数据库表自动生成实体类、Mapper接口、Service接口和实现类、Controller,只要表结构建好了,几分钟就能生成一套基础CRUD代码。生成后我再手工调整VO、DTO和具体业务逻辑,大部分重复性工作直接被砍掉。需要注意生成器的版本要和MyBatis-Plus版本保持兼容,避免API变动导致代码报错。

第二是善用IDEA的插件。Lombok插件装上之后,实体类一个@Data注解就把getter/setter/toString全搞定了,代码量少很多。MyBatisX插件可以通过Mapper接口方法名生成SQL,还可以在IDE里直接可视化操作数据库表。还有一个生成器的技巧,MyBatisX的代码生成器也很好用,可以直接在IDEA里生成代码,不需要单独建工程跑依赖。

第三是数据准备。开发联调阶段,客户、车辆、配件这些基础数据不要一条条手打,写几个测试类或者直接在Navicat里跑SQL脚本,一次性把十几条基础数据插进去。我当时把维修项目表的基础数据也预先插好了(如机油更换、刹车片更换、发动机检测等),这样演示系统的时候能快速创建一个完整的维修工单,效果好了很多。毕竟演示的时候如果临时造数据,手慢又容易出错,提前准备好完备的演示数据本身就是负责任的表现,也能让答辩更流畅。

第四是频繁重启太浪费时间。SpringBoot开发时,热部署工具spring-boot-devtools是可以配的,它默认会在classpath中检测到文件变更时自动重启应用,虽然还有冷启动的间隔,但比手动重启省事多了。IDEA里还要确保Build project automatically选项已开启。不过要注意,不要依赖热部署来做所有变更,加了新依赖一般需要手动重启一次才能生效。

最后想说的

做这个系统的过程里,我最大的体会是:毕业设计的核心目标不是为了做一个多么惊艳的商业产品,而是把大学几年学的知识体系完整地串起来。从需求分析、技术选型、数据库设计、编码实现,到最后的测试和论文写作,每一个环节都是一次综合能力训练。SpringBoot刚好是一个非常合适的载体,它让你不用在环境搭建上耗太多时间,把精力放到真正需要思考的业务逻辑上,这就是它成为主流后端框架的原因,也是我选它的原因。

最后再分享一个小技巧:做毕设时建议边做边截图、边写笔记。每个模块完成一个功能就截一张运行效果图,把遇到的问题和解法记录下来。到了写论文的时候你才发现这些素材多宝贵,不用再回头去补截图,而且笔记里的排查过程就是你论文“系统测试”章节里最真实的素材。祝你的毕设顺利通过,有问题欢迎在评论区讨论。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询