资讯动态

SSM框架+Vue汽车租赁系统实战:从数据库设计到前后端联调

发布时间:2026/9/24 23:46:07 来源:尧图企业网站定制
拿到这个题目的时候我就觉得挺有意思汽车租赁系统在毕业设计和课程设计里出场率一直很高但能坚持用SSM框架做底子、再用Vue做前端交互的反而比现在清一色Spring Boot脚手架多了一些“把原理搞清楚”的价值。这套SSM296汽车租赁系统vue本质上就是一个典型的JavaWeb全栈项目后端三件套负责业务逻辑和数据持久化前端用Vue做单页交互数据库围绕车、用户、订单三张核心表展开。今天这篇文章不打算只给你贴代码我会把我做这个系统时从数据库设计、后端接口编写到前端页面联调的完整思考过程都拆开讲清楚顺便把踩过的坑、排查问题的方法也一并放出来。不管你是准备拿它当毕设、课设还是想学一下SSM框架怎么和Vue配合这篇文章你都能直接用得上。1. 项目整体定位与技术选型分析1.1 这套技术栈为什么不用Spring Boot先聊一个很多人拿到项目都会问的问题现在新项目都用Spring Boot为什么还选SSM我个人的看法是SSM骨架能让人把三层架构看得更明白。Spring Boot把自动配置、内嵌Tomcat全都藏起来了对一个刚接触JavaWeb的人来说项目能跑起来但很多底层概念是模糊的。而SSM是Spring、SpringMVC、MyBatis三个框架手动整合web.xml、applicationContext.xml、springmvc.xml、mybatis-config.xml四个配置文件全都要自己维护。你在配置数据源、扫描包、配置视图解析器、写Mapper扫描路径的时候能清晰感觉到请求是怎么从Tomcat进入DispatcherServlet再经Controller、Service、Mapper一路传入数据库的。这个项目的定位恰恰适合这种“看得见过程”的技术栈。汽车租赁系统虽然业务不算复杂但用户管理、车辆管理、订单流转、费用计算、公告发布这些模块足够撑起一个完整SSM项目。用SSM不是因为它比Spring Boot更好而是因为这套组合在课程设计和入门学习阶段更能锻炼人对框架整合的理解能力。等将来跳去Spring Boot你会发现原来的框架知识并没有浪费反而能帮你更快看懂自动配置背后在做什么。当然如果你后续想把它升级成Spring Boot版本也不难。把XML配置迁移成依赖注入和application.yml再把web.xml里的DispatcherServlet替换成WebApplicationInitializer或者干脆用Spring Boot的spring-boot-starter-web一键搞定。所以在做SSM项目的时候配置别乱写每一条都要知道干什么后面迁移会非常顺利。1.2 Vue承担的角色与前后端分离取舍既然是SSM搭配vue就需要明确一个关键决策是前后端完全分离、分开部署还是由SpringMVC渲染静态页面。我第一次做这套项目的时候选了完全分离。前端用Vue脚手架起工程开发环境下通过代理转发请求到后端8080端口后端只提供JSON接口不返回任何前端页面。正式部署时前端打包成静态文件放到Nginx或Tomcat的webapps下后端依然跑SpringMVC。这种方式的好处非常明显前后端开发节奏互不阻塞接口一旦约定好前端有Mock数据就能先做页面后端有Postman就能先调通接口。但代价是跨域得处理好、部署结构要清楚、打包之后静态资源路径不能写错。对新手来说这一步没有想象中那么难但确实会比传统的“后端扔一个JSP页面”多考虑一些东西。我当时测试时做过一次非分离的临时方案让Controller直接返回一个test.jsp页面来验证后端环境最后主线还是回归到了前后端完全分离。关于这个取舍我的建议是如果这个项目是你用来交课设或者毕设强烈建议直接用前后端分离答辩时能讲的东西会多很多。问起跨域、部署、接口设计每个点都能展开聊这也是评分老师比较看重的内容。1.3 工程结构设计项目顶层分三大块前端vue目录、后端ssm目录、数据库脚本目录。后端按照Maven标准结构包名建议做成com.xxx.system。常见的包划分是controller接收前端请求、返回JSON数据是前后端交互的入口service业务逻辑层处理订单状态流转、费用计算、库存校验等核心业务mapper或dao层与数据库交互的接口层entity数据库表对应的实体类common放Result包装类、状态枚举、工具类interceptor登录拦截器、权限校验拦截器前端目录就比较标准化了Vue脚手架生成后在src下组织views、router、api、assets等目录。views里我一般按照模块再拆一层比如sys系统管理、car车辆、order订单、user个人中心路由和目录一一对应维护起来非常直观。这样的结构把每一层职责划分得很清晰。controller只做参数接收和结果转化service专心处理业务判断mapper只执行SQL操作。哪怕你后面要换数据库、加功能模块也不会牵一发动全身。2. 数据库设计与业务模型拆解2.1 核心表结构设计汽车租赁系统的数据模型说大不大说小不小但是关键表必须有。我先用户、车辆、订单三张表画好再把辅助表加上去整个系统的数据骨架就立住了。用户表主要字段有用户ID、用户名、密码、真实姓名、手机号、身份证号、性别、余额、角色0管理员1普通用户、状态、注册时间。这里密码不能明文存至少用MD5加盐处理或者直接用BCrypt虽然SSM框架下需要额外引入依赖但很值得。车辆表字段包括车辆ID、品牌、车型、车牌号、颜色、日租金、押金、车辆状态0空闲1出租中2维修中、车辆图片地址、车辆描述、座位数、排量。这里车辆状态字段非常关键会影响“租赁下单选车”的逻辑判断。订单表是核心中的核心字段包括订单ID、订单编号、用户ID、车辆ID、取车时间、计划还车时间、实际还车时间、租用天数、下单时租金单价、订单总金额、应付总金额、订单状态、创建时间。为什么要有“计划还车时间”和“实际还车时间”两个字段因为租车业务中用户可能提前还车也可能逾期还车超时部分费用计算逻辑会不一样。至于下单时的租金单价必须单独存一份原因在于车辆租金后期可能调整如果某张订单创建时租金是200元/天管理员后来把租金改成250元这条订单的金额计算就乱了。保存一份当时的下单快照账目才准确。辅助表还包括公告表、留言反馈表或投诉建议表、租车人审核记录等。留言反馈这块很多简单系统会省略但我觉得加一张表成本很低还能让整个系统的完整度上一个档次至少是“用户能看到自己的历史反馈记录管理员能处理”这样一个完整的闭环。2.2 订单状态机与租赁计费逻辑订单状态建议用数字代号存储前端通过字典映射成中文展示这样数据库只存0、1、2这类值清晰又不占空间。我定义的订单状态规则如下状态值含义说明0待取车用户下单支付或提交管理员确认后生成取车信息1租赁中用户已取车订单进行中2待结算用户还车等待系统/管理员核算超时费用3已完成用户支付尾款或结算完成订单关闭4已取消用户下单后未取车主动取消这里有一个容易被忽略的细节状态的流转不是用户想改就能改的后端controller里必须做状态校验。比如待取车订单只能流转为租赁中或已取消租赁中的订单不能直接跳成已完成必须经过待结算这个中间态因为还车时可能产生额外的超时费用费用没算清楚之前直接关闭订单会留下漏洞。计费逻辑我分成两块一块是正常租车的费用另一块是超时还车的费用。正常费用就是下单时日租金乘以计划租用天数这部分在下单预览时就计算给用户看。超时费用则是按实际超出的天数乘以1.5倍日租金或者超过某个阈值按违约处理。我实际写的是“超出计划还车时间未还每天按租金两倍赔偿”的违约逻辑因为可以避免用户长期占用车辆。还车时业务层根据实际还车时间和计划还车时间对比如果超时就把超时费计算出来然后从用户账户余额扣除。这些操作都必须在同一个事务里完成更新订单状态、扣用户余额、更新车辆状态为空闲任何一个步骤失败都要整体回滚否则会出现“车已归还但余额没扣成功”的脏数据。2.3 角色权限该怎么落表汽车租赁系统的角色其实就两种管理员和普通用户。权限模型不需要整太复杂的RBAC多表关联搞成用户表里加一个role字段就够用。管理员拥有用户管理、车辆管理、订单管理、公告管理、反馈处理等菜单普通用户只能看到首页汽车列表、个人订单、个人信息维护。落库的时候建议管理员账号用SQL脚本初始化一个比如admin / admin密码加密后再写进去避免写死在代码里。前端的控制方式更简单后端接口返回给前端的用户信息里带上role字段前端路由守卫根据角色判断能不能访问某个页面。但真正防越权的地方在后端每个管理端接口的controller里做一遍角色校验。我的习惯是写一个工具方法判断当前登录用户角色如果不是管理员就直接抛出无权限异常。前端藏菜单只是界面体验后端校验才是安全兜底。前端这部分可以结合vue的路由守卫beforeEach做两层控制第一层判断是否登录未登录直接去登录页第二层判断路由的meta信息中要求的角色和当前用户角色是否匹配不匹配就跳404或403页面。这样用户就算手动改地址栏也进不了管理页面。3. 后端SSM核心模块实现3.1 工程骨架与配置文件后端我习惯用IntelliJ IDEA创建Maven项目Java版本用8或11关键依赖是spring-webmvc、mybatis、mybatis-spring、mysql-connector-java、fastjson或Jackson以及数据库连接池Druid。配置文件的组织方式有两种一种是用XML配置一种是纯注解配置。为了体现SSM的原汁原味我建议用XML加注解混搭。Spring的配置交给applicationContext.xml只做扫描、数据源和事务管理SpringMVC的配置交给springmvc.xml主要配置注解驱动、静态资源放行、视图解析器MyBatis的配置就写在mybatis-config.xml里配置驼峰命名映射和日志实现。放一个经典的springmvc.xml要点给你参考mvc:annotation-driven / mvc:resources mapping/static/** location/static/ / context:component-scan base-packagecom.xxx.system.controller / !-- 使用jackson消息转换器解决ResponseBody返回JSON时中文乱码 -- mvc:annotation-driven mvc:message-converters bean classorg.springframework.http.converter.StringHttpMessageConverter property namesupportedMediaTypes list valuetext/plain;charsetUTF-8/value valuetext/html;charsetUTF-8/value /list /property /bean /mvc:message-converters /mvc:annotation-driven这个配置里最容易被忽略的是中文乱码尤其是返回JSON字符串时默认的StringHttpMessageConverter用的编码不是UTF-8接口返回的中文直接变问号。用上面的方式重新设置支持的媒体类型就能避免这个问题。3.2 核心接口与业务代码示例后端接口设计我遵循REST风格但没完全照搬比如列表查询用POST而不是GET因为传输条件多请求体传JSON比参数拼接更方便。核心接口大致是模块接口说明登录/api/user/login登录并返回token或user信息注册/api/user/register用户自助注册车辆/api/car/list车辆分页查询车辆/api/car/add管理员新增车辆订单/api/order/create用户创建订单订单/api/order/back用户还车结算订单/api/order/takeCar管理员确认取车订单/api/order/cancel取消订单以创建订单这个核心接口为例Controller层只做参数接收和结果包装核心业务判断全部下沉到Service层。这是SSM三层架构一个很重要的约定。RequestMapping(/api/order/create) ResponseBody public Result createOrder(RequestBody OrderVO vo, HttpSession session) { User user (User) session.getAttribute(loginUser); if (user null) { return Result.error(请先登录); } return orderService.createOrder(vo, user); }Service层里创建订单至少要做这么几步判断车辆是否存在、车辆状态是否为空闲、计划还车时间是否晚于取车时间、用户余额是否足够覆盖押金加预估租金。这些步骤做不完订单就不允许插入。Mapper层对应的SQL没有复杂到需要大动干戈但有一点值得提醒插入订单后需要回写订单ID方便后续把订单编号生成出来。订单编号我习惯用时间戳加随机数避免并发下单导致主键冲突。3.3 事务、异常与安全处理SSM项目手写事务管理其实很讲究。一个比较典型的坑是只依赖Spring声明式事务的默认行为结果发现某些方法没有生效。原因通常出在两个地方事务管理器的bean没配置或者事务方法被同类内部调用了。同类中方法A调方法BB上的Transactional不会生效因为事务是通过代理对象控制入退的内部调用没有走代理。解决办法是把需要事务的代码下沉到另一个类或者自己通过ApplicationContext获取代理对象调用。异常处理这块建议加一个全局异常处理类。虽然不需要Spring Boot那种RestControllerAdvice但SpringMVC同样支持用注解方式实现方法上标注ExceptionHandler把业务异常统一返回成Result对象前端只需要判断其中的success字段即可。安全方面除了前面提到的密码加密和登录校验之外还应该防止最简单的SQL注入。MyBatis里有两种取值方式一个#{}一个${}这个项目里几乎所有场景都应该用#{}因为它是预编译占位符天然防注入${}是字符串拼接除非是动态排序字段名这种不能预编译的场景否则不要用。车系筛选的时候如果要拼接数据库字段名老老实实写白名单判断前端传什么就拼什么是很危险的习惯。4. 前端Vue页面与交互实现4.1 环境准备与项目初始化做前端之前先把环境弄干净。Node版本建议用16或18npm源建议换成国内镜像安装依赖会快很多。为什么要强调Node版本因为Vue脚手架对Node版本有要求太老的Node在编译时会报错太新的有时候会和旧依赖冲突。Vue版本我建议用Vue 2搭配Vue CLI 4或5原因是这套项目在很多网上的课程设计中都是基于Vue 2写的组件库像Element UI在Vue 2生态里最成熟。当然如果你完全是从头做也可以直接用Vue 3加Vite但那样坑会多一些比如Element Plus的按需引入、Vite跨域代理配置都对基础有更高要求。初始化命令就一行vue create car-rental-front创建的时候手动选择Router、Vuex和CSS预处理器回车等依赖安装完。如果安装过程中卡住很长时间多半是网络问题CtrlC之后用淘宝镜像单独装依赖。Vue项目跑起来之后第一步要做的是改vue.config.js里的代理配置把前端开发服务器的请求转发到后端Tomcatmodule.exports { devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这样前端请求/api/car/list在开发环境会自动转发到http://localhost:8080/api/car/list绕开跨域限制。这也是前后端分离开发阶段最关键的一步配不好你会一直被跨域问题折磨。4.2 路由、状态管理与请求封装前端路由我挂在Router里同时用Vuex存用户信息和状态。登录成功后把用户对象放进Vuex再用localStorage存一份刷新页面后从localStorage恢复登录态。路由守卫是必须写的代码很简单router.beforeEach((to, from, next) { const user Vuex.state.user if (to.meta.requiresAuth !user) { next(/login) } else if (to.meta.role admin user.role ! 0) { next(/403) } else { next() } })第一次做这个功能的时候我踩过一个坑刷新页面Vuex里的数据全部清空路由守卫把已登录用户赶回登录页。后来我在全局注册的地方加了一个初始化逻辑启动时从localStorage尝试读取用户信息并重新commit到Vuex刷新问题就解决了。请求封装方面我用axios创建了一个实例设置baseURL指向/api然后统一拦截器处理token、处理错误状态码。后端返回的Result结构固定成{ code, message, data }这种格式前端拦截器里看到code不等于200就直接跳出提示不用在每个页面重复写错误处理。接口调用的API文件建议全部集中在一个目录。比如src/api/order.js里统一导出订单相关的接口组件里只关心调用方法、传参数、拿结果逻辑非常干净。4.3 用户端页面核心细节用户端的主线是首页、车型列表、车型详情、下单、个人中心。首页通常放一个轮播图加几个精选车型这个没啥难点。车型列表最有讲究的是分页和条件筛选。分页参数page和limit要跟着用户操作实时变筛选条件比如车型品牌、座位数、价格区间都要传回后端。数据回来之后用卡片循环渲染每张卡片放图片、名称、日租价点进去到详情页。车型详情页选好取车时间、计划还车时间后系统要实时计算预计费用。这个计算不能只在前端做后端在下单接口也要重新算但前端可以先算出来给用户预览提升交互体验。Vue的计算属性在这里非常方便监听取车时间和还车时间的变化自动算出天数并计算出金额。下单后的个人订单列表核心是让用户能清楚看到每个订单处在哪个状态。待取车订单可以取消租赁中订单显示“车辆使用中”待结算订单会提示还车超时产生的额外费用明细。这里有一个体验细节值得注意订单状态最好用标签组件显示不同颜色已取消灰色、租赁中蓝色、已完成绿色、逾期红色一眼就能看懂比纯文字直观很多。4.4 管理端页面与后端联调管理端是菜单栏加表格页面的经典组合。车辆管理页面最核心的是新增和编辑车辆表单里有一个滚珠效果是车辆图片上传。因为不打算做独立的文件服务器图片可以存成Base64字符串直接存数据库正常用但要注意图片太大会撑爆数据库表。更稳妥的做法是后端做一个通用的图片上传接口把图片保存在服务器磁盘或项目的upload目录下数据库只存访问路径前端拿相对路径拼上域名就能显示图片。订单管理页面的操作按钮要根据状态动态渲染。待取车订单显示“确认取车”租赁中订单显示“确认还车”待结算订单显示“完成结算”。每个操作都要二次确认避免管理员手滑。还车操作尤其要注意管理员确认还车时后端必须实时从车辆表里选出该车的日租金计算超时费用然后一并更新订单、车辆和用户余额三张表。联调阶段我强烈建议用浏览器的开发者工具观察网络请求。如果接口报404先检查后端RequestMapping的路径和前端请求路径是否完全一致如果报500直接看后端Tomcat控制台的异常栈一般SQL语句不对或者空指针居多。调试Vue页面时Vue Devtools插件是标配可以用来检查组件的data变化和Vuex状态。在浏览器地址栏输入路径直接刷新能访问说明前端路由用的history模式如果部署到服务器上白屏多半是后端没有配置前端路由的fallback。5. 部署、联调与问题排查实录5.1 从开发到部署的完整流程开发完成后第一步是处理前端。在vue工程目录执行npm run build生成的dist目录就是静态资源。如果你后端的Tomcat用来部署所有内容直接把dist里的文件拷贝到Tomcat的webapps/ROOT目录下。Tomcat默认的首页是ROOT/index.html这样做的好处是访问根路径就能进入系统不需要输一堆子路径。但这里有一个细节非常容易被忽略拷贝之前把webapps下原来的ROOT目录备份或删除否则新旧文件混在一起会出现加载了旧资源或者404的情况。我就是因为懒直接覆盖结果dist里的某个文件没有覆盖掉旧的过期文件前端一直加载缓存里的旧JS怎么清缓存都没用最后Clean一下重拷才正常。后端打成war包放在Tomcat的webapps目录下。打包之前要检查Maven配置文件里finalName保持一致发布时就不会出现jar包冲突或资源找不到的问题。数据库脚本先在本地MySQL完整执行一遍确认没有语法错误后再到服务器执行。整个系统部署完成后的访问路径建议是环境前端地址后端接口地址开发环境http://localhost:3000http://localhost:8080生产环境http://服务器IP:8080/http://服务器IP:8080/5.2 高频问题与排错速查表我整理了一份我自己实际遇到过的、以及帮别人排查过的高频问题清单都是可以直接照着查的问题现象可能原因解决办法前端页面能打开但接口请求404后端路径和前端请求路径不一致对比Controller中的RequsetMapping和axios请求url接口请求报403后端登录拦截器拦截了检查拦截器排除路径配置登录接口要放行接口报500后台提示SQL语法错误Mapper.xml的SQL写错复制SQL到Navicat执行验证中文乱码编码不统一保证Tomcat连接器、SpringMVC、数据库连接地址都配置UTF-8部署后刷新页面404前端路由用history模式服务器没有fallback配置改为hash模式或配置Tomcat默认跳转到index.html上传图片后无法显示图片路径拼接错误确认图片存储路径和静态资源映射一致Tomcat启动后访问500数据库没初始化执行数据库脚本检查数据源接口是否正确idea部署无法访问TomcatArtifact没设置对检查IntelliJ的Deployment配置确认Application context每个问题都值得展开说一句。前端刷新404那个问题在SSM项目里尤其容易遇到。Vue的history模式在开发环境没有任何问题因为Webpack DevServer做了历史记录机会但部署到Tomcat之后访问/car/detail这个路径Tomcat找不到对应的物理文件就会返回404。最简单的解决办法是在Vue Router里改成hash模式地址栏会多出一个#但刷新不再出现404。如果非要保持history模式就得多配置一块Tomcat的RewriteValve或者在后端做一个内部转发。再比如登录拦截器的问题。虽然项目里登录流程必须有但如果你在拦截器里把所有路径都拦截了那么自带的登录接口也会被拦住直接造成死循环。正确做法是拦截器排除登录、注册、车辆列表以及静态资源js、css、img这些路径。否则前端页面都加载不出来。5.3 我踩过的坑做这套系统的时候我印象最深的是MyBatis的Mapper接口和XML映射文件绑定问题。当时把Mapper接口和XML放在同一个包下面但是Maven构建时默认不编译xml文件结果一直报“Invalid bound statement”。排查了很久才发现是pom.xml缺了资源过滤配置。解决办法是build resources resource directorysrc/main/java/directory includes include**/*.xml/include /includes /resource /resources /build这个坑几乎每个SSM新手都会踩到提前告诉你有这个概念后续遇到就能快速定位。另一个坑是前端在Node环境中请求图片路径时经常出现跨域问题因为图片路径是/upload/xxx.jpg和/api不在同一个代理规则下。当时我把静态资源的代理也配上了图片才正常显示。开发环境的代理配置修改很简单但别忘了生产环境Nginx或Tomcat也要做对应的静态资源路径映射否则到了服务器环境图片照样挂掉。最后一个坑是关于Druid连接监控的。加了Druid之后启动日志一直报SQL异常排查后才发现是Druid过滤器的StatViewServlet和SpringMVC的DispatcherServlet路径冲突了。所以如果你用了Druid要把/druid/*的访问路径明确排除在SpringMVC的DispatcherServlet映射之外否则两个Servlet抢同一个路径后台一堆莫名其妙的异常。6. 项目能怎么扩展这套SSM车轮子项目完成后可扩展的空间其实挺大我列几个我认为最值得尝试的方向。第一个是接入微信公众号登录或扫码登录模拟真实租赁商家的用户入口。前端的难度在于微信公众号的OAuth2回调地址配置后端要新增一个微信登录接口处理微信服务器的临时授权码换取用户openid再到本地用户表匹配注册。如果不想真的注册公众号也可以用其他平台的第三方登录模拟重点是理解OAuth2的授权码流程。第二个是把计费改成按小时计费的类型比如时租、日租、月租混合计费。这需要改订单表和费用计算逻辑业务复杂度会提升不少但可以展现出你对业务的理解深度。第三个是加一个数据统计管理后台比如按日、按月统计订单量、营业额、热门车型排行。后端可以用group by日期做统计前端用ECharts展示图表效果非常直观。第四个是使用Redis缓存热点数据比如车辆列表、某辆车近期的可租时间区间。虽然SSM项目引入Redis会多搭很多配置但作为进阶扩展点写在README里能让项目多一个亮点。这些扩展方向都不需要改动现有的核心结构属于增量开发。做毕设或者想要在面试中展示这个项目的话挑一个扩展点做深比把所有功能侧搬一遍全堆上去要有说服力得多。个人体会把整套系统从零搭完、跑通、调优前后花了一周。最大的感触是SSM Vue这套组合虽然现在看起来“不够新”但它把现代JavaWeb开发中最重要的几块拼图——IOC容器、AOP事务、ORM映射、前后端分离、跨域处理——全部清楚地串起来了。如果你能完完整整地把这套汽车租赁系统做下来其实你已经理解了JavaWeb开发最核心的那部分能力。再去看Spring Boot、Spring Cloud那些微服务框架时会发现它们只是在这套骨架外面又包了很多自动化和快速集成的壳子。过程中我最推荐的策略是“先跑通、再优化”。很多新手容易陷入“我必须一开始就把代码写得完美”的误区结果纠结在某个细节里花了三天连最基本的登录注册都没实现。我的做法是先实现一个最简会话比如用户注册登录、管理员维护车辆、用户下单选车所有功能都用最简单的代码打通然后在此基础上逐步增加事务控制、异常处理、图片上传、日志监控这些锦上添花的功能。先有主干、再长枝叶项目才能在时间里稳步推进。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑