恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

SSM+Vue开发益农农资管理系统:从数据库设计到部署答辩全流程

  • 首页
  • 资讯中心
  • /
  • SSM+Vue开发益农农资管理系统:从数据库设计到部署答辩全流程

相关资讯

从DRM到合规:浅析AnyPS5类主机破解争议 2026/10/10 23:51:38
数据交易安全实战:解密全链路防护与隐私计算落地 2026/10/10 23:51:38
降ai率工具哪个好用?2026实测8款降低ai率软件,帮你少走90%弯路 2026/10/10 23:51:38

最新资讯

ASPDF在Classic ASP中生成PDF的实战指南
2026年最新8款AI编程工具入门教程深度实测
PJ85718DM+STM32F765ZI工业温测方案:RS-485直驱与双核协同设计
Docker进阶之路(1)
Docker沙箱与容器池:在线代码安全执行的核心技术
分布式 ID 唯一性保障:数据库号段模式在高并发宕机时的安全性防御

今日推荐

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

SSM+Vue开发益农农资管理系统:从数据库设计到部署答辩全流程

发布时间:2026/10/10 23:51:38
SSM+Vue开发益农农资管理系统:从数据库设计到部署答辩全流程 每年毕设季SSMVue的管理系统类项目都是绝对的“流量担当”而“益农农资管理系统”这个题目我第一眼看就觉得很值得聊。它跟满大街的学生管理系统、图书管理系统不一样背后挂着一个非常真实的业务场景农资门店或农业合作社的进货、入库、销售、供应商管理。种子、化肥、农药、农具这些商品不仅种类杂还涉及保质期、库存批次、供应商结算业务逻辑比一般的CRUD要丰富不少。选这个题说明你不想只交个demo凑数而是想把一套完整的前后端技术链路真正走通。这篇文章我就拿这个项目为例子从选题拆解到SSM后端落地再到Vue前端实现、打包部署和毕设答辩避坑把整个流程完整讲一遍。我自己帮学生改过很多套这种系统对典型的代码结构和容易踩的坑都心里有数。下面写的内容不是教科书式的架构科普而是按我实际带项目的思路来说这个系统的核心模块要怎么拆数据库表怎么设计才不返工Controller、Service、Mapper每一层各自该写什么Vue这边路由、Axios、页面组件怎么组织怎么把打包后的前端塞进Spring Boot里跑起来以及最后答辩时老师最爱问的几个点。如果你正准备做类似的毕设或者想用SSMVue练手做个带实际业务背景的完整项目这篇文章可以当一份参考地图来用。1. 项目概述与技术选型思路1.1 益农农资管理系统到底解决什么问题先把这个项目要在真实世界中干的事说清楚。农资店不是普通的零售店它的日常业务有很强的行业特点商品按“品种规格厂家”区分一款复合肥可能有不同配比和包装规格库存要能追溯批次因为部分农资有时间属性供应商不止一家进货价和零售价差价明显同时销售还可能涉及“赊销”也就是农户先拿走货、收成后再结算。所以这套系统不是简单管一个商品列表而是要把“商品—供应商—库存—订单—客户”这条链路都接起来。围绕这些需求我把系统拆成几个核心模块农资商品管理、农资分类管理、供应商管理、库存管理包含入库与出库、销售订单管理、系统用户与权限管理。管理员负责基础数据维护和库存盘点销售人员处理开单、收款、客户信息登记。“基于SSMVue的益农农资管理系统”这个题目的完整含义就是这样一个具有真实业务背景的进销存管理系统。1.2 为什么选SSMVue这套组合说句实在话现在很多新人一上来就直接用Spring BootVue因为Spring Boot省去了大量繁琐的XML配置。但做毕业设计我仍然建议用SSM理由很实在SSM是Spring SpringMVC MyBatis每一层都要你自己配置、自己声明Bean、自己写Mapper映射这逼着你去理解IoC容器、AOP、DispatcherServlet、SqlSessionFactory这些底层机制。答辩时老师问“Spring是什么”“MyBatis的#{}和${}有什么区别”“事务注解的工作原理是什么”你都能从项目实际配置里说出答案。换成Spring Boot很多自动配置是“黑盒”你可能只记得加了几个注解但说不出背后发生了什么。Vue这边就更不用说了它是渐进式前端框架响应式数据绑定、组件化开发、Vue Router路由、Axios请求这些在真实项目里每天都在用。而且Vue有Element UI这样成熟的中后台组件库表格、表单、弹窗、分页、消息提示全都有现成组件能在很短时间内搭出一个像模像样的管理系统界面。SSM负责把后端接口和数据层撑起来Vue负责把交互体验和界面做出来这套组合在毕设场景下性价比非常高。1.3 系统架构与整体技术栈整个项目按典型的单体分层架构来组织浏览器访问Vue页面Vue通过Axios发送HTTP请求到后端SpringMVC的DispatcherServlet接收请求路由到对应的ControllerController调用Service处理业务Service通过MyBatis的Mapper与MySQL交互。流程清晰每一层职责单一出问题时很好定位。后端核心是SSM三件套开发工具用IntelliJ IDEA项目管理用Maven数据库用MySQL 5.7或8.0。前端基于Vue 2.6 Vue Router 3 Axios Element UI构建工具用Vue CLI。这里说明一下为什么用Vue 2而不是Vue 3因为这个项目场景大量依赖Element UI生态Vue 2配合Element UI最成熟稳定网上参考资料也多毕设阶段不容易被版本问题卡住手脚。技术栈选型的核心原则是“求稳”不要在临近交稿时折腾Composition API和新的组件库兼容性。2. 数据库设计与后端SSM核心实现2.1 数据库表设计少返工的关键数据库设计是整个系统最值得花时间的地方。很多同学一上来就建表结果后面写SQL时发现关联关系乱、字段缺失、数据冗余返工成本极高。我的习惯是先画业务对象关系图再落表。这个系统的核心表就这六张用户表、农资分类表、农资商品表、供应商表、库存流水表、销售订单表外加一张订单明细表。先看用户表字段很简单id、username、password、real_name、role、create_time。密码一般用MD5加盐存储不要在数据库里明文保存。权限控制不搞复杂的RBAC用role字段区分“管理员”和“销售员”就够了。农资分类表是典型的树形结构但农资分类深度一般只有两级比如“肥料”下面有“复合肥”“有机肥”所以用parent_id字段就能支持递归查询没必要上嵌套集合模型。商品表是整个系统的核心字段需要认真设计。我给出一个可以直接用的简化版本CREATE TABLE goods ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL COMMENT 商品名称, category_id int(11) NOT NULL COMMENT 分类ID, specification varchar(100) DEFAULT NULL COMMENT 规格如50kg/袋, manufacturer varchar(100) DEFAULT NULL COMMENT 生产厂家, unit varchar(20) DEFAULT NULL COMMENT 单位如袋、桶、瓶, purchase_price decimal(10,2) DEFAULT NULL COMMENT 进货价, sale_price decimal(10,2) DEFAULT NULL COMMENT 零售价, stock int(11) DEFAULT 0 COMMENT 当前库存, image varchar(255) DEFAULT NULL COMMENT 商品图片, status tinyint(4) DEFAULT 1 COMMENT 状态1上架 0下架, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;特别注意我加了specification、manufacturer、unit三个字段。农资商品同名的很多光写“复合肥”根本没法区分是哪个厂家的、多大包装的这三个字段是实际业务里的必填信息。库存流水表记录每一次入库和出库goods_id、change_type1入库、2出库、3盘点调整、change_count、before_stock、after_stock、operator_id、remark。用流水表记录每次变更是个好习惯就算库存数据算错了也能通过流水追责和回溯。订单这块拆成主表和明细表。orders表存订单编号、客户名称、客户电话、总金额、下单时间、操作人order_item表存商品快照、购买数量、成交单价、小计金额。注意订单明细里一定要冗余“商品快照”不能只存goods_id。因为商品价格随时可能调整如果以后追溯历史订单价格已经变了不存快照根本说不清这笔订单当时到底卖了多少钱。2.2 SpringMVC Controller层开发实录后端代码从Controller层开始写最顺手。SSM的Controller既要处理页面跳转也能处理JSON接口。我们这个项目因为前后端分离后端只写JSON接口所以统一用RestController。以一个农资商品管理的接口为例RestController RequestMapping(/goods) public class GoodsController { Autowired private GoodsService goodsService; GetMapping(/list) public Result list(RequestParam(required false) String name, RequestParam(required false) Integer categoryId, RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize) { PageInfoGoods page goodsService.pageQuery(name, categoryId, pageNum, pageSize); return Result.success(page); } PostMapping(/add) public Result add(RequestBody Goods goods) { goodsService.addGoods(goods); return Result.success(); } PutMapping(/update) public Result update(RequestBody Goods goods) { goodsService.updateGoods(goods); return Result.success(); } DeleteMapping(/delete/{id}) public Result delete(PathVariable Integer id) { goodsService.deleteGoods(id); return Result.success(); } }这个Controller看起来简单但有几个细节值得展开。第一RequestParam和PathVariable的使用区别。分页参数name、pageNum这些是GET请求的查询参数用RequestParam绑定delete接口的id直接拼在URL路径里用PathVariable绑定。这两个注解的适用场景不要搞混面试和答辩也常被问到。第二新增和修改接口用RequestBody接收JSON对象因为前端Vue默认用axios.post发送application/json格式的数据如果后端只用RequestParam是接不到的这几乎是所有前后端分离项目第一次联调必踩的坑。第三分页返回的PageInfo这里用PageHelper插件它返回的对象里已经包含了总条数和当前页数据前端分页组件就能直接用了。Result类是一个统一响应体包含code、msg、data三个字段。这个类用泛型定义例如Result.success(Object data)返回code200、datadataerror(String msg)返回code500、msgmsg。统一响应体的好处是前端Axios拦截器可以做统一处理错误弹窗、登录失效跳转这些逻辑只需要写一遍不用每个页面单独判断。2.3 Service层与MyBatis持久层核心要点Service层是业务逻辑的核心也是体现系统“设计感”的地方。我在这个项目里遵循一条最简单的原则事务边界放在Service层方法上。比如“销售开单”这个方法必须同时完成三件事往orders表插主记录、往order_item表插明细、扣减goods表的库存。这三步要么全部成功要么全部回滚否则会出现超卖或者数据不一致。Service public class OrderServiceImpl implements OrderService { Autowired private OrderMapper orderMapper; Autowired private OrderItemMapper orderItemMapper; Autowired private GoodsMapper goodsMapper; Override Transactional(rollbackFor Exception.class) public void createOrder(OrderVO orderVO) { ListOrderItem items orderVO.getItems(); BigDecimal totalAmount BigDecimal.ZERO; for (OrderItem item : items) { Goods goods goodsMapper.selectById(item.getGoodsId()); if (goods.getStock() item.getQuantity()) { throw new RuntimeException(商品[ goods.getName() ]库存不足); } item.setPrice(goods.getSalePrice()); item.setSubtotal(goods.getSalePrice().multiply(new BigDecimal(item.getQuantity()))); totalAmount totalAmount.add(item.getSubtotal()); } Order order new Order(); order.setOrderNo(generateOrderNo()); order.setCustomerName(orderVO.getCustomerName()); order.setCustomerPhone(orderVO.getCustomerPhone()); order.setTotalAmount(totalAmount); order.setCreateTime(new Date()); orderMapper.insert(order); for (OrderItem item : items) { item.setOrderId(order.getId()); orderItemMapper.insert(item); goodsMapper.decreaseStock(item.getGoodsId(), item.getQuantity()); } } }这段代码我特意保留了库存检查的环节。实际的农资销售里库存不足必须拦截否则后面库存变负数都不知道怎么回事。Transactional注解在这里是核心一旦某个商品库存不足抛了RuntimeException前面插入的主记录和明细都会自动回滚。注意rollbackFor Exception.class这个写法Spring默认只回滚RuntimeException如果把异常配成Exception但实际抛的是业务异常很容易出现“事务没生效”的错觉。MyBatis的Mapper层用XML写SQL。这个项目的商品分页查询是一个典型场景我把SQL贴出来重点讲一下动态SQL的使用select idpageQuery resultTypecom.example.entity.Goods select * from goods where if testname ! null and name ! and name like concat(%, #{name}, %) /if if testcategoryId ! null and category_id #{categoryId} /if and status 1 /where order by create_time desc /select标签有个很实用的特性如果下面 条件成立它会自动在最前面补一个and如果所有条件都不成立它会自动去掉where关键字。这样写的好处是你不用在SQL里拼“where 11”这种丑陋写法MyBatis帮你处理了多余的and。模糊查询这里我用的是concat(%, #{name}, %)结合了MySQL的字符串拼接函数保证参数不直接拼进SQL。这个问题在答辩中经常被追问核心是#{}是预编译占位符${}是字符串替换模糊查询不能直接写%${name}%那样会有SQL注入风险。另外实体类字段和数据库表字段的映射规则我是这样处理的。在spring-mybatis.xml里配置configuration settings setting namemapUnderscoreToCamelCase valuetrue/ /settings /configuration这样数据库的create_time字段就能自动映射到实体的createTime属性不用每个字段都写resultMap了。我见过很多同学不知道这个配置手动写了大量冗余的resultMap还容易出现大小写不对应的低级错误这里提醒一句驼峰映射是MyBatis的基础配置务必打开。2.4 SSM常用注解速查与配置清单很多新手对SSM的注解体系一头雾水我在这里整理一份结合本项目实际的速查表后面写代码照着用就行。注解所在层作用本项目的实际使用位置RestControllerController返回JSON数据相当于ControllerResponseBodyGoodsController、OrderControllerRequestMappingController映射URL路径支持方法级别/goods/list、/goods/addGetMapping/PostMappingController简化GET/POST请求映射list接口、add接口RequestParamController接收URL查询参数分页参数pageNum、pageSizePathVariableController接收URL路径参数/delete/{id}RequestBodyController接收前端POST/JSON数据新增/修改商品ServiceService注册Service层BeanOrderServiceImplAutowiredService/Controller按类型注入Bean注入Mapper、ServiceTransactionalService事务管理createOrder方法RepositoryMapper注册Mapper层Bean通常用MapperScan替代再补充一个配置层面的骨架。SSM的整合无非就是三份配置文件web.xml是web入口配置spring-mvc.xml管Controller和视图解析spring-mybatis.xml管数据源、事务和Mapper扫描。如果你的项目是Maven打包pom.xml引入spring-webmvc、mybatis、mybatis-spring、mysql-connector-java、druid、pagehelper等依赖。使用Druid连接池而不是默认的JDBC连接池至少有两个好处自带SQL监控页面可以看慢SQL和连接池状态同时Druid有内置的数据库密码加密方案虽然毕设不一定用得上但写进文档能加印象分。3. Vue前端设计与实现3.1 前端环境搭建与工程初始化Vue项目的第一步就是搭环境。Node.js建议安装14或16的LTS版本npm会自带。安装完成后打开命令行先确认版本node -v npm -v然后全局安装Vue CLI脚手架。这里有个版本坑Vue CLI 5.x对应Node版本要求是12以上如果你电脑里是旧版Node安装时会报engine错误这种情况先升级Node再操作。npm install -g vue/cli vue --version vue create nongzi-adminvue create的过程中会有交互选项选择“Manually select features”勾选Router和Vuex。我建议配套也选上CSS预处理器用SCSS后面写样式更方便。创建完成后进入项目目录安装开发依赖cd nongzi-admin npm install element-ui npm install axios npm install sass-loader10 sass node-sass说明一下sass-loader版本为什么固定到10。Element UI的经典项目模板一般配的是4.x版本的sass-loader新版sass-loader在旧webpack环境下会报兼容性错误。如果你使用的是Vue CLI 4或5sass-loader装10比较稳妥实测不会出问题。这里遇到报错一定要看完整错误信息不要凭感觉乱升级很多人卡在环境上就是因为他把sass-loader升到了最新版本结果跟webpack冲突。3.2 Vue项目目录结构设计与路由管理项目初始化后我习惯先搭好目录结构。我的推荐方式是这样src/ ├── api/ # 存放所有接口请求 ├── assets/ # 静态资源 ├── components/ # 公共组件 ├── layout/ # 后台布局框架侧边栏顶栏 ├── router/ # 路由配置 ├── store/ # Vuex状态管理 ├── utils/ # 工具函数axios封装放这里 └── views/ # 页面组件路由配置是这个项目前端比较关键的部分。后台管理系统通常是“左侧菜单右侧内容”的布局我的Router设计如下import Vue from vue import VueRouter from vue-router import Layout from /layout/Layout.vue Vue.use(VueRouter) const routes [ { path: /, component: Layout, redirect: /goods, children: [ { path: goods, name: GoodsList, component: () import(/views/goods/GoodsList.vue), meta: { title: 农资商品管理, icon: goods } }, { path: stock, name: StockList, component: () import(/views/stock/StockList.vue), meta: { title: 库存管理, icon: stock } }, { path: order, name: OrderList, component: () import(/views/order/OrderList.vue), meta: { title: 销售订单, icon: order } } ] }, { path: /login, name: Login, component: () import(/views/Login.vue) } ]children里的一级菜单就是系统的子模块。菜单可以手写在Layout组件中遍历也可以依据当前的route匹配动态生成。我建议先手写一遍跑通后再看是否有必要改成根据路由表动态渲染菜单。路由传参也是必考知识点页面跳转传参有两种方式query方式和params方式。query方式URL里带问号比如this.$router.push({ path: /order/detail, query: { id: 1 } })刷新后参数还在params方式通常配合name使用刷新后参数会丢失。如果传的是商品ID这种关键数据我建议用query重新刷新页面依然能正确加载详情。路由守卫控制权限是管理系统必须做的。用全局前置守卫判断是否已登录router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path /login) { next() } else { if (!token) { next(/login) } else { next() } } })后端判断请求头里的token是否有效前端在Axios请求拦截器统一加上Authorization头。这一套“前端路由守卫后端token校验”的组合已经足够应付毕设的权限控制了。3.3 Axios封装与接口层设计后端写好了接口前端不能每页都裸用axios.get。我的做法是在utils/request.js统一封装axios实例加上请求拦截器和响应拦截器import axios from axios import { Message } from element-ui const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization token } return config }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { Message.error(res.msg || 请求失败) return Promise.reject(new Error(res.msg)) } return res }, error { if (error.response error.response.status 401) { Message.error(登录已过期请重新登录) router.push(/login) } else { Message.error(网络异常请稍后重试) } return Promise.reject(error) } ) export default requestbaseURL统一为/api然后在vue.config.js里配置开发代理。这里要强调一下开发环境跨域问题的标准解法是代理不是在后端写CrossOrigin了事。虽然后端开启跨域一种方式但如果前端代理能解决更适合放到生产环境的Nginx处理。vue.config.js配置如下const { defineConfig } require(vue/cli-service) module.exports defineConfig({ devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } })这样前端访问/api/goods/list代理到后端就是http://localhost:8080/goods/list。注意pathRewrite的写法^/api会被替换成空字符串因为后端Controller里没有/api这个前缀。接口层统一放到api目录例如api/goods.jsimport request from /utils/request export function getGoodsList(params) { return request({ url: /goods/list, method: get, params }) } export function addGoods(data) { return request({ url: /goods/add, method: post, data }) }页面里所有的业务请求都通过api目录里的函数来调用。这个习惯很重要就算后端接口地址变了只需要改api目录里的一个文件不用去每个页面里搜字符串。3.4 农资商品管理页面的实现细节商品管理页面是整个系统最核心的界面。这个页面要完成三件事条件搜索、表格展示、分页翻页。模板结构的核心代码如下template div classgoods-container el-form :inlinetrue classsearch-bar el-form-item label商品名称 el-input v-modelquery.name placeholder请输入关键字 clearable / /el-form-item el-form-item el-button typeprimary clickhandleSearch查询/el-button el-button clickresetSearch重置/el-button /el-form-item /el-form el-table :datatableData border stripe el-table-column propname label商品名称 min-width140 / el-table-column propspecification label规格 width100 / el-table-column propsalePrice label零售价 width100 / el-table-column propstock label库存 width100 / el-table-column label操作 width180 template slot-scopescope el-button typetext clickopenEdit(scope.row)编辑/el-button el-button typetext classdanger-btn clickhandleDelete(scope.row.id)删除/el-button /template /el-table-column /el-table el-pagination background layouttotal, prev, pager, next :totaltotal :current-page.syncquery.pageNum :page-size.syncquery.pageSize current-changefetchList / /div /template这里有几个细节值得提一下。表格列我用prop直接绑定字段名但显示上如果要格式化价格或者状态可以用formatter属性或者在插槽里写模板。库存字段如果低于阈值可以动态给当前行加个class比如Excel表格那种“缺货预警”的效果。Element UI的el-table自带排序和筛选功能通过sortable和filters属性就能开启不需要自己写复杂逻辑这个功能放到文档里也能体现前端细节。新增和编辑共用一个Dialog弹窗用v-model控制显示隐藏。表单提交前要校验Element UI的el-form自带rules校验机制比如“商品名称必填”“价格必须为正数”这些规则通过validator函数实现。我建议把商品图片上传也放到这个弹窗里使用Element UI的el-upload组件配合Spring Boot的静态资源映射上传后的图片链接存到goods.image字段列表页用el-image预览这样整个项目就有真实可用的商品图库功能了。开发阶段如果后端接口还没完成可以用Mock数据做先行调试。Vue生态里推荐用Mock.js在api目录下挂一个mock分支拦截axios请求返回假数据。不过要注意Mock和真实接口是同一套URL正式联调时一定要把mock的注册代码注释掉否则前端一直拿的是假数据白白浪费调试时间。4. 前后端联调、打包与部署4.1 联调时最容易出问题的几个环节前后端联调是新手翻车重灾区。我总结一下最常见的三个问题。第一个是请求方式不一致。前端axios默认post发送的是JSON格式如果后端Controller用RequestParam接收就会报“Required String parameter xxx is not present”。解决办法有两种前端用URLSearchParams或qs库转成表单格式后端改用RequestBody接收JSON。我推荐后端统一用RequestBody更符合前后端分离的习惯。第二个是后端返回的数据结构和前端约定不一致。我见过太多项目联调时前端取不到数据最后发现是后端返回的是Raw JSON数组前端却期待一个{code, data}结构。所以前后端开始联调之前第一件事就是对接口文档先对齐统一响应体结构再逐个调试。第三个是数据库日期格式问题。后端返回的Date类型默认格式是“2024-05-20T10:30:00”前端显示很不好看。解决方案是在后端实体类的日期字段加JsonFormat注解指定pattern为“yyyy-MM-dd HH:mm:ss”这样返回出去的就是格式化好的字符串前端不用再做处理。这是一个很小但很影响观感的细节。4.2 把Vue打包放进Spring Boot项目中这个项目最后交付的是一个Spring Boot或SSM的Web工程前端Vue要作为一个静态资源跟后端一起启动。操作流程很固定在Vue项目根目录执行npm run build生成dist目录然后把dist目录下的所有文件复制到后端src/main/resources/static目录。但这里有个关键问题Vue Router默认使用history模式URL是http://localhost:8080/goods/list这种不带#的地址。如果部署到Tomcat或内嵌Tomcat刷新页面时后端会把它当成一个后端路由去找结果找不到就返回404了。解决方式有两种第一种最省事把Vue Router改成hash模式。修改router/index.jsconst router new VueRouter({ mode: hash, routes })这样URL会变成http://localhost:8080/#/goods/list刷新永远是从根路径返回的index.html页面内部再解析hash路由。缺点就是URL风格不够好看但对毕设项目完全够用。第二种保留history模式后端配置一个兜底转发。提供这种配置Configuration public class WebMvcConfig implements WebMvcConfigurer { Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController(/{path:[^\\.]*}).setViewName(forward:/index.html); } }这样所有不包含点的路径都会转发到index.html前端路由就能正常工作了。这两种方案我都用过毕设答辩建议用history模式后端转发方案因为你可以借此讲清楚“前端路由和后端路由的区别”“为何刷新会404”两个知识点老师会认为你是真的理解了这个项目。文件不能编译进jar中。4.3 后端打包与部署的完整过程后端项目如果用的是SSM传统war包部署步骤是修改pom.xml的packaging为war在tomcat的webapps目录放入项目名.war启动Tomcat。如果用的是Spring Boot内嵌tomcat打jar步骤是mvn clean package然后java -jar demo.jar。无论哪种方式启动成功后访问http://localhost:8080能看到Vue的登录页说明前后端整合成功。这里要提醒一点数据库连接信息不要硬编码在代码里用Spring的配置文件统一管理配合Druid连接池的监控页面可以实时查看当前连接数和SQL执行情况。对毕设答辩来说能在现场演示“Druid监控页面里看到项目执行的SQL日志”比空口讲“我的系统很稳定”有说服力得多。5. 常见问题排查与答辩避坑5.1 问题排查速查表我在带这个项目的过程中积累了不少经典问题的排查经验。这里整理成表格可以当作“项目急救手册”来用。现象可能原因排查方案前端页面白屏控制台报错JS依赖缺失或路由配置错误按F12看Console逐条处理报错多刷新一次看是否加载了dist页面能打开但列表无数据接口返回结构不对或后端无数据先看Network请求是否成功再看响应体中code和data字段新增/编辑接口400前端传的JSON字段与后端实体不一致核对字段名大小写加前后端日志输出数据库中文乱码字符集不一致JDBC连接加useUnicodetruecharacterEncodingutf8登录成功后刷新就跳到登录页token存到了session里但跨端口失效token存localStorage每次请求头里带上上传图片不显示静态资源路径映射问题检查后端静态资源映射配置用完整URL访问MyBatis报Column not found实体字段与数据库列名不一致开启mapUnderscoreToCamelCase或手写resultMapPageHelper出来的数据没有total字段pagehelper版本与MyBatis版本不兼容pagehelper 5.x配mybatis 3.5.x固定版本号事务不回滚事务方法被同类中调用或异常被吞了用通过注入的Service调用事务方法不要同类自调用5.2 答辩准备与LW文档写作思路最后聊聊文档和答辩。文档不能只是代码的复制粘贴要写成“从需求到实现”的完整记录。我建议按这种结构来写引言与选题意义、需求分析、系统设计架构图、数据库设计、系统实现分模块描述、系统测试用例截图、总结与展望。数据库设计这一章放ER图和表结构说明系统实现一章采用“界面截图核心代码功能说明”的方式展示测试一章至少要写20个测试用例覆盖登录、CRUD、权限校验、库存扣减、异常输入这些场景。答辩时老师问的问题其实绕不开这几类一是“你的系统有哪些模块各模块关系是什么”这时你可以拿着架构图和数据表关系讲清楚二是“为什么用SSM和Spring Boot比有什么优劣”这时候把上一篇文章里那张比对的思路讲出来就够三是“你的项目有什么亮点或难点”这个项目可以说库存流水追溯、动态SQL查询、事务控制保证订单一致性、Vue路由守卫控制权限、前后端分离部署理解这五点四是“项目还有什么不足”不要说什么“没有不足”而是真诚地说“没有做多角色细粒度权限、没有做密码加密传输、没有做Redis缓存”并给出后续改进设想这种“有反思能力”的回答反而容易拿高分。最后说两句个人感受这套系统做完最大的收获不是那几万行代码而是你终于把“前端页面—HTTP请求—后端接口—数据库表”这条链路从头到尾走通了。只有在真实项目中踩过POST参数收不到、路由刷新404、事务回滚失效这一连串的坑你才算真正理解什么叫Web开发。我见过太多同学项目能跑起来但说不出原理答辩时一问三个不知道。其实只要按照这篇文章的思路把SSM和Vue每一层的职责理清楚把几个核心业务闭环走通再把文档写得有真实细节这个题目的毕设不仅能顺利过审还能成为你简历上真正拿得出手的一个项目。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号