SSM框架超市进销存管理系统毕业设计实战:从数据库设计到部署答辩
做计算机毕业设计最怕的不是题目难而是题目老、资料少、找不到参考最后憋到答辩前一周才开始赶工。超市进销存管理系统算是一个非常经典的选题了它好就好在业务逻辑清楚模块划分自然工作量适中而且用 SSM 框架去做正好能体现你对 Java Web 技术栈的掌握程度。我当初做这个系统的时候也是从网上扒了一大堆资料最后发现真正能一口气跑起来的源码少得可怜很多帖子要么缺数据库脚本要么配置文件写了一半折腾两天还卡在启动报错上。这篇文章我就把自己从选题、设计、编码到部署的思路完整捋一遍后面附带的源码也是我本地实测跑通的版本希望能帮你少走点弯路。这篇文章适合两类人看一类是正在准备计算机毕业设计、考虑用 SSM 做仓库或进销存方向的同学另一类是刚学完 SSM 框架、想找一个完整项目练手的初学者。我不会只贴代码还会把每一步为什么这么做的逻辑讲清楚这样你答辩的时候被老师追问设计思路也能从容应对。1. 为什么选“超市进销存”这个题目1.1 选题背后的需求逻辑很多同学选毕设题目时有个误区觉得题目越新、技术越高大上越好。实际上毕业设计和商业项目不同核心目标是展示你掌握了哪些能力以及能不能独立完成一个完整的项目。超市进销存管理系统恰恰能满足这几个要求。从业务角度看超市的日常运营绕不开三件事进什么货、货放哪里、货卖了多少。进货对应采购管理货放哪里对应库存管理货卖了多少对应销售管理和统计报表。这三个核心环节天然形成了业务闭环你可以围绕它们做模块划分也能扩展出供应商管理、会员管理、预警提醒等功能。模块多了工作量就上去了模块少了内容又不够写论文这个度刚好可以通过进销存系统来灵活控制。从技术角度看进销存系统涉及增删改查、关联查询、事务处理、分页搜索、数据统计报表等常见开发场景能把 SSM 框架的各个层面都用上包括 Spring 的依赖注入和事务管理、SpringMVC 的请求流转、MyBatis 的 SQL 映射和动态 SQL。相比做那种花里胡哨的前端页面这种项目更能让答辩老师看到你的后端功底。这里还要多说一句进销存系统的业务逻辑比单纯的“XX管理系统”要复杂一点因为有库存加减、价格计算、单据和明细表关联这些操作所以在项目里能体现业务级的事务处理能力这在答辩时是很加分的点。1.2 SSM 技术栈选型的真实原因现在很多同学可能会纠结是不是该用 Spring Boot 或者 Spring Cloud我的建议是如果你学校教学用的是 SSM 框架或者你还没有完全掌握微服务那套东西就老老实实选 SSM。原因很简单SSM 是传统 Java Web 开发的基础组合Spring Boot 本质上是在 Spring 和 SpringMVC 基础上的自动配置整合。你在 SSM 项目里要手动配置数据源、配置事务管理器、配置 MyBatis 的 SqlSessionFactory这些东西折腾一遍你对框架内部怎么运作的理解会比直接套用 Spring Boot 深得多。答辩的时候老师常常会问“你配这个事务是怎么生效的”如果你亲手配过tx:advice或者Transactional你答起来就有底气了。选 SSM 还有另一个现实原因网上的参考资料多前人踩过的坑基本都有解决方案。我的项目用的是经典 SSM 组合也就是 Spring 5 SpringMVC MyBatis 3配合 MySQL 5.7 和 Maven 做依赖管理。这套组合稳定、兼容性好、官方文档和社区资料都很全毕设做它性价比最高。2. 项目整体设计与核心模块拆解2.1 功能模块怎么划分才清晰超市进销存管理系统的功能划分我建议遵循“一个角色一条线”的思路把普通超市的日常操作流程映射到系统模块里。我的项目里分了这几个核心模块商品管理负责商品分类和商品信息的维护包括名称、条码、规格、单位、进价、售价、库存上下限等。供应商管理维护供应商的基本资料方便采购时关联供应商信息。采购入库管理填写采购单选择供应商和商品填写数量和进价确认入库后自动增加库存。销售出库管理填写销售单选择商品填写销售数量保存后自动扣减库存并计算销售金额。库存管理查看当前所有商品的库存数量支持库存预警低库存商品高亮提示还可以做库存盘点调整差异数量。报表统计按时间段统计进货金额、销售金额、毛利用列表展示每日或每月的销售趋势。你可能已经注意到了在进销存这样的系统里“单据”和“明细”是两个非常关键的概念。以采购单为例一张采购单要同时记录单头信息单号、供应商、采购日期、操作员、总金额和单体信息本次采购了哪些商品、每个商品多少数量、什么进价所以数据库里至少是两张表而且要在事务里一次性保存。这是我项目里特别重视的一部分也是后面写代码时容易出错的地方。2.2 数据库设计是重中之重数据库设计好不好直接影响写代码的难度。我第一次做这个系统的时候就是图省事每张表都单独设计结果做销售单的时候字段对不上改了一晚上表结构。后来我重新梳理了表的关系才把数据模型稳定下来。我的表设计大体如下user用户表字段包括 id、用户名、密码、真实姓名、角色角色可以简单分管理员和收银员。category商品分类表字段包括 id、分类名称、备注。product商品表字段包括 id、分类 id、条码、名称、规格、单位、进价、售价、库存数量、库存下限、库存上限。supplier供应商表字段包括 id、供应商名称、联系人、联系电话、地址、备注。purchase采购单表字段包括 id、采购单号、供应商 id、采购日期、总金额、操作人、备注。purchase_item采购单明细表字段包括 id、采购单 id、商品 id、采购数量、采购单价、小计金额。sale销售单表字段与采购单类似。sale_item销售单明细表字段与采购单明细表类似。关键的设计点是商品表里的库存数量是一个“冗余字段”每次采购入库或销售出库时都会更新它。这里要强调一下商品库存数量并非只能通过查流水表汇总得到如果每次都去 sum 所有入库记录再减去所有出库记录数据量大了以后性能会很差。直接在 product 表里维护一个实时库存字段虽然有一定的冗余但对一个小型超市进销存系统来说是最实用的做法。另外采购单号和销售单号我推荐用“日期自增编号”的方式生成比如PO20250601001这样人眼识别方便数据库里做唯一索引也好做还方便按日期搜索。2.3 项目目录结构与分层思路SSM 项目最忌讳的是把代码全部塞到 Controller 里那样改起来会非常痛苦。我用了经典的三层架构表现层Controller、业务层Service、持久层Mapper。项目的 Maven 目录结构如下ssm-supermarket/ ├── pom.xml ├── src/main/java/com/example/supermarket/ │ ├── controller/ # 控制器接收前端请求 │ ├── service/ # 业务接口 │ ├── service/impl/ # 业务实现类 │ ├── mapper/ # MyBatis Mapper接口 │ ├── entity/ # 实体类 │ ├── dto/ # 数据传输对象用于接收页面参数 │ └── common/ # 公共类比如分页结果、统一返回结果 ├── src/main/resources/ │ ├── mapper/ # MyBatis XML映射文件 │ ├── spring/ # Spring配置文件 │ ├── mybatis-config.xml │ └── jdbc.properties └── src/main/webapp/ ├── static/ # 静态资源JS、CSS、图片 └── WEB-INF/ ├── views/ # JSP页面 └── web.xml很多同学喜欢把业务逻辑写在 Service 里这一点要明确Service 层是业务的核心比如库存加减、金额计算这种逻辑一定放在 Service 里Controller 只负责接收参数、调用 Service 方法、返回视图或 JSON 数据。Mapper 层只做 SQL 查询和持久化操作不写业务判断。这里有一个我踩过的坑要特别提醒实体类字段和数据库字段的命名要尽量保持一致或者用 MyBatis 的mapUnderscoreToCamelCase配置来自动映射。比如数据库字段是create_timeJava 属性是createTime如果不开驼峰映射就要在每个查询里自己用resultMap映射那会很啰嗦。我项目里直接在mybatis-config.xml里开了这个配置settings setting namemapUnderscoreToCamelCase valuetrue/ /settings这个配置虽然不起眼但能省下大量重复的 resultMap 代码。3. 核心功能实现与关键代码解析3.1 Spring、SpringMVC、MyBatis 的配置串联搭建 SSM 项目第一步是把三大框架整合起来。网上有很多零散配置但如果你不理解配置文件的加载顺序很容易出问题。我来理一下思路。web.xml 是整个项目的入口它负责启动 Spring 容器和 SpringMVC 容器。一个常见的坑是Spring 的容器是父容器SpringMVC 的容器是子容器。子容器可以拿到父容器的 Bean但父容器拿不到子容器的 Bean。所以在配置扫描包时Spring 的扫描要扫除 Controller 以外的包SpringMVC 只扫 Controller。我的 web.xml 核心配置如下context-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/applicationContext-*.xml/param-value /context-param listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener servlet servlet-namedispatcher/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/springmvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcher/servlet-name url-pattern//url-pattern /servlet-mapping这里再解释一下为什么用url-pattern//url-pattern而不是*.do。其实两种都能用但/表示所有请求都经过 SpringMVC配合注解驱动和静态资源映射代码风格会更 RESTful 一点。如果你用了*.do链接里就要带 .do 后缀我个人不太喜欢这种风格。Spring 的配置里最核心的是数据源、事务管理器、以及 MyBatis 的 SqlSessionFactory。我用的是 Druid 连接池配置如下context:property-placeholder locationclasspath:jdbc.properties/ bean iddataSource classcom.alibaba.druid.pool.DruidDataSource property namedriverClassName value${jdbc.driver}/ property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property namemapperLocations valueclasspath:mapper/*.xml/ property nameconfigLocation valueclasspath:mybatis-config.xml/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.example.supermarket.mapper/ /bean bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManager property namedataSource refdataSource/ /bean tx:annotation-driven transaction-managertransactionManager/这里有一个细节必须注意mapperLocations配置的是 MyBatis XML 文件路径如果你在src/main/resources/mapper目录下放的是ProductMapper.xml那ProductMapper.java接口里的方法名就要和 XML 里的statement id完全一致。如果出现“Invalid bound statement (not found)”这个报错第一反应就是去检查 XML 文件的namespace是不是写成了全限定接口名以及方法名是否一致。3.2 商品的增删改查与分页搜索商品管理是所有模块的基础其他模块都要引用商品表。它的核心操作就是分页搜索和增删改查。分页我用了 PageHelper这是一个 MyBatis 的分页插件功能很强大配置也简单。在 Spring 配置里加这一段bean idsqlSessionFactory ... ... property nameplugins array bean classcom.github.pagehelper.PageInterceptor property nameproperties value helperDialectmysql reasonabletrue /value /property /bean /array /property /bean然后在 Service 层里只需要在查询前调用PageHelper.startPage(pageNum, pageSize)后面紧跟的 Mapper 查询就会自动带 limit。返回的时候把查询结果包装成 PageInfo就能拿到总条数、总页数这些分页数据。举一个商品查询的例子ServiceImpl 里大概是这样的逻辑Override public PageInfoProduct findProductList(String keyword, Integer pageNum, Integer pageSize) { PageHelper.startPage(pageNum, pageSize); ListProduct list productMapper.searchProducts(keyword); return new PageInfo(list); }对应的 Mapper XML 使用了动态 SQL这样搜索框不输入关键字时也能正常查询select idsearchProducts resultTypecom.example.supermarket.entity.Product SELECT * FROM product where if testkeyword ! null and keyword ! AND (name LIKE CONCAT(%, #{keyword}, %) OR barcode LIKE CONCAT(%, #{keyword}, %)) /if /where ORDER BY id DESC /select写分页搜索的时候有几个容易踩的小坑。第一个是PageHelper.startPage必须紧跟在你要分页的 Mapper 查询之前中间不能夹着其他查询否则分页插件会把不是目标查询的 SQL 也处理了结果就是分页失效甚至报错。第二个是如果你的查询里还有子查询或者嵌套结果集PageHelper 有时会统计不对遇到这种情况可以手动写一个 count 查询来修正。3.3 采购入库与事务处理的核心逻辑采购入库模块是整个系统里最有业务含量的部分。它的流程是用户在前端填写一张采购单选择供应商然后往明细里添加若干商品每个商品还要填数量和进价。提交的时候后端要同时完成以下操作生成采购单主记录包含单号、供应商、日期、总金额。逐条插入采购单明细。更新商品库存product.stock product.stock 采购数量。如果有库存下限逻辑还要检查是否需要触发补货预警。因为这四个操作要保证“要么全成功要么全失败”所以必须加上事务控制。我推荐在 Service 方法上加Transactional注解简单直接而且 Spring 声明式事务能帮你处理回滚。核心代码类似这样Transactional(rollbackFor Exception.class) Override public void createPurchaseOrder(PurchaseDTO dto) { Purchase purchase new Purchase(); purchase.setPurchaseNo(generatePurchaseNo()); purchase.setSupplierId(dto.getSupplierId()); purchase.setPurchaseDate(new Date()); purchase.setOperator(dto.getOperator()); double totalAmount 0; // 先插入主单获取主单ID purchaseMapper.insert(purchase); for (PurchaseItemDTO item : dto.getItemList()) { PurchaseItem detail new PurchaseItem(); detail.setPurchaseId(purchase.getId()); detail.setProductId(item.getProductId()); detail.setQuantity(item.getQuantity()); detail.setPrice(item.getPrice()); detail.setSubtotal(item.getQuantity() * item.getPrice()); totalAmount detail.getSubtotal(); purchaseItemMapper.insert(detail); // 更新库存 productMapper.increaseStock(item.getProductId(), item.getQuantity()); } // 更新主单总金额 purchase.setTotalAmount(totalAmount); purchaseMapper.updateTotalAmount(purchase); }这里有几个容易想不明白的地方我展开解释一下。第一为什么先插主单再插明细因为明细表里需要一个purchase_id作为外键关联主单。如果我们先插明细就没有主单 ID 可用。MyBatis 里要拿到自增主键可以在 insert 语句里配置useGeneratedKeystrue keyPropertyid这样插入后实体的 id 字段就会被自动填上。insert idinsert parameterTypecom.example.supermarket.entity.Purchase useGeneratedKeystrue keyPropertyid INSERT INTO purchase (purchase_no, supplier_id, purchase_date, operator, remark) VALUES (#{purchaseNo}, #{supplierId}, #{purchaseDate}, #{operator}, #{remark}) /insert第二库存更新用productMapper.increaseStock(productId, quantity)而不是先 select 再 set这是为了减少一次查询也避免并发下出现库存覆盖的问题。SQL 类似update idincreaseStock UPDATE product SET stock stock #{quantity} WHERE id #{id} /update这里用stock stock #{quantity}而不是stock #{stock} #{quantity}关键区别是前者直接在数据库层面做原子更新不需要先读出当前库存安全性更高。第三事务只对 RuntimeException 回滚对受检异常默认不回滚所以我在注解里写rollbackFor Exception.class确保任何异常都触发回滚。3.4 销售出库、库存扣减与负库存处理销售出库的逻辑和采购入库是镜像的但有个额外的顾虑不能卖超了。也就是说销售数量不能大于当前库存否则会出现负库存这在超市场景里是不允许的。我实现的方法是在扣减库存前先检查库存是否充足然后在更新库存的 SQL 里再加一个条件双保险int rows productMapper.decreaseStock(productId, quantity); if (rows 0) { throw new RuntimeException(商品 productId 库存不足); }对应的 SQLupdate iddecreaseStock UPDATE product SET stock stock - #{quantity} WHERE id #{id} AND stock #{quantity} /update这个方法很巧妙MySQL 的 UPDATE 会检查 WHERE 条件如果stock quantity不成立就影响 0 行。我们就可以根据影响行数来判断是否扣减成功。这么做的好处是在并发场景下也能防止超卖因为数据库行锁会保证更新是串行的。对于毕设项目来说这一处细节足够让你在答辩时讲半分钟而且能体现你对并发问题的敏感性。销售单保存后前端通常还需要显示当前商品的库存余量。我建议在页面提交前用 AJAX 实时查询商品库存并做前端校验这样就避免了用户填了 99 个结果提交后才发现库存不足的情况。3.5 登录认证与拦截器实现细节既然是管理系统登录和权限控制肯定是绕不开的。我的系统用了最简单的 Session 登录方案用户登录成功后把用户对象放到 Session 里然后写一个拦截器拦截所有页面请求只有登录过的人才能访问。登录 Controller 的核心逻辑PostMapping(/login) public String login(String username, String password, HttpSession session) { User user userService.login(username, password); if (user ! null) { session.setAttribute(loginUser, user); return redirect:/index; } return redirect:/login?error1; }密码存储我用了 MD5 加盐处理虽然现在推荐用 BCrypt但毕设项目里 MD5 加盐已经是及格线了答辩老师一般不会在这个点上刁难你。如果你有余力可以引入 spring-security-crypto 里的 BCryptPasswordEncoder这个在论文里能写成“使用 BCrypt 加密算法保证密码安全”会显得专业很多。拦截器配置在 springmvc.xml 里mvc:interceptors mvc:interceptor mvc:mapping path/**/ mvc:exclude-mapping path/login/ mvc:exclude-mapping path/static/**/ bean classcom.example.supermarket.interceptor.LoginInterceptor/ /mvc:interceptor /mvc:interceptors注意这里要把静态资源路径排除掉否则 CSS、JS 文件也被拦截页面样式会全部丢失。3.6 报表统计模块的思路报表统计模块是进销存系统里的加分项也是很多同学觉得“不知道从哪下手”的地方。其实核心就是几个带 GROUP BY 的聚合查询。比如按天统计销售金额select idcountDailySale resultTypemap SELECT DATE_FORMAT(sale_date, %Y-%m-%d) AS day, SUM(total_amount) AS amount FROM sale GROUP BY day ORDER BY day DESC LIMIT 30 /select这里的返回类型用 map是为了避免为聚合结果单独创建实体类。前端拿到后可以用 JSTL 或者 JS 图表库渲染。如果你想让论文显得有亮点可以引入 ECharts把每天的销售趋势画成折线图、把商品销售占比画成饼图视觉效果会好很多。毛利统计也很有意思。利润的核心计算方式是“售价金额 - 进价成本”但在设计表结构时我们可以直接在 sale_item 里冗余保存商品的进价字段这样统计毛利就不需要再去关联商品表取进价了。有些同学可能会问进价不是应该以商品表里的最新进价为准吗但实际情况是商品进价是波动的采购时是什么价格就应该按那个价格算成本所以在销售明细里存一个 snapshot 进价字段是最稳妥的也方便以后做成本核算。4. 部署运行的完整指南与避坑心得4.1 环境准备与项目导入要把项目跑起来环境配置是关键。我用的是下面的组合已经实测过兼容性没问题JDK 1.8Maven 3.6 以上Tomcat 8.5 或 9MySQL 5.7IDEA 2021 或更新版本拿到源码后部署的步骤大致是先用 IDEA 打开项目等待 Maven 自动下载依赖。如果下载很慢建议在settings.xml里配置阿里云镜像这里不展开但这是很多新手卡住的第一关。在 MySQL 里新建数据库我项目里叫db_supermarket然后把sql目录里的初始化脚本执行一遍它会自动建表并插入测试数据。修改jdbc.properties里的数据库地址、用户名、密码三个参数一定要改对。配置 Tomcat把项目部署到 Tomcat 中启动。浏览器访问http://localhost:8080/ssm-supermarket/如果看到登录页面说明项目启动成功。登录页面的初始账号密码在数据库脚本里给定一般是admin/123456但是为了安全你部署后应该立刻更改。4.2 启动过程中常见的报错排查项目跑不起来对新手来说非常折磨因为报错信息五花八门。我把这几年看到学生遇到的最多的错误整理成了一个速查表你在部署时可以直接对照报错信息可能原因解决方法Invalid bound statement (not found): ...ProductMapper.findByIdMapper XML 没被扫描到或 namespace 写错检查 Spring 配置里的mapperLocations是否为classpath:mapper/*.xml检查 XML 的 namespace 是全限定接口名java.sql.SQLException: Access denied for user rootlocalhost数据库用户名或密码错误检查jdbc.properties注意不要有多余空格Table db_supermarket.product doesnt exist数据库脚本没执行成功或连错数据库确认脚本执行完成在 MySQL 里用show tables查看启动时端口被占用Tomcat 8080 被其他程序占用修改 Tomcat 端口或先把占用程序停掉404访问不到页面项目没有正确部署到 webapps或 context path 不对检查 IDEA 里 Artifacts 配置确认 deployment 里的 Application contextClassNotFoundException: com.mysql.cj.jdbc.DriverMySQL 驱动版本和连接串不匹配把驱动改成com.mysql.cj.jdbc.DriverURL 里加serverTimezoneAsia/ShanghaiFailed to configure a DataSourceSpring 配置里没有加载到 jdbc.properties检查context:property-placeholder路径是否正确这些报错里最经典的就是Invalid bound statement几乎每个 SSM 新手都会遇到。它的本质原因是 Mapper 接口和 XML 映射文件没有关联上要么是 XML 没在mapperLocations指定的目录里要么是 namespace 写错。排查思路也很简单先编译项目确认 XML 是否被复制到了 target/classes 目录下。如果 XML 不在说明 Maven 没有把它当资源文件需要在 pom.xml 里配置 resources 节点。4.3 论文配图和演示时的注意点做毕设答辩演示环节其实比代码本身更重要。你应该提前准备几条演示路径不要现场随意点击。我的建议是登录后先展示主页介绍系统概览和库存预警信息然后演示商品管理指出分页搜索功能现场搜索一个关键字再演示采购入库录一张带 3 个商品的采购单展示库存变化再演示销售出库录入一个销售单展示库存扣减和毛利计算最后打开报表统计展示销售趋势图。这一套流程走下来基本能把系统的核心功能全部覆盖。实操时有个小技巧提前准备一批商品测试数据数量别太少至少几十条这样分页效果才明显。演示销售单的时候别选库存只有 1 的商品万一被别人测试过已经卖完了你现场提交会直接报错那就尴尬了。5. 答辩常见问题与自查清单5.1 五个高频答辩问题怎么答老师答辩时很少会问特别刁钻的问题基本都是围绕项目本身发问。我梳理了几个高频问题每个问题背后都是要你展示对项目原理的理解。问题一为什么使用 SSM 框架它的优点是什么这是一个送分题但很多同学答得太浅。你可以这样组织回答SSM 是 Spring SpringMVC MyBatis 的组合Spring 负责解耦对象管理通过 IoC 和 AOP 管理 BeanSpringMVC 负责请求分发通过 DispatcherServlet 把请求路由到 ControllerMyBatis 负责持久层操作封装了 JDBC支持灵活的 SQL 编写。三者各司其职让系统层次清晰、便于维护。问题二采购入库时如何保证数据一致性这个问题直接考察事务概念。你回答时要说清楚采购入库涉及插入主单、插入明细、更新库存三个操作任何一个失败都必须回滚。我用 Spring 的声明式事务在 Service 方法上添加Transactional注解交给 Spring 管理事务的提交和回滚。问题三库存是怎么更新的如果多个人同时下单怎么办库存更新我直接在 SQL 里用UPDATE product SET stock stock - #{quantity} WHERE id #{id} AND stock #{quantity}这条原子语句数据库行锁能保证同一商品只能串行扣减所以不会出现超卖。问题四如何进行权限控制我的系统通过 Session 保存登录用户实现了一个拦截器将除登录请求和静态资源外的所有请求都拦截下来判断 Session 中是否有用户对象。后续拓展可以做基于角色表的动态权限控制。问题五项目里你遇到的最大难点是什么回答这个问题要有故事感不要泛泛而谈。你可以说最开始的难点是 MyBatis 多表关联时结果集映射经常出问题后来我通过自定义 DTO 类来承接多表查询结果绕开了 resultMap 的复杂配置也让代码更直观。这里“自定义 DTO”是个很好的回答点因为它是实际开发的常用技巧老师听了会觉得你真做过项目。5.2 提交源码前的自查清单交源码之前建议按照下面这个清单逐项检查避免被答辩老师现场指出低级问题数据库脚本是否能一键执行执行后是否有测试数据。数据库连接配置是否和环境匹配是否误提交了真实密码。项目在干净环境下能否一次启动成功。所有页面是否有统一风格错误提示是否友好。论文里的表结构、截图是否和实际代码一致。README 文件是否写了如何部署和默认账号。代码里是否有无用的System.out.println或调试代码。删除本地缓存文件如 IDEA 的 .idea、target 目录压缩源码时保证干净。特别是第一条。很多同学源码里数据库脚本是有的但一执行就各种报错或者脚本里没有 insert 测试数据登录后所有列表都是空的演示效果就会大打折扣。我给你的源码里已经准备了一部分商品和供应商测试数据你应该再根据自己的需求扩充一些比如多建几个分类、多录几个供应商。5.3 从毕设项目延伸到面试项目的空间如果你不是只想应付毕设还想把这套内容放到简历上那么我建议你在现有基础上做三个小升级成本低但简历含金量高。第一把 SSM 升级为 Spring Boot MyBatis 版本核心业务代码可以复用只改配置层。Spring Boot 的自动配置能让你省掉大量 XML 配置简历上写“熟悉 Spring Boot 项目开发”更有说服力。第二给登录模块引入 JWT 或者 Spring Security能体现你对认证授权的理解。第三把报表模块的统计逻辑改为定时任务比如每天凌晨自动汇总昨天的销售数据到一张统计表里用 Spring 的Scheduled实现这可以让项目更有“工程感”。当然如果你现在时间紧张不建议大改先保证核心流程能跑通。毕设的核心是“完整”不是“复杂”你要在论文里写清楚模块设计、数据库设计、关键代码分析再把项目演示顺畅就是一份能拿到不错成绩的成品。6. 写在最后一点过来人的建议做完整个超市进销存系统我有一个很深的体会毕业设计其实是一场“项目管理”训练而不是单纯考验编程能力。你需要在不同模块之间取舍在有限时间内确定优先级还要让最后的交付物源码、论文、演示都能稳定运行。很多同学喜欢在前期纠结用什么前端框架、要不要加 Redis 缓存结果连基础的进销存流程都没写完。我的建议永远是先跑通核心链路再考虑锦上添花。在做这个项目的过程中我自己也反复踩了不少坑比如 MyBatis 的驼峰映射配置没开导致大量字段映射失败比如采购单和明细表的事务忘了加rollbackFor出错了也不会自动回滚再比如没有提前准备测试数据演示时页面空空如也。这些坑都不算难但非常典型这篇文章里我尽量都讲到了。你如果照着做即使遇到问题也能顺着排查思路找到原因。最后再送一个小技巧如果你用了 JSP 做页面建议在web.xml里把项目默认首页指向登录页或者做一个index.jsp做重定向。这样部署后访问根路径就能跳转到登录体验会好很多。祝你的毕设顺利过关。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →